@koda-sl/baker-cli 0.28.1 → 0.32.0-dev.31ee8d9c

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.
Files changed (74) hide show
  1. package/README.md +277 -15
  2. package/dist/cli.js +1 -1
  3. package/dist/commands/actions/complete.d.ts +2 -2
  4. package/dist/commands/actions/complete.d.ts.map +1 -1
  5. package/dist/commands/actions/complete.js +10 -8
  6. package/dist/commands/actions/complete.js.map +1 -1
  7. package/dist/commands/actions/shared.d.ts +1 -0
  8. package/dist/commands/actions/shared.d.ts.map +1 -1
  9. package/dist/commands/actions/shared.js +3 -0
  10. package/dist/commands/actions/shared.js.map +1 -1
  11. package/dist/commands/images/extract.d.ts +23 -0
  12. package/dist/commands/images/extract.d.ts.map +1 -0
  13. package/dist/commands/images/extract.js +53 -0
  14. package/dist/commands/images/extract.js.map +1 -0
  15. package/dist/commands/images/find.d.ts +33 -0
  16. package/dist/commands/images/find.d.ts.map +1 -0
  17. package/dist/commands/images/find.js +70 -0
  18. package/dist/commands/images/find.js.map +1 -0
  19. package/dist/commands/images/gif.d.ts +33 -0
  20. package/dist/commands/images/gif.d.ts.map +1 -0
  21. package/dist/commands/images/gif.js +81 -0
  22. package/dist/commands/images/gif.js.map +1 -0
  23. package/dist/commands/images/google.d.ts +38 -0
  24. package/dist/commands/images/google.d.ts.map +1 -0
  25. package/dist/commands/images/google.js +77 -0
  26. package/dist/commands/images/google.js.map +1 -0
  27. package/dist/commands/images/icon.d.ts +23 -0
  28. package/dist/commands/images/icon.d.ts.map +1 -0
  29. package/dist/commands/images/icon.js +57 -0
  30. package/dist/commands/images/icon.js.map +1 -0
  31. package/dist/commands/images/index.d.ts.map +1 -1
  32. package/dist/commands/images/index.js +45 -7
  33. package/dist/commands/images/index.js.map +1 -1
  34. package/dist/commands/images/ingest.d.ts +28 -0
  35. package/dist/commands/images/ingest.d.ts.map +1 -0
  36. package/dist/commands/images/ingest.js +60 -0
  37. package/dist/commands/images/ingest.js.map +1 -0
  38. package/dist/commands/images/library.d.ts +55 -0
  39. package/dist/commands/images/library.d.ts.map +1 -0
  40. package/dist/commands/images/library.js +86 -0
  41. package/dist/commands/images/library.js.map +1 -0
  42. package/dist/commands/images/logo.d.ts +18 -0
  43. package/dist/commands/images/logo.d.ts.map +1 -0
  44. package/dist/commands/images/logo.js +49 -0
  45. package/dist/commands/images/logo.js.map +1 -0
  46. package/dist/commands/images/meme.d.ts +28 -0
  47. package/dist/commands/images/meme.d.ts.map +1 -0
  48. package/dist/commands/images/meme.js +66 -0
  49. package/dist/commands/images/meme.js.map +1 -0
  50. package/dist/commands/images/screenshot.d.ts +23 -0
  51. package/dist/commands/images/screenshot.d.ts.map +1 -0
  52. package/dist/commands/images/screenshot.js +64 -0
  53. package/dist/commands/images/screenshot.js.map +1 -0
  54. package/dist/commands/images/search.d.ts.map +1 -1
  55. package/dist/commands/images/search.js +1 -0
  56. package/dist/commands/images/search.js.map +1 -1
  57. package/dist/commands/images/sticker.d.ts +33 -0
  58. package/dist/commands/images/sticker.d.ts.map +1 -0
  59. package/dist/commands/images/sticker.js +81 -0
  60. package/dist/commands/images/sticker.js.map +1 -0
  61. package/dist/commands/images/stock.d.ts +58 -0
  62. package/dist/commands/images/stock.d.ts.map +1 -0
  63. package/dist/commands/images/stock.js +116 -0
  64. package/dist/commands/images/stock.js.map +1 -0
  65. package/dist/commands/images/use.d.ts +18 -0
  66. package/dist/commands/images/use.d.ts.map +1 -0
  67. package/dist/commands/images/use.js +57 -0
  68. package/dist/commands/images/use.js.map +1 -0
  69. package/dist/output.d.ts.map +1 -1
  70. package/dist/output.js +1 -0
  71. package/dist/output.js.map +1 -1
  72. package/dist/output.test.js +1 -0
  73. package/dist/output.test.js.map +1 -1
  74. package/package.json +1 -1
package/README.md CHANGED
@@ -1573,27 +1573,289 @@ Research data is cached server-side (shared across all callers). No local cache
1573
1573
 
1574
1574
  ### Assets (`baker images`, `baker videos`, `baker testimonials`)
1575
1575
 
1576
- ### `baker images search <query>`
1576
+ #### Image sourcing verb-per-provider overview
1577
1577
 
1578
- Semantic search using hybrid BM25 + vector + reranking. Only returns ready images.
1578
+ Each external source is its own subcommand. Pick the verb that matches the source — license, cost, and result shape are all provider-specific.
1579
+
1580
+ | Command | Purpose | Cost | Auto-ingest default |
1581
+ |---|---|---|---|
1582
+ | `baker images library <q>` | Hybrid library search (replaces `search`) | $0 | n/a |
1583
+ | `baker images find <q>` | Fanout: library + opted-in providers | sum of providers | off |
1584
+ | `baker images stock <q> [--type photo\|vector\|psd]` | Magnific (Freepik's dev API) — photos, vectors, illustrations, PSDs (~250M assets) | $0.002/req | off |
1585
+ | `baker images google <q>` | Google Images via the official Custom Search JSON API | $0 under 100/day, then $0.005/query | off |
1586
+ | `baker images logo <domain>` | Brand logo via Brandfetch CDN | $0 | **on** (top 1) |
1587
+ | `baker images icon <name>` | Iconify (200+ icon sets, no API key) | $0 | off (CDN URL is stable) |
1588
+ | `baker images gif <q>` | Reaction GIFs / memes via Giphy (paid-social creative) | $0 | off |
1589
+ | `baker images sticker <q>` | Transparent stickers via Giphy (overlay-friendly for ad creative) | $0 | off |
1590
+ | `baker images extract <url>` | Pull every image off a URL via Firecrawl | $0.001/scrape | off |
1591
+ | `baker images screenshot <url>` | Website screenshot via ScreenshotOne | $0.009/capture | **on** |
1592
+ | `baker images ingest <url>` | Save a remote URL to the library | ~$0.001–$0.002 (describe + embed) | always on |
1593
+ | `baker images use <url>` | Sugar over `ingest` — waits until `ready` | same as `ingest` | always on |
1594
+ | `baker images get <id>` | Single record | $0 | n/a |
1595
+ | `baker images upload <file>` | Upload a local file | $0 | always on |
1596
+ | `baker images delete <id>` | Delete a record | $0 | n/a |
1597
+
1598
+ **Auto-ingest** runs the full `processImage` pipeline (Gemini describe + Voyage multimodal embed + OpenRouter text embed, ~$0.001–$0.002/image) on top of the provider cost. Override with `--auto-ingest N` (turn on) or `--no-auto-ingest` (turn off where default is on). After auto-ingest the next `baker images library` query for the same concept hits the local row.
1599
+
1600
+ **Hash-dedup is automatic.** `contentHash` (sha256 of bytes) + `externalId` per-source — same JPEG from two providers becomes one library row.
1601
+
1602
+ **`baker images search` is a deprecated alias** for `library` (stderr deprecation log, removed in next minor).
1603
+
1604
+ ### `baker images library <query>`
1605
+
1606
+ Search the company library (hybrid BM25 + vector + Cohere rerank). Use this FIRST before any external provider.
1607
+
1608
+ ```bash
1609
+ baker images library "hero banner"
1610
+ baker images library "logo" --aspect-ratio 1:1 --tags logo
1611
+ baker images library "office" --source magnific
1612
+ baker images library "pricing" --external-url-host competitor.com
1613
+ ```
1614
+
1615
+ **Flags:**
1616
+
1617
+ | Flag | Description |
1618
+ |-----------------------|--------------------------------------------------------------------------|
1619
+ | `--limit` | Max results (default 5) |
1620
+ | `--min-score` | Minimum relevance score, 0-1 |
1621
+ | `--aspect-ratio` | Filter by aspect ratio |
1622
+ | `--tags` | Comma-separated tag names |
1623
+ | `--source` | Filter by source (uploaded, magnific, brandfetch, google_images, firecrawl, screenshotone, iconify, giphy, …) |
1624
+ | `--external-url-host` | Filter by host substring of `externalUrl` (e.g. competitor.com) |
1625
+ | `--output` | Output format: `json` \| `files` \| `md` |
1626
+ | `--fields` | Comma-separated field names to include |
1627
+ | `--full` | Include full metadata |
1628
+
1629
+ > `baker images search` is a deprecated alias for `library` (emits a deprecation log on stderr; removed in the next minor).
1630
+
1631
+ ### `baker images find <query> --sources <list>`
1632
+
1633
+ Fanout image search: library first, then opted-in providers in parallel.
1634
+
1635
+ ```bash
1636
+ baker images find "office" --sources library,magnific --limit 20
1637
+ baker images find "office" --sources library,magnific --fallback --threshold 0.4
1638
+ baker images find "celebration" --sources library,giphy --auto-ingest 3
1639
+ ```
1640
+
1641
+ Providers: `library`, `magnific`, `google`, `iconify`, `brandfetch`, `giphy`. Response shape: `{ groups: { library, external }, meta: { counts, errors } }`. Partial failures (one provider throws) return the successful providers plus a `meta.errors` array; the whole call never fails on a single provider error.
1642
+
1643
+ **Flags:**
1644
+
1645
+ | Flag | Description |
1646
+ |------------------|--------------------------------------------------------------------------------------------|
1647
+ | `--sources` | Comma-separated providers (default `library`) |
1648
+ | `--limit` | Max results per group (default 20, max 50) |
1649
+ | `--fallback` | Skip external providers when the top library score ≥ `--threshold` |
1650
+ | `--threshold` | Library score floor for `--fallback` (default `0.4`) |
1651
+ | `--auto-ingest` | Ingest top N external hits into the library (0–20, default 0) |
1652
+
1653
+ ### `baker images stock <query>`
1654
+
1655
+ Stock search via **Magnific** — Freepik's developer API (post-acquisition rebrand — `api.magnific.com`, header `x-magnific-api-key`). One library, ~250M assets covering photos, vectors, illustrations, icon sets, mockups, PSDs.
1656
+
1657
+ ```bash
1658
+ baker images stock "minimalist office"
1659
+ baker images stock "flat office workers" --type vector
1660
+ baker images stock "hero photo of a kitchen" --type photo --orientation landscape --ai exclude
1661
+ baker images stock "brand pattern" --color "#0a0a0a" --license freemium --auto-ingest 2
1662
+ baker images stock "office reaction" --people only
1663
+ ```
1664
+
1665
+ Cost: $0.002/req. Free tier exists but watermarks previews — pass `--license freemium` to filter to clean free assets explicitly.
1666
+
1667
+ **Flags:**
1668
+
1669
+ | Flag | Description |
1670
+ |------------------|--------------------------------------------------------------------------------------------|
1671
+ | `--type` | Content type: `photo \| vector \| psd` |
1672
+ | `--orientation` | `landscape \| portrait \| square \| panoramic` |
1673
+ | `--license` | `freemium` (free with attribution) or `premium` (paid, watermark-free) |
1674
+ | `--color` | Hex color filter (`#0a0a0a` or `0a0a0a`) |
1675
+ | `--ai` | AI-generated filter: `exclude` or `only` (default: no filter) |
1676
+ | `--people` | People-in-image filter: `include` \| `exclude` \| `only` |
1677
+ | `--order` | `relevance` (default) or `recent` |
1678
+ | `--limit` | Max results (1–50, default 10) |
1679
+ | `--page` | Page number for pagination |
1680
+ | `--auto-ingest` | Ingest top N hits (0–20, default 0) |
1681
+
1682
+ ### `baker images google <query>`
1683
+
1684
+ Google Images via the official Custom Search JSON API. ⚠ Source is unverified web content — inspect before placing.
1685
+
1686
+ ```bash
1687
+ baker images google "industrial workshop" --type photo --size large --limit 20
1688
+ ```
1689
+
1690
+ Cost: $0.005/query above the free tier (100 queries/day free). Custom Search caps at 10 results per call — pagination is automatic and bills per page (`--limit 30` = 3 queries against your daily quota).
1691
+
1692
+ Requires both `GOOGLE_CUSTOM_SEARCH_API_KEY` and `GOOGLE_CUSTOM_SEARCH_ENGINE_ID` (Programmable Search Engine `cx`) set on the Convex deployment, with the engine configured to "Search the entire web" + Image search ON.
1693
+
1694
+ **Flags:**
1695
+
1696
+ | Flag | Description |
1697
+ |------------------|----------------------------------------------------------------------------------------------------------|
1698
+ | `--type` | `imgType`: `photo \| clipart \| lineart \| stock \| animated \| face \| news` |
1699
+ | `--size` | `imgSize`: `icon \| small \| medium \| large \| xlarge \| xxlarge \| huge` |
1700
+ | `--color` | `imgColorType`: `color \| gray \| mono \| trans` |
1701
+ | `--safe` | `off \| active` |
1702
+ | `--limit` | Max results (1–50, paginated 10 per call) |
1703
+ | `--auto-ingest` | Ingest top N (0–20, default 0) |
1704
+
1705
+ ### `baker images logo <domain>`
1706
+
1707
+ Brand logo via Brandfetch CDN (`fallback/404`). Returns up to 5 variants per domain (icon, light/dark logo, light/dark symbol). Auto-ingests the first by default.
1708
+
1709
+ ```bash
1710
+ baker images logo stripe.com
1711
+ baker images logo linear.app --variant logo
1712
+ baker images logo example.com --no-auto-ingest
1713
+ ```
1714
+
1715
+ If the domain isn't in Brandfetch the result is empty — fall back to `baker images extract https://<domain>` to pull the logo from the site directly.
1716
+
1717
+ **Flags:**
1718
+
1719
+ | Flag | Description |
1720
+ |---------------------|--------------------------------------------------------------------------|
1721
+ | `--variant` | Pin to one variant: `icon \| logo \| symbol` (default: try all 5) |
1722
+ | `--no-auto-ingest` | Skip the default top-1 ingest |
1723
+
1724
+ ### `baker images icon <name> [--set <set>]`
1725
+
1726
+ Icon lookup via Iconify (200+ icon sets). Free, no API key.
1727
+
1728
+ ```bash
1729
+ baker images icon react --set devicon
1730
+ baker images icon lucide:check --color "#0a0a0a" --width 24
1731
+ baker images icon stripe # tries simple-icons → logos → devicon
1732
+ ```
1733
+
1734
+ Pass a prefixed id (`lucide:check`) to pin both set and name explicitly. Without `--set`, the lookup chain is `simple-icons → logos → devicon`.
1735
+
1736
+ **Flags:**
1737
+
1738
+ | Flag | Description |
1739
+ |------------|------------------------------------------------------------------------------------------------------|
1740
+ | `--set` | Iconify set (`simple-icons`, `logos`, `lucide`, `devicon`, `heroicons`, `tabler`, `phosphor`, …) |
1741
+ | `--color` | Hex color — replaces `currentColor` in the SVG |
1742
+ | `--width` | Render width in px (height auto-scales) |
1743
+
1744
+ ### `baker images gif <query>`
1745
+
1746
+ Search **Giphy** for GIFs / reaction memes — built for paid-social creative (Meta, TikTok, LinkedIn, X). Free API, no per-request cost. Replaces the discontinued Tenor integration.
1747
+
1748
+ ```bash
1749
+ baker images gif "this is fine" --limit 10
1750
+ baker images gif "office reaction" --rating pg --auto-ingest 2
1751
+ baker images gif "celebration" --lang es
1752
+ baker images gif --trending --limit 25
1753
+ ```
1754
+
1755
+ Each hit returns the primary URL (WebP — best for ingest) plus `providerMeta.gifUrl`, `providerMeta.mp4Url`, `providerMeta.webpUrl` so you can pick the right format per platform. `providerMeta.kind` is `"gif"`. `externalUrl` points at the Giphy permalink for verification.
1756
+
1757
+ **Flags:**
1758
+
1759
+ | Flag | Description |
1760
+ |------------------|--------------------------------------------------------------------------------------------|
1761
+ | `--trending` | Fetch the current trending feed (omit `<query>` when set) |
1762
+ | `--limit` | Max results (default 20, max 50) |
1763
+ | `--rating` | Content rating: `g \| pg \| pg-13 \| r` (default `pg`) |
1764
+ | `--lang` | ISO 639-1 language code (`en`, `es`, `fr`, …) to bias results |
1765
+ | `--auto-ingest` | Ingest top N (0–20, default 0). Ingest uses the WebP URL; `processImage` partial-fails on animated GIFs (no thumbhash/palette) but describe + embed still work. |
1766
+
1767
+ ### `baker images sticker <query>`
1768
+
1769
+ Search **Giphy's sticker corpus** — same API as `gif`, different corpus. Stickers are transparent-background WebPs / GIFs, ideal for overlaying on ad creative (Stories, Reels, banners).
1770
+
1771
+ ```bash
1772
+ baker images sticker "thumbs up" --limit 10
1773
+ baker images sticker celebration --rating g --auto-ingest 3
1774
+ baker images sticker --trending --limit 25
1775
+ ```
1776
+
1777
+ Same response shape as `gif`. `providerMeta.kind` is `"sticker"`; `externalUrl` points at `https://giphy.com/stickers/<id>`.
1778
+
1779
+ **Flags:** identical to `baker images gif` (`--trending`, `--limit`, `--rating`, `--lang`, `--auto-ingest`).
1780
+
1781
+ ### `baker images extract <url>`
1782
+
1783
+ Pull every image from a single URL via Firecrawl (`formats: ["images"]`).
1784
+
1785
+ ```bash
1786
+ baker images extract https://stripe.com --auto-ingest 5
1787
+ baker images extract https://example.com --wait-for 1500 --limit 20
1788
+ ```
1789
+
1790
+ Every image extracted from a page shares the scraped-page URL as `externalUrl`. Big pages can return 100+ images — cap auto-ingest at 20.
1791
+
1792
+ Cost: $0.001/scrape. JS-rendered pages with `--wait-for` cost the heavier credit bucket.
1793
+
1794
+ **Flags:**
1795
+
1796
+ | Flag | Description |
1797
+ |------------------|--------------------------------------------------------------------------------------------|
1798
+ | `--wait-for` | JS render wait in ms (0–30000) |
1799
+ | `--limit` | Max images returned (default 50) |
1800
+ | `--auto-ingest` | Ingest top N (0–20, default 0) |
1801
+
1802
+ ### `baker images screenshot <url>`
1803
+
1804
+ Capture a website screenshot via ScreenshotOne. Auto-ingests on success.
1805
+
1806
+ ```bash
1807
+ baker images screenshot https://stripe.com
1808
+ baker images screenshot https://stripe.com --full-page --viewport 1440x900
1809
+ baker images screenshot https://stripe.com --format png
1810
+ ```
1811
+
1812
+ Auto-ingests with prefetched bytes (no double-fetch). The screenshot bytes themselves are the artifact — `externalUrl` is the captured URL.
1813
+
1814
+ Cost: $0.009/capture. ScreenshotOne caches captures for 30 days, so re-shotting the same URL within that window is cheap.
1815
+
1816
+ **Flags:**
1817
+
1818
+ | Flag | Description |
1819
+ |----------------|--------------------------------------------------------------------------------------------|
1820
+ | `--full-page` | Capture the full scrolled page (default: viewport only) |
1821
+ | `--viewport` | `WxH` viewport (default `1280x800`) |
1822
+ | `--format` | `webp \| png \| jpg` (default `webp`) |
1823
+
1824
+ ### `baker images ingest <url> --source <enum>`
1825
+
1826
+ Download a remote URL and store it in the library. Byte-exact deduped via sha256 + externalId, then queued for describe + embed.
1827
+
1828
+ ```bash
1829
+ baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific --external-id 12345
1830
+ baker images ingest https://acme.com/hero.png --source firecrawl --external-url https://acme.com/pricing --context "competitor pricing hero"
1831
+ ```
1832
+
1833
+ Returns `{ imageId, deduped, contentHash }`. When `deduped: true`, an existing library row is returned — no new bytes are stored. Max ingest size 25MB.
1834
+
1835
+ **Flags:**
1836
+
1837
+ | Flag | Description |
1838
+ |------------------|--------------------------------------------------------------------------------------------|
1839
+ | `--source` | **Required.** Source enum (`uploaded`, `magnific`, `brandfetch`, `google_images`, `firecrawl`, `screenshotone`, `iconify`, `giphy`, `instagram`, …) |
1840
+ | `--external-id` | Provider asset id — enables per-source dedup before bytes are fetched |
1841
+ | `--external-url` | Canonical page URL (parent page for scraped/Google hits, provider page for stock) |
1842
+ | `--context` | Free-text hint passed to Gemini describe to bias the generated description and tags |
1843
+
1844
+ ### `baker images use <url>`
1845
+
1846
+ Sugar over `ingest`: stores the URL and polls `get` until the library record is `ready` (or errored). Returns the ingest result plus the ready image doc — synchronous from the agent's perspective.
1579
1847
 
1580
1848
  ```bash
1581
- baker images search "hero banner"
1582
- baker images search "logo" --aspect-ratio 1:1 --tags logo
1583
- baker images search "team photo" --limit 5 --min-score 0.3
1849
+ baker images use https://cdn.example.com/hero.png
1850
+ baker images use https://cdn.example.com/hero.png --source magnific --max-wait 60000
1584
1851
  ```
1585
1852
 
1586
1853
  **Flags:**
1587
1854
 
1588
- | Flag | Description |
1589
- |------------------|--------------------------------------------------------------------------|
1590
- | `--limit` | Max results (default 5) |
1591
- | `--min-score` | Minimum relevance score, 0-1 |
1592
- | `--aspect-ratio` | Filter by aspect ratio (1:1, 16:9, 9:16, 2:3, 3:4, 1:2, 2:1, 4:5, 3:2, 4:3) |
1593
- | `--tags` | Comma-separated tag names to filter by |
1594
- | `--output` | Output format: `json` \| `files` \| `md` |
1595
- | `--fields` | Comma-separated field names to include |
1596
- | `--full` | Include full metadata |
1855
+ | Flag | Description |
1856
+ |----------------|--------------------------------------------------------------------------------------------|
1857
+ | `--source` | Source enum (default `uploaded`) |
1858
+ | `--max-wait` | Max wait ms before returning `TIMEOUT` (default `30000`, polled every 1500ms) |
1597
1859
 
1598
1860
  ### `baker images get <id>`
1599
1861
 
@@ -1694,7 +1956,7 @@ baker actions release <action-id>
1694
1956
  baker actions create --name "Build hero" --description "..." --tag copy,landing
1695
1957
  # → returns { ok, data: { tempId }, hints: [...] } — check hints for dependencies/tags/description reminders
1696
1958
  baker actions update <action-id> --name "Better name"
1697
- baker actions complete <action-id> --note "What was done" # stages — applies on chat publish
1959
+ baker actions complete <action-id-or-tempId> --note "What was done" # stages — applies on chat publish
1698
1960
  baker actions discard <action-id> --reason "obsolete"
1699
1961
 
1700
1962
  baker actions link --blocker <id-or-tempId> --blocked <id-or-tempId>
package/dist/cli.js CHANGED
@@ -12,7 +12,7 @@ import { videosCommand } from "./commands/videos/index.js";
12
12
  const main = defineCommand({
13
13
  meta: {
14
14
  name: "baker",
15
- version: "0.28.1",
15
+ version: "0.32.0",
16
16
  description: `AI-agent CLI for finding and managing images, videos, testimonials, action items, and ad platform data in Baker.
17
17
 
18
18
  Auth: Set BAKER_API_KEY (starts with bk_) and BAKER_API_URL environment variables.
@@ -1,12 +1,12 @@
1
1
  export declare const completeCommand: import("citty").CommandDef<{
2
2
  readonly id: {
3
3
  readonly type: "positional";
4
- readonly description: "Action ID";
4
+ readonly description: "Action ID or temp ID";
5
5
  readonly required: false;
6
6
  };
7
7
  readonly "action-id": {
8
8
  readonly type: "string";
9
- readonly description: "Action ID";
9
+ readonly description: "Action ID or temp ID";
10
10
  readonly required: false;
11
11
  };
12
12
  readonly note: {
@@ -1 +1 @@
1
- {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/commands/actions/complete.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;EAyB1B,CAAC"}
1
+ {"version":3,"file":"complete.d.ts","sourceRoot":"","sources":["../../../src/commands/actions/complete.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;EA2B1B,CAAC"}
@@ -2,23 +2,23 @@ import { defineCommand } from "citty";
2
2
  import { apiPost, validateConvexId } from "../../client.js";
3
3
  import { requireChatId } from "../../env.js";
4
4
  import { registerSchema } from "../../schemas.js";
5
- import { failApi, failValidation, writeOk } from "./shared.js";
5
+ import { failApi, failValidation, isTempId, writeOk } from "./shared.js";
6
6
  registerSchema({
7
7
  command: "actions.complete",
8
- description: "Stage completion of a claimed action. The action stays claimed and in_progress until the chat is published only then does it become completed.",
8
+ description: "Stage completion of an action. Accepts a real action ID (must be claimed) or a temp ID from the same draft. The action becomes completed when the chat is published.",
9
9
  args: {
10
- id: { type: "string", description: "Action ID (must be claimed by current chat)", required: true },
10
+ id: { type: "string", description: "Action ID or temp ID", required: true },
11
11
  note: { type: "string", description: "What was done — context for the team and AI", required: false },
12
12
  },
13
13
  });
14
14
  export const completeCommand = defineCommand({
15
15
  meta: {
16
16
  name: "complete",
17
- description: "Stage completion of a claimed action. Real completion happens on chat publish. Example: baker actions complete <id>",
17
+ description: "Stage completion of an action. Accepts real IDs (claimed) or temp IDs (same draft). Example: baker actions complete <id>",
18
18
  },
19
19
  args: {
20
- id: { type: "positional", description: "Action ID", required: false },
21
- "action-id": { type: "string", description: "Action ID", required: false },
20
+ id: { type: "positional", description: "Action ID or temp ID", required: false },
21
+ "action-id": { type: "string", description: "Action ID or temp ID", required: false },
22
22
  note: { type: "string", description: "What was done — context for the team and AI", required: false },
23
23
  },
24
24
  run: async ({ args }) => {
@@ -27,9 +27,11 @@ export const completeCommand = defineCommand({
27
27
  if (!id) {
28
28
  failValidation("Action ID is required.");
29
29
  }
30
- validateConvexId(id);
30
+ if (!isTempId(id)) {
31
+ validateConvexId(id);
32
+ }
31
33
  const chatId = requireChatId();
32
- await apiPost("/api/actions/complete", { chatId, actionId: id, note: args.note });
34
+ await apiPost("/api/actions/complete", { chatId, actionRef: id, note: args.note });
33
35
  writeOk();
34
36
  }
35
37
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../src/commands/actions/complete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE/D,cAAc,CAAC;IACb,OAAO,EAAE,kBAAkB;IAC3B,WAAW,EACT,kJAAkJ;IACpJ,IAAI,EAAE;QACJ,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE,QAAQ,EAAE,IAAI,EAAE;QAClG,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE,QAAQ,EAAE,KAAK,EAAE;KACtG;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;IAC3C,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU;QAChB,WAAW,EACT,qHAAqH;KACxH;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE;QACrE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1E,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE,QAAQ,EAAE,KAAK,EAAE;KACtG;IACD,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,GAAI,IAAI,CAAC,EAAyB,IAAK,IAAI,CAAC,WAAW,CAAwB,CAAC;YACxF,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,cAAc,CAAC,wBAAwB,CAAC,CAAC;YAC3C,CAAC;YACD,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACrB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,OAAO,CAAe,uBAAuB,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAChG,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"complete.js","sourceRoot":"","sources":["../../../src/commands/actions/complete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEzE,cAAc,CAAC;IACb,OAAO,EAAE,kBAAkB;IAC3B,WAAW,EACT,sKAAsK;IACxK,IAAI,EAAE;QACJ,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC3E,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE,QAAQ,EAAE,KAAK,EAAE;KACtG;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,aAAa,CAAC;IAC3C,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU;QAChB,WAAW,EACT,0HAA0H;KAC7H;IACD,IAAI,EAAE;QACJ,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,sBAAsB,EAAE,QAAQ,EAAE,KAAK,EAAE;QAChF,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE,QAAQ,EAAE,KAAK,EAAE;QACrF,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE,QAAQ,EAAE,KAAK,EAAE;KACtG;IACD,GAAG,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,MAAM,EAAE,GAAI,IAAI,CAAC,EAAyB,IAAK,IAAI,CAAC,WAAW,CAAwB,CAAC;YACxF,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,cAAc,CAAC,wBAAwB,CAAC,CAAC;YAC3C,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;gBAClB,gBAAgB,CAAC,EAAE,CAAC,CAAC;YACvB,CAAC;YACD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,OAAO,CAAe,uBAAuB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACjG,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
@@ -2,4 +2,5 @@ export declare function writeOk<T = null>(data?: T): void;
2
2
  export declare function failValidation(message: string): never;
3
3
  export declare function failApi(err: unknown): never;
4
4
  export declare function generateTempId(): string;
5
+ export declare function isTempId(id: string): boolean;
5
6
  //# sourceMappingURL=shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/actions/shared.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAEhD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAGrD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CAW3C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC"}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/commands/actions/shared.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAEhD;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,KAAK,CAGrD;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CAW3C;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAE5C"}
@@ -22,4 +22,7 @@ export function failApi(err) {
22
22
  export function generateTempId() {
23
23
  return `temp_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
24
24
  }
25
+ export function isTempId(id) {
26
+ return id.startsWith("temp_");
27
+ }
25
28
  //# sourceMappingURL=shared.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/actions/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,OAAO,CAAW,IAAQ;IACxC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,CAAM,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC5B,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACtF,CAAC"}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/commands/actions/shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,UAAU,OAAO,CAAW,IAAQ;IACxC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,IAAI,IAAI,CAAM,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAY;IAClC,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;QAC5B,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;QACzB,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IACzF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,EAAU;IACjC,OAAO,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC"}
@@ -0,0 +1,23 @@
1
+ export declare const extractCommand: import("citty").CommandDef<{
2
+ readonly url: {
3
+ readonly type: "positional";
4
+ readonly description: "URL to scrape";
5
+ readonly required: false;
6
+ };
7
+ readonly "wait-for": {
8
+ readonly type: "string";
9
+ readonly description: "JS render wait ms";
10
+ readonly required: false;
11
+ };
12
+ readonly limit: {
13
+ readonly type: "string";
14
+ readonly description: "Max returned images";
15
+ readonly required: false;
16
+ };
17
+ readonly "auto-ingest": {
18
+ readonly type: "string";
19
+ readonly description: "Auto-ingest top N";
20
+ readonly required: false;
21
+ };
22
+ }>;
23
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../../../src/commands/images/extract.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;EAmCzB,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { defineCommand } from "citty";
2
+ import { ApiError, apiPost } from "../../client.js";
3
+ import { writeJson } from "../../output.js";
4
+ import { registerSchema } from "../../schemas.js";
5
+ registerSchema({
6
+ command: "images.extract",
7
+ description: "Extract images from a URL via Firecrawl (formats: images).",
8
+ args: {
9
+ url: { type: "string", description: "URL to scrape", required: true },
10
+ "wait-for": { type: "number", description: "JS render wait ms", required: false },
11
+ limit: { type: "number", description: "Limit returned images", required: false, default: 50 },
12
+ "auto-ingest": { type: "number", description: "Auto-ingest top N", required: false, default: 0 },
13
+ },
14
+ });
15
+ export const extractCommand = defineCommand({
16
+ meta: {
17
+ name: "extract",
18
+ description: "Pull every image from a single URL via Firecrawl. ~$0.001/scrape. Cap auto-ingest at 20.\n\nExample: baker images extract https://stripe.com --auto-ingest 5",
19
+ },
20
+ args: {
21
+ url: { type: "positional", description: "URL to scrape", required: false },
22
+ "wait-for": { type: "string", description: "JS render wait ms", required: false },
23
+ limit: { type: "string", description: "Max returned images", required: false },
24
+ "auto-ingest": { type: "string", description: "Auto-ingest top N", required: false },
25
+ },
26
+ run: async ({ args }) => {
27
+ try {
28
+ const url = args.url;
29
+ if (!url) {
30
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "URL is required" } });
31
+ process.exit(1);
32
+ }
33
+ const body = { url };
34
+ if (args["wait-for"])
35
+ body.waitFor = Number(args["wait-for"]);
36
+ if (args.limit)
37
+ body.limit = Number(args.limit);
38
+ if (args["auto-ingest"])
39
+ body.autoIngest = Number(args["auto-ingest"]);
40
+ const data = await apiPost("/api/images/extract", body);
41
+ writeJson({ ok: true, data });
42
+ }
43
+ catch (err) {
44
+ if (err instanceof ApiError) {
45
+ writeJson({ ok: false, error: { code: err.code, message: err.message } });
46
+ process.exit(1);
47
+ }
48
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
49
+ process.exit(1);
50
+ }
51
+ },
52
+ });
53
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../../../src/commands/images/extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ export declare const findCommand: import("citty").CommandDef<{
2
+ readonly query: {
3
+ readonly type: "positional";
4
+ readonly description: "Search query";
5
+ readonly required: false;
6
+ };
7
+ readonly sources: {
8
+ readonly type: "string";
9
+ readonly description: "Comma-separated providers";
10
+ readonly required: false;
11
+ };
12
+ readonly limit: {
13
+ readonly type: "string";
14
+ readonly description: "Max results per group (default 20)";
15
+ readonly required: false;
16
+ };
17
+ readonly fallback: {
18
+ readonly type: "boolean";
19
+ readonly description: "Cascade to externals only when library thin";
20
+ readonly required: false;
21
+ };
22
+ readonly threshold: {
23
+ readonly type: "string";
24
+ readonly description: "Fallback threshold (default 0.4)";
25
+ readonly required: false;
26
+ };
27
+ readonly "auto-ingest": {
28
+ readonly type: "string";
29
+ readonly description: "Auto-ingest top N external hits";
30
+ readonly required: false;
31
+ };
32
+ }>;
33
+ //# sourceMappingURL=find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/commands/images/find.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCtB,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { defineCommand } from "citty";
2
+ import { ApiError, apiPost } from "../../client.js";
3
+ import { writeJson } from "../../output.js";
4
+ import { registerSchema } from "../../schemas.js";
5
+ registerSchema({
6
+ command: "images.find",
7
+ description: "Fanout image search: library first, then opted-in external providers.",
8
+ args: {
9
+ query: { type: "string", description: "Search query", required: true },
10
+ sources: {
11
+ type: "string",
12
+ description: "Comma-separated providers: library,magnific,google,iconify,brandfetch,giphy",
13
+ required: false,
14
+ },
15
+ limit: { type: "number", description: "Max results per group", required: false, default: 20 },
16
+ fallback: {
17
+ type: "boolean",
18
+ description: "Only cascade to externals when top library score < threshold",
19
+ required: false,
20
+ default: false,
21
+ },
22
+ threshold: { type: "number", description: "Fallback threshold (0-1)", required: false, default: 0.4 },
23
+ "auto-ingest": { type: "number", description: "Auto-ingest top N external hits", required: false, default: 0 },
24
+ },
25
+ });
26
+ export const findCommand = defineCommand({
27
+ meta: {
28
+ name: "find",
29
+ description: "Library-first fanout image search. Opt in to providers with --sources. `--fallback` short-circuits to externals only when library is thin.\n\nExample: baker images find 'office' --sources library,magnific --limit 20",
30
+ },
31
+ args: {
32
+ query: { type: "positional", description: "Search query", required: false },
33
+ sources: { type: "string", description: "Comma-separated providers", required: false },
34
+ limit: { type: "string", description: "Max results per group (default 20)", required: false },
35
+ fallback: { type: "boolean", description: "Cascade to externals only when library thin", required: false },
36
+ threshold: { type: "string", description: "Fallback threshold (default 0.4)", required: false },
37
+ "auto-ingest": { type: "string", description: "Auto-ingest top N external hits", required: false },
38
+ },
39
+ run: async ({ args }) => {
40
+ try {
41
+ const query = args.query;
42
+ if (!query) {
43
+ writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Query is required" } });
44
+ process.exit(1);
45
+ }
46
+ const body = { query };
47
+ if (args.sources)
48
+ body.sources = args.sources.split(",").filter(Boolean);
49
+ if (args.limit)
50
+ body.limit = Number(args.limit);
51
+ if (args.fallback)
52
+ body.fallback = true;
53
+ if (args.threshold)
54
+ body.threshold = Number(args.threshold);
55
+ if (args["auto-ingest"])
56
+ body.autoIngest = Number(args["auto-ingest"]);
57
+ const data = await apiPost("/api/images/find", body);
58
+ writeJson({ ok: true, data });
59
+ }
60
+ catch (err) {
61
+ if (err instanceof ApiError) {
62
+ writeJson({ ok: false, error: { code: err.code, message: err.message } });
63
+ process.exit(1);
64
+ }
65
+ writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
66
+ process.exit(1);
67
+ }
68
+ },
69
+ });
70
+ //# sourceMappingURL=find.js.map