diff --git a/CLAUDE.md b/CLAUDE.md index a06bc3a..df430c5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -287,6 +287,38 @@ failures: it gains the 0.3.7 chat-retry layer (`TINYCLOUD_MODEL_RETRIES` now covers both agents), and an errored turn is truthful — `✖ turn failed` on stderr, an `error` field in the `--json` trace, exit 1 (previously a backend blip could exit 0 with an empty, zero-usage trace). +0.3.20 picks up SDK 0.7.24 and adds **playable Slack unfurls and entity +search** (features 42→45, verbs stay 17): `--link-preview` on `publish` and +`publish video` gains a `player` level (feature +`publish.link.preview.player.v1`) — the pasted link unfurls in Slack with an +INLINE PLAYER via the Cloudglue Slack app instead of a static card. On a +private share, `player` makes the share itself play; a site plays its hero +share, set with the new site-only `--preview-share ` flag (requires +`--link-preview player`; `""` clears; without a hero the unfurl stays +card-only). Unlike `full`, `player` matters on BOTH site visibilities — a +public site's hero must be a public share, and public *shares* already unfurl +playable with no flag. Private content plays only in Slack workspaces the +account owner connected in the Cloudglue dashboard; `player` implies the +`full` card, anyone who can see the Slack message can play the video (every +doc surface says ask the user first), and downgrading revokes playback in +already-posted unfurls. The card-field flags now accept `full` or `player`; +the hero comes back as `data.preview_share_id` and in `publish list` rows as +`link-preview=player hero=`. Entity search (features `probe.entities.v1` +/ `probe.scope.auto.v1`): an `entities` collection is a first-class +`probe`/`ask` target — each file's latest completed extraction is indexed +into search documents for free; video-level extractions search at `--scope +file`, segment-level at `--scope segment` (tinycloud-created entities +collections are segment-level by default), and omitting `--scope` is now AUTO +(the search picks the level per scope, so probing no longer requires knowing +the collection type — previously an omitted scope meant segment-only). +`collections show` file rows gain `searchable_status` (the metadata/entity +search-index readiness signal, distinct from the enrichment `status`), and +the SDK bump also makes `publish video list`'s file filter bind server-side +(the SDK previously sent camelCase query keys the API ignored; tinycloud's +client-side filter masked it). Because the skill teaches the new +flag values and probe semantics, the floor was raised to 0.3.20 (same +merge-after-CDN gate — the dist PR merges only after CDN `channels.stable` = +0.3.20). The host-level `profile` verb and the leading global flags `--home`/`--profile` (also `$TINYCLOUD_HOME`; 0.3.3+) relocate state and are intentionally absent from `commands --json` — like the launcher's install/update, they're CLI/host @@ -339,9 +371,9 @@ of printing JSON. Any script invoking the binary must redirect ` --from col_desc --json tinycloud library collections delete col_desc --json @@ -152,6 +155,9 @@ tinycloud publish video ./demo.mp4 --visibility public --json tinycloud publish video ./demo.mp4 --clip-start 18 --clip-end 33 --json # Hard clip — the share page plays ONLY the moment (0.3.8+) tinycloud publish video ./demo.mp4 --clip-start 18 --clip-end 33 --clip-only --json +# Playable Slack unfurl (0.3.20+, ASK THE USER FIRST): the pasted link plays inline in Slack +tinycloud publish video ./demo.mp4 --visibility private --link-preview player --json +tinycloud publish ./site --link-preview player --preview-share --json # site link plays its hero share ``` Per-verb details and all flags: [reference/verbs.md](reference/verbs.md). @@ -208,10 +214,23 @@ Authoring your own recipes: [reference/workflow-authoring.md](reference/workflow added to collections. Local `search` can match cached `see` results. - Do not pass `--background` to `ask`; background jobs exist only for tracked async ops (`watch`, `see`, `extract`). +- `probe`/`ask` scope (0.3.20+): omit `--scope` for AUTO — the search picks + the right level for the collection (media, metadata, or entities) itself, + so you no longer need to know a collection's type before probing it. An + explicit `--scope` still forces a level: `metadata` and video-level + `entities` collections are file-level (`--scope segment` errors); + segment-level `entities` collections search at `--scope segment` — and + collections created by `collections create --type entities` are + segment-level by default. +- Entity search (0.3.20+): an `entities` collection is a first-class + `probe`/`ask` target — each file's latest completed extraction is indexed + into search documents for free. `probe` FINDS entity content (segment hits + carry real timestamps); `query` still MEASURES it. Wait for + `files[].searchable_status == "completed"` in `collections show` before + expecting hits. - `probe --filter` works only with a collection scope (`--in - collection:col_…`), and a `metadata` collection is file-level — probe it - with `--scope file` (segment scope errors). `source_metadata.*` filters are - file-level facts too, so pair them with `--scope file`. + collection:col_…`). `source_metadata.*` filters are file-level facts, so + pair them with `--scope file`. - `query` (0.3.17+) is for analytics, not search: when the task is to COUNT, GROUP, rank, or join across a collection ("how many…", "which … most", "total hours per host"), reach for `query`, not `probe`/`ask`. Run `query @@ -265,6 +284,16 @@ Authoring your own recipes: [reference/workflow-authoring.md](reference/workflow link (content and playback stay sign-in gated), and platforms cache per exact URL, so turning it back off does not retract posted cards. Details in [reference/verbs.md](reference/verbs.md). +- Playable Slack unfurls (0.3.20+): `--link-preview player` upgrades the + Slack card to an **inline player** (via the Cloudglue Slack app; implies the + `full` card). A private share plays itself; a site — public or private — + plays the hero share set with `--preview-share ` (a public site's + hero must be a public share; public *shares* already unfurl playable, no + flag needed). Private content plays only in Slack workspaces the account + owner has connected in the Cloudglue dashboard. ⚠️ Anyone who can see the + Slack message can play the video — always ask the user before opting + private content in; downgrading to `full`/`none` revokes playback in + already-posted unfurls. Details in [reference/verbs.md](reference/verbs.md). - Live-API components (0.3.6+; the fuller v8–v12 surface is taught from 0.3.18): the same embed script also defines collection-scoped, **private-site-only** elements that let viewers search/chat/query inside a diff --git a/skills/tinycloud/reference/verbs.md b/skills/tinycloud/reference/verbs.md index b0d840a..92d2c69 100644 --- a/skills/tinycloud/reference/verbs.md +++ b/skills/tinycloud/reference/verbs.md @@ -155,11 +155,32 @@ place during the scan, nothing is re-billed). ### probe — semantic search (cloud) ```bash -tinycloud probe "" --in collection:col_… [--scope file|segment] [--limit 20] +tinycloud probe "" --in collection:col_… [--limit 20] # no --scope = AUTO (0.3.20+) +tinycloud probe "" --in collection:col_… --scope file|segment # force a level tinycloud probe "" --in collection:col_… --scope file \ --filter "source_metadata.host_email=kevin@acme.com" --filter "source_metadata.tags*=demo,intro" ``` +**Auto scope (0.3.20+, feature `probe.scope.auto.v1`)**: omit `--scope` and +the search picks the right level for the collection itself (and can fan out +to file + segment plans and fuse the results) — so a bare +`probe "" --in collection:` works on media-descriptions, metadata, and +entities collections alike, without knowing the collection's type first. An +explicit `--scope` forces the level and must be supported by the collection: +`metadata` and video-level `entities` collections are file-level +(`--scope segment` errors); segment-level `entities` collections search at +`segment`. + +**Entity search (0.3.20+, feature `probe.entities.v1`)**: an `entities` +collection is a first-class probe target — each file's latest completed +extraction is indexed into search documents for free after the extract job. +Video-level extractions surface as file hits; segment-level ones as segment +hits with real start/end times (citations resolve like media segments) — +collections created by `library collections create --type entities` are +segment-level by default, so expect segment hits. Wait +for `files[].searchable_status == "completed"` in `collections show` before +expecting hits. `probe` FINDS entity content; `query` MEASURES it. + `--filter ` (0.3.15+, feature `probe.filters.v1`; repeatable, ANDed, collection scopes only) narrows the searched set by stored fields before semantic ranking. Criteria are ANDed — with each other and with any @@ -175,9 +196,9 @@ through arrays match when ANY element matches; ISO datetime fields compare as strings with `<`/`>`), `metadata.*` (user metadata from `collections add --metadata`), `video_info.duration_seconds|has_audio`, and `file.filename|bytes|uri|created_at|id`. source_metadata filters are -file-level facts — pair them with `--scope file`. Probing a `metadata` -collection requires `--scope file` (its documents are file-level; segment -scope errors). +file-level facts — pair them with `--scope file`. A `metadata` collection is +file-level: probe it with `--scope file` or no `--scope` at all (auto); +explicit `--scope segment` errors. ### ask — grounded Q&A (cloud) @@ -186,6 +207,9 @@ tinycloud ask "" --in [--include-citations[=false]] ``` +`ask` accepts the same collection scopes as `probe` — media-descriptions, +rich-transcripts, metadata, and (0.3.20+) entities collections; the answer +grounds itself in whichever document kinds the collection carries. Never pass `--background` to `ask`. ### query — structured analytics over collections (cloud, 0.3.17+) @@ -370,7 +394,12 @@ completed`; `failed` is terminal) — a query before then returns empty or error `has_more`, and `next_page_token` — page with `--page-token` until the token is null (0.3.16+, feature `library.collections.pagination.v1`; earlier binaries capped every listing at 50 with a wrong `has_more: false` and a -redacted token, so a >50-file collection could not be enumerated). +redacted token, so a >50-file collection could not be enumerated). Each file +row's `status` is the enrichment readiness (poll to `completed` before +querying); on metadata and entities collections rows also carry +`searchable_status` (0.3.20+) — the search-index readiness for the file's +metadata/entity documents (`completed` = findable via `probe`/`ask`; it can +lag `status` briefly while docs index). The collection's `--type` decides which verb reads it (every type follows the same `create → add → poll show → query → delete` lifecycle): @@ -379,9 +408,9 @@ same `create → add → poll show → query → delete` lifecycle): |---|---| | `media-descriptions` (default) | `ask` / `probe` / `search` (`--in collection:`) | | `face-analysis` | `face list` / `face search` | -| `entities` (needs `--prompt`/`--schema`) | `library collections entities ` | +| `entities` (needs `--prompt`/`--schema`) | `library collections entities `; also `probe` / `ask` (0.3.20+ — entities are search-indexed free) | | `rich-transcripts` | `collections sync --artifacts transcripts` | -| `metadata` (0.3.15+, free) | `probe --scope file` / `ask` | +| `metadata` (0.3.15+, free) | `probe` / `ask` (file-level; omit `--scope` or use `--scope file`) | Every type is additionally queryable with `query` (0.3.17+) for analytics — counts, group-bys, joins over file attributes, user/connector metadata, and @@ -397,8 +426,9 @@ index connector `source_metadata` plus user `--metadata` fields into file-level search documents WITHOUT downloading or processing the media — indexing is free and near-instant (no describe/transcribe jobs, so `add` readiness is quick). Add google-drive, dropbox, zoom, gong, recall, grain, or -iconik URIs/share links (or already-synced files) and query with -`probe --scope file` (segment scope errors) or `ask`, using `--filter` on +iconik URIs/share links (or already-synced files) and query with `probe` +(omit `--scope` for auto, or `--scope file`; explicit segment scope errors) +or `ask`, using `--filter` on `source_metadata.*`/`metadata.*` paths to narrow. Use one to triage a large connector library (titles, participants, dates, tags) before paying for full processing in a `media-descriptions` collection. @@ -481,7 +511,8 @@ tinycloud workflow [--param k=v] [--segment ] [--out ] ```bash tinycloud publish [--name ] [--visibility public|private] - [--link-preview none|full] [--preview-title ] [--preview-image ] --json + [--link-preview none|full|player] [--preview-title ] [--preview-image ] + [--preview-share ] --json tinycloud publish list --json # sites for this account, with URLs tinycloud publish unpublish --json # site_id, site name, or the --name label ``` @@ -529,10 +560,12 @@ completely differently: `--link-preview` is flippable on an **existing** site without republishing content: the run reports `action: "settings-only"` (a settings PATCH, no re-upload, no new version). The state comes back as `data.link_preview` (plus -`data.preview_title` / `data.preview_image_url`) and shows in `publish list` -rows as `link-preview=full`. `--preview-title`/`--preview-image` require -`--link-preview full`, and a non-absolute `--preview-image` errors before any -upload. +`data.preview_title` / `data.preview_image_url` / `data.preview_share_id`) +and shows in `publish list` rows as `link-preview=full` or +`link-preview=player hero=`. `--preview-title`/`--preview-image` require +`--link-preview full` or `player`, `--preview-share` requires +`--link-preview player`, and a non-absolute `--preview-image` errors before +any upload. ⚠️ **Ask the user before opting a private site in.** `--link-preview full` makes the card title, the site description, and the card image readable by @@ -542,12 +575,26 @@ or cookies; the site stays sign-in gated). Platforms cache per exact URL and rehost the image, so flipping back to `none` stops *future* unfurls but does not retract already-posted cards. +**Playable Slack unfurls (0.3.20+, `publish.link.preview.player.v1`)** — +`--link-preview player` upgrades the Slack unfurl from a static card to an +**inline player** (via the Cloudglue Slack app; other platforms still show +the card). It implies the `full` card, so every card rule above applies. A +site plays its **hero share**, set with `--preview-share ` (a share +id from `publish video`; without one the unfurl stays card-only; pass `""` to +clear). Unlike `full`, `player` matters on **both** visibilities: a public +site's hero must be a **public** share, and a private site's hero plays only +in Slack workspaces the account owner has connected in the Cloudglue +dashboard (Settings → Slack) — everywhere else the link falls back to the +ordinary card. ⚠️ Anyone who can see the Slack message can play the video — +ask the user before opting private content in. Downgrading to `full`/`none` +revokes playback in already-posted unfurls (posted cards are not retracted). + ### publish video — share a video ```bash tinycloud publish video [--visibility public|private] # default public [--name ] [--segment-id <id>] [--clip-start <s> --clip-end <e> [--clip-only]] - [--link-preview none|full] --json + [--link-preview none|full|player] --json tinycloud publish video list [--in <source>] [--visibility public|private] --json tinycloud publish video unpublish <share-id | source> --json # --visibility disambiguates ``` @@ -591,10 +638,20 @@ feature id. "Sign in" card unless you pass `--link-preview full`, which serves bots a metadata-only stub built from those same three fields. It comes back as `data.share.link_preview`, and re-running flips it on an existing share - (a PATCH — no new share). Playback stays sign-in gated in every mode. + (a PATCH — no new share). Playback outside Slack stays sign-in gated in + every mode. ⚠️ Ask the user first: `full` makes the share's title, description, and thumbnail readable by anyone who fetches the link, and platforms cache per exact URL, so turning it back off does not retract already-posted cards. +- Playable Slack unfurls (0.3.20+, `publish.link.preview.player.v1`): + `--link-preview player` on a PRIVATE share lets the share itself play + inline when its link is pasted in a Slack workspace the account owner has + connected in the Cloudglue dashboard (implies the `full` card; elsewhere + the link falls back to the card). A PUBLIC share already unfurls playable + wherever the Cloudglue Slack app is installed — no flag needed. ⚠️ Anyone + who can see the Slack message can play the video — ask the user before + opting a private share in. Downgrading to `full`/`none` revokes playback in + already-posted unfurls. When generating custom site HTML around a `<cg-video>` embed, use the component's built-ins instead of reinventing them. It defaults to a diff --git a/skills/tinycloud/scripts/preflight.sh b/skills/tinycloud/scripts/preflight.sh index 65ae326..1f402d8 100755 --- a/skills/tinycloud/scripts/preflight.sh +++ b/skills/tinycloud/scripts/preflight.sh @@ -9,11 +9,11 @@ set -u # Mirror tinycloud-skill.json: min_version / supported_range upper bound # (CI diffs these against the manifest). -MIN_VERSION="0.3.18" +MIN_VERSION="0.3.20" MAX_VERSION_EXCLUSIVE="0.4.0" INSTALL_CMD='curl -fsSL https://app.cloudglue.dev/tinycloud.sh | bash' # Kept in sync with ../tinycloud-skill.json required_features (CI diffs them). -REQUIRED_FEATURES="envelope.v1 watch.v1 watch.speech.v1 see.v1 extract.v1 extract.images.v1 caption.v1 search.v1 probe.v1 probe.filters.v1 ask.v1 query.v1 query.export.v1 clip.v1 grab.v1 face.v1 jobs.v1 library.collections.v1 library.collections.create.v1 library.collections.mutate.v1 library.collections.entities.v1 library.collections.metadata.v1 library.collections.describe.v1 library.collections.pagination.v1 library.sync.url.v1 workflow.v1 publish.v1 publish.manage.v1 publish.video.v1 publish.link.preview.v1 setup.v1" +REQUIRED_FEATURES="envelope.v1 watch.v1 watch.speech.v1 see.v1 extract.v1 extract.images.v1 caption.v1 search.v1 probe.v1 probe.filters.v1 probe.entities.v1 probe.scope.auto.v1 ask.v1 query.v1 query.export.v1 clip.v1 grab.v1 face.v1 jobs.v1 library.collections.v1 library.collections.create.v1 library.collections.mutate.v1 library.collections.entities.v1 library.collections.metadata.v1 library.collections.describe.v1 library.collections.pagination.v1 library.sync.url.v1 workflow.v1 publish.v1 publish.manage.v1 publish.video.v1 publish.link.preview.v1 publish.link.preview.player.v1 setup.v1" # 1) Binary present and responsive? if ! command -v tinycloud >/dev/null 2>&1; then diff --git a/skills/tinycloud/tinycloud-skill.json b/skills/tinycloud/tinycloud-skill.json index dc24eec..8047bc9 100644 --- a/skills/tinycloud/tinycloud-skill.json +++ b/skills/tinycloud/tinycloud-skill.json @@ -1,8 +1,8 @@ { - "skill_version": "0.3.19", + "skill_version": "0.3.20", "tinycloud": { - "min_version": "0.3.18", - "supported_range": ">=0.3.18 <0.4.0", + "min_version": "0.3.20", + "supported_range": ">=0.3.20 <0.4.0", "required_features": [ "envelope.v1", "watch.v1", @@ -14,6 +14,8 @@ "search.v1", "probe.v1", "probe.filters.v1", + "probe.entities.v1", + "probe.scope.auto.v1", "ask.v1", "query.v1", "query.export.v1", @@ -34,6 +36,7 @@ "publish.manage.v1", "publish.video.v1", "publish.link.preview.v1", + "publish.link.preview.player.v1", "setup.v1" ], "envelope_schema": "1",