@officexapp/vidfarm-devcli 0.21.62 → 0.21.64
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/.agents/skills/dollarplatoon-skill/SKILL.md +163 -1174
- package/.agents/skills/dollarplatoon-skill/SOURCE.md +62 -0
- package/.agents/skills/dollarplatoon-skill/skill/clients.md +234 -0
- package/.agents/skills/dollarplatoon-skill/skill/feeds.md +326 -0
- package/.agents/skills/dollarplatoon-skill/skill/gigs.md +395 -0
- package/.agents/skills/dollarplatoon-skill/skill/gigworkers.md +324 -0
- package/.agents/skills/dollarplatoon-skill/skill/orders.md +573 -0
- package/.agents/skills/dollarplatoon-skill/skill/payouts.md +234 -0
- package/.agents/skills/dollarplatoon-skill/skill/platform.md +174 -0
- package/.agents/skills/dollarplatoon-skill/skill/prices.md +75 -0
- package/.agents/skills/dollarplatoon-skill/skill/pricing-and-tags.md +255 -0
- package/.agents/skills/dollarplatoon-skill/skill/proofs.md +555 -0
- package/.agents/skills/dollarplatoon-skill/skill/queue.md +404 -0
- package/.agents/skills/dollarplatoon-skill/skill/quickstart.md +191 -0
- package/.agents/skills/dollarplatoon-skill/skill/staging.md +178 -0
- package/.agents/skills/dollarplatoon-skill/skill/tasks.md +588 -0
- package/.agents/skills/dollarplatoon-skill/skill/web-pages.md +586 -0
- package/.agents/skills/vidfarm/SKILL.md +3 -3
- package/.agents/skills/vidfarm/references/core-workflows.md +107 -3
- package/SKILL.director.md +109 -5
- package/SKILL.md +3 -1
- package/clipper.md +20 -0
- package/dist/src/cli.js +50 -6
- package/dist/src/devcli/delivery-seal.js +119 -0
- package/dist/src/devcli/marketplace-console.js +1418 -0
- package/dist/src/devcli/marketplace-gigs.js +162 -16
- package/marketplace.md +299 -1
- package/package.json +24 -3
|
@@ -256,9 +256,74 @@ devcli: `vidfarm channels` lists destinations, `vidfarm schedule <postId> --at <
|
|
|
256
256
|
|
|
257
257
|
Deeper FlockPoster work (connecting accounts, channel management, direct posting/analytics outside vidfarm's schedule wrapper) is FlockPoster's own API, not vidfarm's — grab its skill first: `npx skills add https://github.com/OfficeXApp/flockposter-skill` (mirrored as `vidfarm skills add flockposter`).
|
|
258
258
|
|
|
259
|
-
##
|
|
260
|
-
|
|
261
|
-
|
|
259
|
+
## Pack marketplace — buy a pack, or sell one
|
|
260
|
+
|
|
261
|
+
**There are two marketplaces and they are not the same product.** This one is the **shelf**: a vendor
|
|
262
|
+
puts **pack cards** on `https://vidfarm.cc/marketplace` — one card is one offer, "7 videos, $35, 3-5
|
|
263
|
+
days" — and a buyer orders a **pack** from it. No brief bank, no bell, no swipe deck. The older gig
|
|
264
|
+
marketplace (briefs broadcast to a crowd) is the section after this one.
|
|
265
|
+
|
|
266
|
+
It was web-only until 2026-08-29. It is now REST, under `/api/v1/marketplace/`, and the devcli wraps
|
|
267
|
+
every route. Auth is the ordinary `vidfarm-api-key` header or a session; the whole surface is
|
|
268
|
+
paid-only and answers **402** to a free key.
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
GET /api/v1/marketplace/shelf PUBLIC — what is for sale
|
|
272
|
+
GET /api/v1/marketplace/shelf/:shop/:machine one card + examples + reviews
|
|
273
|
+
GET /api/v1/marketplace/shop your shop, cards, limits
|
|
274
|
+
POST /api/v1/marketplace/shop/profile create/edit the shop
|
|
275
|
+
POST /api/v1/marketplace/shop/machines create/edit a pack card
|
|
276
|
+
POST /api/v1/marketplace/shop/machines/:id/visibility on/off for buyers
|
|
277
|
+
GET /api/v1/marketplace/shop/orders the vendor queue
|
|
278
|
+
POST /api/v1/marketplace/shop/orders/:id/fulfil DELIVER — { items: [...] }
|
|
279
|
+
POST /api/v1/marketplace/purchases place an order
|
|
280
|
+
GET /api/v1/marketplace/purchases/:id one order + thread + files + `can`
|
|
281
|
+
POST /api/v1/marketplace/purchases/:id/accept pays, and is FINAL
|
|
282
|
+
POST /api/v1/marketplace/purchases/:id/request-changes free; nothing moves
|
|
283
|
+
GET /api/v1/marketplace/free-order-status/:shopSlug is MY first order here free?
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
devcli — **two verbs, and they do not overlap**: `vidfarm shop` is the vendor
|
|
287
|
+
(`shop orders`, `shop deliver <id> --item "<preview>::<master>::<note>"`, `shop earnings`,
|
|
288
|
+
`shop withdraw`), `vidfarm purchases` is the buyer (`purchases shelf`, `vidfarm buy
|
|
289
|
+
<shop>/<card> -y`, `purchases accept <id> -y`, `purchases changes <id> "<fix>"`). Full lists:
|
|
290
|
+
`vidfarm shop help`, `vidfarm purchases help`. Everything takes `--json`.
|
|
291
|
+
|
|
292
|
+
**An order ends three ways, and only one is reversible.** `accept` approves and settles in full and
|
|
293
|
+
is FINAL in both directions. `request-changes` is FREE and reaches nothing on chain — the deposit
|
|
294
|
+
stays in escrow and the vendor re-delivers. `refund` returns the escrow; whoever signs pays the gas.
|
|
295
|
+
Never route a fixable note through Dollar Platoon's reject — theirs is final and would kill a funded
|
|
296
|
+
order. **Clean masters are withheld until the payout is stamped**; everything before that is
|
|
297
|
+
watermarked, and the rule is applied server-side.
|
|
298
|
+
|
|
299
|
+
### First order free — the NEW SHOP flag
|
|
300
|
+
|
|
301
|
+
The platform can mark a shop so that **every buyer's FIRST order there is free** — one pack, $0,
|
|
302
|
+
one per SHOP rather than one per card. It is superagency-only
|
|
303
|
+
(`POST /api/v1/admin/shops/new-status`); a vendor can neither grant nor revoke it.
|
|
304
|
+
|
|
305
|
+
It changes three rules, and an agent that misses them will mislead its human:
|
|
306
|
+
|
|
307
|
+
- **No deposit and no escrow.** There is nothing to refund. A "refund" on a free order is a
|
|
308
|
+
**cancel** — it closes the order and returns nothing.
|
|
309
|
+
- **The buyer's approval is FINAL and releases the files by itself.** On the paid rail the PAYOUT
|
|
310
|
+
unlocks the masters; on the free rail the APPROVAL does, because there is no payout after it. So
|
|
311
|
+
accepting is the entire transaction and there is no undo behind it.
|
|
312
|
+
- **A spent free order does not come back.** Cancelling one does not restore the entitlement.
|
|
313
|
+
|
|
314
|
+
**Read `is_free` on the order — NEVER `total_usd === 0`.** A zero total reached any other way still
|
|
315
|
+
has escrow semantics, and treating it as free skips the payout. Underneath, a free order runs on a
|
|
316
|
+
**separate Dollar Platoon gig** (`dp_free_gig_id`): their API locks a gig's price mode at creation,
|
|
317
|
+
so one gig cannot sell both.
|
|
318
|
+
|
|
319
|
+
`GET …/shelf` is shared-cached and therefore only ever carries the **offer** (`shop.new_shop`).
|
|
320
|
+
Whether *this* buyer still has theirs is per-account and lives on its own `no-store` route. It is
|
|
321
|
+
**advisory**: price at the paid number and lower it on a yes, never the other way round.
|
|
322
|
+
`vidfarm purchases pack <shop>/<card>` does exactly that and prints the terms.
|
|
323
|
+
|
|
324
|
+
## Older gig marketplace — broadcast a brief to a crowd
|
|
325
|
+
|
|
326
|
+
Web-only. NEVER render or reimplement it locally (not in the terminal, not on a serve box) — send the human to **https://vidfarm.cc/marketplace** (featured agents), `/marketplace/browse` (portfolios by category tag), `/marketplace/manage` (their orders). `vidfarm marketplace` prints exactly those links.
|
|
262
327
|
|
|
263
328
|
An **order IS a Dollar Platoon gig** (tagged `vidfarm_order_<uuidv7>` plus category tags). Vidfarm exposes a deliberately thin REST wrapper — auth via session or the `vidfarm-api-key` header:
|
|
264
329
|
|
|
@@ -279,6 +344,45 @@ POST /api/v1/marketplace/orders/:gigId/invite { "slug": "<agent portfolio slug
|
|
|
279
344
|
|
|
280
345
|
devcli: `vidfarm marketplace` (browse links), `vidfarm marketplace orders`, `vidfarm marketplace order --title <t> --brief <b> [--count <n>] [--price <usd>] [--rate-limit-per-day <n>] [--tags a,b] [--folder <path>]` (defaults: 10 videos, $0.50, 2/day per worker), `vidfarm marketplace invite <gigId> --portfolio <slug>`.
|
|
281
346
|
|
|
347
|
+
## Notifications — one list for both sides of the marketplace
|
|
348
|
+
|
|
349
|
+
Everything that happens on an order lands on **https://vidfarm.cc/notifications**, buyer side and vendor side in the same list. The bell that opens it sits on `/marketplace`, `/marketplace/shop` and `/shop/:slug`; the gold **Marketplace** / **Vendor** button in the sidebar wears a green dot while anything is unseen.
|
|
350
|
+
|
|
351
|
+
| you are | you are told about |
|
|
352
|
+
|---|---|
|
|
353
|
+
| **vendor** | a new order · a new review · a payout · the buyer asked for changes · a new comment · the buyer withdrew · a wallet withdrawal |
|
|
354
|
+
| **buyer** | your order was fulfilled · a new comment · the vendor refunded and closed it |
|
|
355
|
+
|
|
356
|
+
**Three words that look alike and are not.** On the vendor's list *"Order rejected"* means the BUYER asked for **changes** — nothing reached Dollar Platoon and the deposit is still in escrow, so the right move is to re-upload, not to argue. *"Order withdrawn"* means the buyer refunded and the order is dead. On the BUYER's list *"Order rejected"* means the **vendor** refunded and closed it. See `https://vidfarm.cc/marketplace.md`.
|
|
357
|
+
|
|
358
|
+
Web-only, and **not paid-gated** — a free account can fulfil work, so it can be owed a payout. Everything on the page is a form post and works with JavaScript off:
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
GET /notifications?q=<search>&filter=all|unseen&page=<n> the list, newest first
|
|
362
|
+
POST /notifications/:notificationId/seen form: seen=1|0, q, filter, page
|
|
363
|
+
POST /notifications/mark-all-seen form: q, filter
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
A row carries **two separate controls**: *Mark seen / Mark unseen*, and *Open ↗* — a plain link that opens the order in a new tab. Clicking the row itself does nothing, on purpose.
|
|
367
|
+
|
|
368
|
+
The unseen count is **not** in the page HTML — `/marketplace` is shared-cached for anonymous visitors, so a count baked in would be one buyer's badge served to a stranger. It rides the session's own access probe instead, which an agent can read directly:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
curl -s -b cookies.txt "https://vidfarm.cc/api/v1/user/me/marketplace-access"
|
|
372
|
+
# { "ok": true, "marketplace": true, "vendor": true, "shop_slug": "acme", "notifications_unseen": 3 }
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Marketplace email — two messages, one switch
|
|
376
|
+
|
|
377
|
+
`marketplace@vidfarm.cc` sends exactly two things, and nothing else ever comes from that address:
|
|
378
|
+
|
|
379
|
+
| to | when |
|
|
380
|
+
|---|---|
|
|
381
|
+
| the **vendor** | a buyer placed an order in their shop |
|
|
382
|
+
| the **buyer** | a vendor delivered the pack — it is ready to tear |
|
|
383
|
+
|
|
384
|
+
**Default ON**, by absence of a preference rather than by a backfill. The switch is **Settings → Marketplace → Marketplace email** (`POST /settings/marketplace/email-prefs`). Turning it off changes nothing about how orders work; the same events are still on `/notifications`. Never tell a user to disable it as a fix for something else — those two mails are how the other party learns money moved.
|
|
385
|
+
|
|
282
386
|
## Your Dollar Platoon key, from the vidfarm REST API
|
|
283
387
|
|
|
284
388
|
Every paid vidfarm account owns a Dollar Platoon account, and **one route hands the agent that credential** — so an agent holding only a `vidfarm-api-key` can drive the whole gig side without the human copying anything out of Settings.
|
package/SKILL.director.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vidfarm
|
|
3
|
-
skill_version: 0.21.
|
|
3
|
+
skill_version: 0.21.64
|
|
4
4
|
description: Use Vidfarm as a director. Run a strategy **consultation** (the `brainstorm/*` chain — cold-start interview, awareness stages, persuasive angles, hooks, product placement). Answer "give me content ideas" / "what should I post" / "I need 30 videos this month" from the bundled idea banks (50 content frames x 5 awareness stages x 44 problem angles). Browse/add inspiration videos, browse the free public raws catalog BY CATEGORY (curated shelves like scroll-stoppers/greenscreen/reaction — the cheapest way to source footage for one video, and a ready-made clip pool for bulk scripting N variants), fork a template into a composition, edit it in the Trackpad Editor (timeline-based like Premiere/DaVinci), auto-decompose source video into scenes, render to MP4, approve into a shareable post, and schedule it. Includes login, provider keys, discovery, versioning, uploads/downloads, and billing. Every step is available as raw REST; `vidfarm-devcli` wraps those routes and composes the file-backed scripting flows.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -478,7 +478,7 @@ You may be running as the **in-web AI chat** (the /editor copilot, the chat dock
|
|
|
478
478
|
|
|
479
479
|
| File | Size | Read it when |
|
|
480
480
|
|---|---|---|
|
|
481
|
-
| `references/core-workflows.md` | ~
|
|
481
|
+
| `references/core-workflows.md` | ~530 ln | Template discovery, auth, fork → render → approve → share, versioning, cost/wallet, marketplace orders, notifications + marketplace email, the customer's Dollar Platoon key + the four gig quick tasks, dedupe-before-publish |
|
|
482
482
|
| `references/editor-workflows.md` | ~650 ln | **The biggest read.** Timeline editing, decompose, captions, transitions, motion, AI placement, the caption standard, the editor action verbs |
|
|
483
483
|
| `references/assets-and-sourcing.md` | ~390 ln | **Google search for footage** (the query playbook), raws hunts, clip scanning, My Files, **uploading (presign → PUT → finalize)**, recurring characters, downloading media off a URL, social recycle |
|
|
484
484
|
| `references/agent-included-imagegen.md` | ~70 ln | **Free custom art without spending.** Image generation the AGENT's own subscription already includes (Antigravity / Gemini CLI, Codex / ChatGPT — Claude Code has none): why it is allowed in cost mode `minimize`, `vidfarm agent-image --check` / the brief command, where it sits on the asset ladder, and the honest limits |
|
|
@@ -572,7 +572,7 @@ The File Index above says what each file *is*; this says which one a given ask m
|
|
|
572
572
|
5b. If the task is an **explainer built from cutout/sticker art** — flat illustrations on a stage, a sticker sheet, keyed art, “make it look like those animated explainer videos” — read `recipes/cutout-graphics-for-explainers.md`. It carries the house style, the sheet→sticker pipeline, and the dark-stage rules that are easy to get wrong.
|
|
573
573
|
5c. If the task is **introducing a product a stranger has never heard of** — a client's URL turned into a 20–30s "what is this?" video, a launch/brand-intro clip, or a batch of N customer URLs → N videos that must not look alike — read `harnesses/product-explainer.HARNESS.md`. It is the format with the single most expensive defect in the catalog (the product never plainly named in the first 5s, which costs a VO re-record to fix), plus the simple-open text-run count, the sticker dosage, and the anti-convergence assignment method. Use `product-demo` instead when you actually have the UI on screen.
|
|
574
574
|
6. If the task explicitly asks for a primitive or needs specialized generation/transcription work, read `references/primitives.md`.
|
|
575
|
-
7. If the task is the MARKETPLACE (ordering videos from specialist agents, or running your own two vending machines): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. **`GET /api/v1/user/me/marketplace` hands you the customer's own Dollar Platoon API key** (paid plans only), so an agent with a `vidfarm-api-key` needs nothing copied out of Settings. Orders plus the four quick tasks — check a machine for new proofs, approve/reject one, add a task, ring the bell on the feed — are worked examples in `references/core-workflows.md` (§ Marketplace, § Your Dollar Platoon key). **When you ring the bell, the notification MUST point at the machine's reusable INVITE link (`…/gig/<id>/join?invite=<token>`)** — that is what a gigworker taps to join and pitch. The gig record's own `invite_url` is tokenless and refuses the join, so never publish it; `POST /api/v1/marketplace/buyer/ring-bell` resolves the right link for you and returns it as `destinationUrl`. Everything deeper on a gig (mailboxes, the queue, per-task pricing, payouts, wallets, reputation) is Dollar Platoon's own API: **read `https://dollarplatoon.com/skill.md`**, its accurate live index, or install it with `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`. Dollar Platoon authenticates on `x-api-key` ONLY; a Bearer token 401s as "Missing x-api-key header" before the key is read. **On the earning side, never submit a proof without the sanity check first:** `vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4` needs no key, loads every proof url the way a stranger's browser would, and exits non-zero on a dead link, a 403 bucket, an error page served as `video/mp4`, or an **expiring presigned url** — then checks the watermarked cut is the public half and the clean master the sealed one. `vidfarm gigs submit` runs it too and refuses a failing proof. **A submitted proof is not one-way:** `vidfarm gigs withdraw <gig> <proof>` pulls a still-`pending` proof back to a private draft (stopping the review clock and hiding it from the buyer) and `gigs send` re-sends it with a fresh window — but withdrawal is closed the moment the buyer approves or rejects, so it is a repair for a bad link or a missing `private_note`, never a substitute for reviewing the cut first. `gigs draft` / `drafts` / `edit-draft` / `discard` work the same lifecycle from the other end. The whole earning loop is `https://vidfarm.cc/agentic-clipper.md`.
|
|
575
|
+
7. If the task is the MARKETPLACE (ordering videos from specialist agents, or running your own two vending machines): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. **`GET /api/v1/user/me/marketplace` hands you the customer's own Dollar Platoon API key** (paid plans only), so an agent with a `vidfarm-api-key` needs nothing copied out of Settings. Orders plus the four quick tasks — check a machine for new proofs, approve/reject one, add a task, ring the bell on the feed — are worked examples in `references/core-workflows.md` (§ Marketplace, § Your Dollar Platoon key). **When you ring the bell, the notification MUST point at the machine's reusable INVITE link (`…/gig/<id>/join?invite=<token>`)** — that is what a gigworker taps to join and pitch. The gig record's own `invite_url` is tokenless and refuses the join, so never publish it; `POST /api/v1/marketplace/buyer/ring-bell` resolves the right link for you and returns it as `destinationUrl`. Everything deeper on a gig (mailboxes, the queue, per-task pricing, payouts, wallets, reputation) is Dollar Platoon's own API: **read `https://dollarplatoon.com/skill.md`**, its accurate live index, or install it with `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`. Dollar Platoon authenticates on `x-api-key` ONLY; a Bearer token 401s as "Missing x-api-key header" before the key is read. **On the earning side, never submit a proof without the sanity check first:** `vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4` needs no key, loads every proof url the way a stranger's browser would, and exits non-zero on a dead link, a 403 bucket, an error page served as `video/mp4`, or an **expiring presigned url** — then checks the watermarked cut is the public half and the clean master the sealed one. `vidfarm gigs submit` runs it too and refuses a failing proof. **A submitted proof is not one-way:** `vidfarm gigs withdraw <gig> <proof>` pulls a still-`pending` proof back to a private draft (stopping the review clock and hiding it from the buyer) and `gigs send` re-sends it with a fresh window — but withdrawal is closed the moment the buyer approves or rejects, so it is a repair for a bad link or a missing `private_note`, never a substitute for reviewing the cut first. `gigs draft` / `drafts` / `edit-draft` / `discard` work the same lifecycle from the other end. **A clipper IS a vendor once they open a shop on /marketplace, and a vidfarm ORDER needs a shaped note:** vidfarm parses the whole `private_note` as JSON to build the buyer's pack, so never hand-roll it and never wrap it in prose — `vidfarm gigs submit … --project <composition folder url> --preview-note "<what the watermarked cut is>" --private-note "<your notes>"` seals it, and `vidfarm gigs seal` (no key) prints it without sending. That sends four separate things: the watermarked preview in `proofs[]`, the clean HD master sealed until `paid_out_at`, the `composition.html`/`composition.json` folder so the buyer can FORK the build, and your notes. The `/delivery/<id>` url is minted by vidfarm when a shop fulfils at `/marketplace/shop/orders` (which submits the sealed proof for you) — never invent one. The whole earning loop is `https://vidfarm.cc/agentic-clipper.md`, and the delivery schema is `https://vidfarm.cc/marketplace.md` → *delivering to a vidfarm order*. **Both sides share one inbox — `https://vidfarm.cc/notifications`** (bell on `/marketplace` and `/marketplace/shop`, green dot on the gold sidebar button, `notifications_unseen` on `GET /api/v1/user/me/marketplace-access`): vendors get new order / review / payout / change request / comment / withdrawal / wallet send, buyers get fulfilled / comment / refund. **`marketplace@vidfarm.cc` emails exactly two of them** — the vendor on a new order, the buyer when the pack is ready to tear — default ON and switchable at Settings → Marketplace; never suggest turning it off, because those two mails are how the other party learns money moved. **A shop's orders do NOT arrive through the feed sweep** — walk `/marketplace/shop/orders`. And read the words: on a VENDOR's list *"Order rejected"* means the buyer asked for **changes** and the deposit is still in escrow (re-upload), while *"Order withdrawn"* means they refunded and the order is dead. Full section: `https://vidfarm.cc/marketplace.md` → *How you get told*, and `references/core-workflows.md` § Notifications.
|
|
576
576
|
|
|
577
577
|
## Non-Negotiables
|
|
578
578
|
|
|
@@ -854,9 +854,74 @@ devcli: `vidfarm channels` lists destinations, `vidfarm schedule <postId> --at <
|
|
|
854
854
|
|
|
855
855
|
Deeper FlockPoster work (connecting accounts, channel management, direct posting/analytics outside vidfarm's schedule wrapper) is FlockPoster's own API, not vidfarm's — grab its skill first: `npx skills add https://github.com/OfficeXApp/flockposter-skill` (mirrored as `vidfarm skills add flockposter`).
|
|
856
856
|
|
|
857
|
-
##
|
|
857
|
+
## Pack marketplace — buy a pack, or sell one
|
|
858
858
|
|
|
859
|
-
|
|
859
|
+
**There are two marketplaces and they are not the same product.** This one is the **shelf**: a vendor
|
|
860
|
+
puts **pack cards** on `https://vidfarm.cc/marketplace` — one card is one offer, "7 videos, $35, 3-5
|
|
861
|
+
days" — and a buyer orders a **pack** from it. No brief bank, no bell, no swipe deck. The older gig
|
|
862
|
+
marketplace (briefs broadcast to a crowd) is the section after this one.
|
|
863
|
+
|
|
864
|
+
It was web-only until 2026-08-29. It is now REST, under `/api/v1/marketplace/`, and the devcli wraps
|
|
865
|
+
every route. Auth is the ordinary `vidfarm-api-key` header or a session; the whole surface is
|
|
866
|
+
paid-only and answers **402** to a free key.
|
|
867
|
+
|
|
868
|
+
```
|
|
869
|
+
GET /api/v1/marketplace/shelf PUBLIC — what is for sale
|
|
870
|
+
GET /api/v1/marketplace/shelf/:shop/:machine one card + examples + reviews
|
|
871
|
+
GET /api/v1/marketplace/shop your shop, cards, limits
|
|
872
|
+
POST /api/v1/marketplace/shop/profile create/edit the shop
|
|
873
|
+
POST /api/v1/marketplace/shop/machines create/edit a pack card
|
|
874
|
+
POST /api/v1/marketplace/shop/machines/:id/visibility on/off for buyers
|
|
875
|
+
GET /api/v1/marketplace/shop/orders the vendor queue
|
|
876
|
+
POST /api/v1/marketplace/shop/orders/:id/fulfil DELIVER — { items: [...] }
|
|
877
|
+
POST /api/v1/marketplace/purchases place an order
|
|
878
|
+
GET /api/v1/marketplace/purchases/:id one order + thread + files + `can`
|
|
879
|
+
POST /api/v1/marketplace/purchases/:id/accept pays, and is FINAL
|
|
880
|
+
POST /api/v1/marketplace/purchases/:id/request-changes free; nothing moves
|
|
881
|
+
GET /api/v1/marketplace/free-order-status/:shopSlug is MY first order here free?
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
devcli — **two verbs, and they do not overlap**: `vidfarm shop` is the vendor
|
|
885
|
+
(`shop orders`, `shop deliver <id> --item "<preview>::<master>::<note>"`, `shop earnings`,
|
|
886
|
+
`shop withdraw`), `vidfarm purchases` is the buyer (`purchases shelf`, `vidfarm buy
|
|
887
|
+
<shop>/<card> -y`, `purchases accept <id> -y`, `purchases changes <id> "<fix>"`). Full lists:
|
|
888
|
+
`vidfarm shop help`, `vidfarm purchases help`. Everything takes `--json`.
|
|
889
|
+
|
|
890
|
+
**An order ends three ways, and only one is reversible.** `accept` approves and settles in full and
|
|
891
|
+
is FINAL in both directions. `request-changes` is FREE and reaches nothing on chain — the deposit
|
|
892
|
+
stays in escrow and the vendor re-delivers. `refund` returns the escrow; whoever signs pays the gas.
|
|
893
|
+
Never route a fixable note through Dollar Platoon's reject — theirs is final and would kill a funded
|
|
894
|
+
order. **Clean masters are withheld until the payout is stamped**; everything before that is
|
|
895
|
+
watermarked, and the rule is applied server-side.
|
|
896
|
+
|
|
897
|
+
### First order free — the NEW SHOP flag
|
|
898
|
+
|
|
899
|
+
The platform can mark a shop so that **every buyer's FIRST order there is free** — one pack, $0,
|
|
900
|
+
one per SHOP rather than one per card. It is superagency-only
|
|
901
|
+
(`POST /api/v1/admin/shops/new-status`); a vendor can neither grant nor revoke it.
|
|
902
|
+
|
|
903
|
+
It changes three rules, and an agent that misses them will mislead its human:
|
|
904
|
+
|
|
905
|
+
- **No deposit and no escrow.** There is nothing to refund. A "refund" on a free order is a
|
|
906
|
+
**cancel** — it closes the order and returns nothing.
|
|
907
|
+
- **The buyer's approval is FINAL and releases the files by itself.** On the paid rail the PAYOUT
|
|
908
|
+
unlocks the masters; on the free rail the APPROVAL does, because there is no payout after it. So
|
|
909
|
+
accepting is the entire transaction and there is no undo behind it.
|
|
910
|
+
- **A spent free order does not come back.** Cancelling one does not restore the entitlement.
|
|
911
|
+
|
|
912
|
+
**Read `is_free` on the order — NEVER `total_usd === 0`.** A zero total reached any other way still
|
|
913
|
+
has escrow semantics, and treating it as free skips the payout. Underneath, a free order runs on a
|
|
914
|
+
**separate Dollar Platoon gig** (`dp_free_gig_id`): their API locks a gig's price mode at creation,
|
|
915
|
+
so one gig cannot sell both.
|
|
916
|
+
|
|
917
|
+
`GET …/shelf` is shared-cached and therefore only ever carries the **offer** (`shop.new_shop`).
|
|
918
|
+
Whether *this* buyer still has theirs is per-account and lives on its own `no-store` route. It is
|
|
919
|
+
**advisory**: price at the paid number and lower it on a yes, never the other way round.
|
|
920
|
+
`vidfarm purchases pack <shop>/<card>` does exactly that and prints the terms.
|
|
921
|
+
|
|
922
|
+
## Older gig marketplace — broadcast a brief to a crowd
|
|
923
|
+
|
|
924
|
+
Web-only. NEVER render or reimplement it locally (not in the terminal, not on a serve box) — send the human to **https://vidfarm.cc/marketplace** (featured agents), `/marketplace/browse` (portfolios by category tag), `/marketplace/manage` (their orders). `vidfarm marketplace` prints exactly those links.
|
|
860
925
|
|
|
861
926
|
An **order IS a Dollar Platoon gig** (tagged `vidfarm_order_<uuidv7>` plus category tags). Vidfarm exposes a deliberately thin REST wrapper — auth via session or the `vidfarm-api-key` header:
|
|
862
927
|
|
|
@@ -877,6 +942,45 @@ POST /api/v1/marketplace/orders/:gigId/invite { "slug": "<agent portfolio slug
|
|
|
877
942
|
|
|
878
943
|
devcli: `vidfarm marketplace` (browse links), `vidfarm marketplace orders`, `vidfarm marketplace order --title <t> --brief <b> [--count <n>] [--price <usd>] [--rate-limit-per-day <n>] [--tags a,b] [--folder <path>]` (defaults: 10 videos, $0.50, 2/day per worker), `vidfarm marketplace invite <gigId> --portfolio <slug>`.
|
|
879
944
|
|
|
945
|
+
## Notifications — one list for both sides of the marketplace
|
|
946
|
+
|
|
947
|
+
Everything that happens on an order lands on **https://vidfarm.cc/notifications**, buyer side and vendor side in the same list. The bell that opens it sits on `/marketplace`, `/marketplace/shop` and `/shop/:slug`; the gold **Marketplace** / **Vendor** button in the sidebar wears a green dot while anything is unseen.
|
|
948
|
+
|
|
949
|
+
| you are | you are told about |
|
|
950
|
+
|---|---|
|
|
951
|
+
| **vendor** | a new order · a new review · a payout · the buyer asked for changes · a new comment · the buyer withdrew · a wallet withdrawal |
|
|
952
|
+
| **buyer** | your order was fulfilled · a new comment · the vendor refunded and closed it |
|
|
953
|
+
|
|
954
|
+
**Three words that look alike and are not.** On the vendor's list *"Order rejected"* means the BUYER asked for **changes** — nothing reached Dollar Platoon and the deposit is still in escrow, so the right move is to re-upload, not to argue. *"Order withdrawn"* means the buyer refunded and the order is dead. On the BUYER's list *"Order rejected"* means the **vendor** refunded and closed it. See `https://vidfarm.cc/marketplace.md`.
|
|
955
|
+
|
|
956
|
+
Web-only, and **not paid-gated** — a free account can fulfil work, so it can be owed a payout. Everything on the page is a form post and works with JavaScript off:
|
|
957
|
+
|
|
958
|
+
```
|
|
959
|
+
GET /notifications?q=<search>&filter=all|unseen&page=<n> the list, newest first
|
|
960
|
+
POST /notifications/:notificationId/seen form: seen=1|0, q, filter, page
|
|
961
|
+
POST /notifications/mark-all-seen form: q, filter
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
A row carries **two separate controls**: *Mark seen / Mark unseen*, and *Open ↗* — a plain link that opens the order in a new tab. Clicking the row itself does nothing, on purpose.
|
|
965
|
+
|
|
966
|
+
The unseen count is **not** in the page HTML — `/marketplace` is shared-cached for anonymous visitors, so a count baked in would be one buyer's badge served to a stranger. It rides the session's own access probe instead, which an agent can read directly:
|
|
967
|
+
|
|
968
|
+
```bash
|
|
969
|
+
curl -s -b cookies.txt "https://vidfarm.cc/api/v1/user/me/marketplace-access"
|
|
970
|
+
# { "ok": true, "marketplace": true, "vendor": true, "shop_slug": "acme", "notifications_unseen": 3 }
|
|
971
|
+
```
|
|
972
|
+
|
|
973
|
+
### Marketplace email — two messages, one switch
|
|
974
|
+
|
|
975
|
+
`marketplace@vidfarm.cc` sends exactly two things, and nothing else ever comes from that address:
|
|
976
|
+
|
|
977
|
+
| to | when |
|
|
978
|
+
|---|---|
|
|
979
|
+
| the **vendor** | a buyer placed an order in their shop |
|
|
980
|
+
| the **buyer** | a vendor delivered the pack — it is ready to tear |
|
|
981
|
+
|
|
982
|
+
**Default ON**, by absence of a preference rather than by a backfill. The switch is **Settings → Marketplace → Marketplace email** (`POST /settings/marketplace/email-prefs`). Turning it off changes nothing about how orders work; the same events are still on `/notifications`. Never tell a user to disable it as a fix for something else — those two mails are how the other party learns money moved.
|
|
983
|
+
|
|
880
984
|
## Your Dollar Platoon key, from the vidfarm REST API
|
|
881
985
|
|
|
882
986
|
Every paid vidfarm account owns a Dollar Platoon account, and **one route hands the agent that credential** — so an agent holding only a `vidfarm-api-key` can drive the whole gig side without the human copying anything out of Settings.
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vidfarm
|
|
3
|
-
skill_version: 0.21.
|
|
3
|
+
skill_version: 0.21.64
|
|
4
4
|
description: Entry point for making, editing, and rendering short-form video with Vidfarm. Use when the task is to create a video, ad, explainer, or social clip; to edit or re-theme an existing composition; to source footage or audio; or to run a batch of video variants. Routes to the full director skill and the `vidfarm` CLI.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -278,6 +278,8 @@ Also served at `vidfarm.cc`: `/flash-harness.md` (**the weak-model process harne
|
|
|
278
278
|
|
|
279
279
|
**Then ask the gigworker one more question: the RUN MODE.** It decides which stages of every task stop for them — `full-interactive` (shortlist · plan · raws · cut), `quick-interactive` (shortlist · cut), `auto-batch` (cut only — build the batch unattended, review it in one sitting), `auto-submit` (nothing; opt-in, in their own words). The middle two are the common ones. `vidfarm clipper-run mode` explains all four and saves the answer, `vidfarm clipper-run next` says what to do right now, and `vidfarm clipper-run gate <task>` exits non-zero while a human gate is open — so `gate && gigs submit …` cannot send an unreviewed cut. Full section: `/marketplace.md` → *The four run modes*.
|
|
280
280
|
|
|
281
|
+
**Both sides share one inbox: `https://vidfarm.cc/notifications`.** Buyer rows and vendor rows in one list, because one person is a buyer on one order and a vendor on the next. The bell is on `/marketplace` and `/marketplace/shop`; the gold sidebar button wears a green dot while anything is unseen; `GET /api/v1/user/me/marketplace-access` returns `notifications_unseen` for an agent that wants the number. Vendors are told about a new order, a review, a payout, a change request, a comment, a withdrawal and a wallet send; buyers about a fulfilment, a comment and a refund. **`marketplace@vidfarm.cc` emails exactly two of those** — the vendor when an order is placed, the buyer when the pack is ready to tear — default ON, switchable at **Settings → Marketplace**, and never a thing to suggest turning off. **One trap: on a VENDOR's list "Order rejected" means the buyer asked for CHANGES — the deposit is still in escrow and the fix is to re-upload.** "Order withdrawn" is the dead one. Full section: `/marketplace.md` → *How you get told*.
|
|
282
|
+
|
|
281
283
|
**Then offer the CLIPPER DASHBOARD — `vidfarm dashboard` — and expect a yes.** Three of the four run modes stop to make a human *watch a video*, and a terminal cannot play one; without the dashboard the gigworker reads a path out of `REVIEW_QUEUE.md`, opens the file by hand, and types a verb, once per task. `vidfarm dashboard` is that queue as one localhost page over the same `CLIPPER/` folder — no key, no network, no account: the cut plays and seeks, the buyer's brief sits beside it, the checks are tickable and the unticked ones pre-fill the rejection note, the shortlist candidates play side by side (`1`/`2`/`3` to pick), and `A`/`C`/`D`/`U` answer the gate. Every button calls the same `clipper-run` transition the CLI calls, so the page and the terminal can never disagree. Ask once, record it in `MISSION.md` as `dashboard: yes | no`, and never depend on it — a gigworker who declines keeps `REVIEW_QUEUE.md`, `clipper-run review` and the `gate` rail exactly as they were. Full section: `/agentic-clipper.md` § 3⅘.
|
|
282
284
|
|
|
283
285
|
**Before ANY proof is submitted, run the sanity check — every time, on every side of the loop.** `vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4` needs no api key. It loads each proof url the way a stranger's browser would (no key, no cookie) and exits non-zero on a 403 bucket, a 404, an s3 AccessDenied body served as `video/mp4`, an **expiring presigned url** (read access dies before the buyer swipes), a `localhost`/Drive/Dropbox link, or a 0-byte file. It then checks the delivery is split the right way: the **watermarked** cut public in `proofs[]`, the **clean master** sealed in `private_note` (`--clean-master`) — recommended, not required, so putting the unwatermarked final in the proof itself only warns, and `--clean-in-proof` says you meant it. `vidfarm gigs submit` runs the same check and refuses a failing proof. The two gates are different questions: `clipper-run gate` = *did a human watch it*, `gigs verify-proof` = *can the buyer open it*. Full section: `/marketplace.md` → *the sanity check before you send*.
|
package/clipper.md
CHANGED
|
@@ -395,6 +395,26 @@ await submitProof(gigId, {
|
|
|
395
395
|
});
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
+
**If the gig is a vidfarm ORDER, one more field, and it has a required shape.** A vendor —
|
|
399
|
+
"clipper" and "vendor" are the same person here — who runs a **vending machine shop** on
|
|
400
|
+
`https://vidfarm.cc/marketplace` sells packs, and the buyer opens the delivery as a pack on
|
|
401
|
+
vidfarm. That pack is built from `private_note`, which vidfarm parses as **JSON, whole**. Do not
|
|
402
|
+
write it by hand and do not wrap it in a sentence — build it:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
vidfarm gigs submit $GIG --task $TASK \
|
|
406
|
+
--proof "$SHARE_URL" --clean-master ./videos/<task-id>-clean.mp4 \
|
|
407
|
+
--project "https://vidfarm.cc/directory/preview/dsh_…/files/<slug>" \
|
|
408
|
+
--preview-note "watermarked, 1080x1920, 27s" \
|
|
409
|
+
--private-note "What I changed, and what I would try next."
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
That sends four separate things: the **watermarked** cut in `proofs` for them to judge, the
|
|
413
|
+
**clean HD master** sealed until the payout, the **`composition.html` / `composition.json` folder**
|
|
414
|
+
so they can fork and re-edit it themselves, and **your notes**. `vidfarm gigs seal` prints the note
|
|
415
|
+
without sending it. The full shape is in `https://vidfarm.cc/marketplace.md` → *delivering to a
|
|
416
|
+
vidfarm order*.
|
|
417
|
+
|
|
398
418
|
Check the response:
|
|
399
419
|
|
|
400
420
|
- **`warning: "available funds are less than the task price"`** — the proof was accepted but
|
package/dist/src/cli.js
CHANGED
|
@@ -1136,7 +1136,28 @@ Files (multi-step flows the devcli handles for you):
|
|
|
1136
1136
|
--job <jobId> Price ONE render/video (sums its charges → "this video cost $X")
|
|
1137
1137
|
--tracer <tracer> Price everything tagged with a tracer; --limit <n> recent events
|
|
1138
1138
|
|
|
1139
|
-
|
|
1139
|
+
The pack marketplace (paid, cloud-only) — SHOPS, PACK CARDS AND ORDERS:
|
|
1140
|
+
A vendor puts PACK CARDS on the shelf ("7 videos, $35, 3-5 days"). A buyer
|
|
1141
|
+
orders a pack, the USDC sits in escrow, the vendor delivers, the buyer rules
|
|
1142
|
+
on it. Accepting is what pays. One person is usually both, so there are two
|
|
1143
|
+
verbs and one key.
|
|
1144
|
+
|
|
1145
|
+
shop Your storefront: cards, orders, deliveries, money
|
|
1146
|
+
shop open --name "…" Create/edit the shop · shop cards · shop orders
|
|
1147
|
+
shop new-card --title "…" --lot-size 7 --price 35 --live
|
|
1148
|
+
shop deliver <orderId> --item "<preview>::<master>::<note>" ← hand the pack over
|
|
1149
|
+
shop refund <orderId> · shop reviews · shop earnings · shop withdraw
|
|
1150
|
+
(full list: vidfarm shop help)
|
|
1151
|
+
purchases What you bought, and every move left on it
|
|
1152
|
+
purchases shelf What is for sale · purchases pack <shop>/<cardId>
|
|
1153
|
+
buy <shop>/<cardId> --packs 1 --answer <id>=<url> -y ← place the order
|
|
1154
|
+
purchases open <orderId> · purchases rate <orderId> <itemId> keep|pass
|
|
1155
|
+
purchases accept <orderId> -y pays in full, FINAL
|
|
1156
|
+
purchases changes <orderId> "<what to fix>" free — nothing moves
|
|
1157
|
+
purchases refund <orderId> [--ask] · purchases review <orderId> …
|
|
1158
|
+
(full list: vidfarm purchases help)
|
|
1159
|
+
|
|
1160
|
+
The older gig marketplace (Dollar Platoon briefs, not pack cards):
|
|
1140
1161
|
marketplace Browse = the web. Prints vidfarm.cc/marketplace (paid customers)
|
|
1141
1162
|
marketplace orders List YOUR orders (each is a Dollar Platoon gig) → GET /api/v1/marketplace/orders
|
|
1142
1163
|
marketplace order Place an order (thin wrapper around a DP gig) → POST /api/v1/marketplace/orders
|
|
@@ -1145,7 +1166,7 @@ Marketplace (paid, cloud-only — the bazaar never renders locally):
|
|
|
1145
1166
|
--rate-limit-per-day <n> per-gigworker daily cap (default 2, 0 = none);
|
|
1146
1167
|
--tags <a,b> category tags; --folder <path> share a My Files folder
|
|
1147
1168
|
marketplace invite <gig> Email-invite an agent portfolio to an order → POST /api/v1/marketplace/orders/:id/invite
|
|
1148
|
-
--portfolio <slug> The agent portfolio slug (from /marketplace/browse)
|
|
1169
|
+
--portfolio <slug> The agent portfolio slug (from /marketplace-old/browse)
|
|
1149
1170
|
Gig inbox / proofs / payouts are Dollar Platoon's own API —
|
|
1150
1171
|
grab the skill: npx skills add https://github.com/OfficeXApp/dollarplatoon-skill
|
|
1151
1172
|
files List My Files assets + folders → GET /api/v1/user/me/attachments
|
|
@@ -1703,6 +1724,25 @@ async function main() {
|
|
|
1703
1724
|
case "market":
|
|
1704
1725
|
await runMarketplaceCommand(rest);
|
|
1705
1726
|
return;
|
|
1727
|
+
// THE PACK MARKETPLACE — shops, pack cards and orders on vidfarm.cc.
|
|
1728
|
+
// `marketplace` above is the OLDER gig surface and stays where it is; these
|
|
1729
|
+
// two are the storefront that replaced it, one verb per side.
|
|
1730
|
+
case "shop":
|
|
1731
|
+
case "vendor":
|
|
1732
|
+
case "storefront": {
|
|
1733
|
+
const { runShopCommand } = await import("./devcli/marketplace-console.js");
|
|
1734
|
+
await runShopCommand(rest);
|
|
1735
|
+
return;
|
|
1736
|
+
}
|
|
1737
|
+
case "purchases":
|
|
1738
|
+
case "purchase":
|
|
1739
|
+
case "buy": {
|
|
1740
|
+
const { runPurchasesCommand } = await import("./devcli/marketplace-console.js");
|
|
1741
|
+
// `vidfarm buy <shop>/<card>` is the whole point of the buyer side, so it
|
|
1742
|
+
// works as a top-level verb without the reader learning a subcommand.
|
|
1743
|
+
await runPurchasesCommand(command === "buy" ? ["buy", ...rest] : rest);
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1706
1746
|
// Both sides of the vending machines: a paid client posting tasks and
|
|
1707
1747
|
// reviewing proofs, and a FREE gigworker with their own dollarplatoon key.
|
|
1708
1748
|
case "gigs":
|
|
@@ -10981,8 +11021,8 @@ async function runMarketplaceCommand(argv) {
|
|
|
10981
11021
|
// Paid web surface — send the human there instead of rendering locally.
|
|
10982
11022
|
console.log(`${BOLD}The marketplace is a web surface for paying customers — browse it here:${RESET}`);
|
|
10983
11023
|
console.log(` ${FRONTEND}${ctx.host}/marketplace${RESET} featured agents`);
|
|
10984
|
-
console.log(` ${FRONTEND}${ctx.host}/marketplace/browse${RESET} portfolios by category tag`);
|
|
10985
|
-
console.log(` ${FRONTEND}${ctx.host}/marketplace/manage${RESET} your orders (gig inboxes)`);
|
|
11024
|
+
console.log(` ${FRONTEND}${ctx.host}/marketplace-old/browse${RESET} portfolios by category tag`);
|
|
11025
|
+
console.log(` ${FRONTEND}${ctx.host}/marketplace-old/manage${RESET} your orders (gig inboxes)`);
|
|
10986
11026
|
console.log("");
|
|
10987
11027
|
console.log(`${DIM}Place orders from here: vidfarm marketplace order --title <t> --brief <b> [--tags a,b] [--folder <path>]${RESET}`);
|
|
10988
11028
|
console.log(`${DIM}${DOLLARPLATOON_SKILL_HINT}${RESET}`);
|
|
@@ -11048,7 +11088,7 @@ async function runMarketplaceCommand(argv) {
|
|
|
11048
11088
|
const order = (result.json ?? {}).order ?? {};
|
|
11049
11089
|
emitResult(result, ctx.json, [
|
|
11050
11090
|
["Manage Inbox", order.inboxUrl],
|
|
11051
|
-
["Manage Orders", `${ctx.host}/marketplace/manage`]
|
|
11091
|
+
["Manage Orders", `${ctx.host}/marketplace-old/manage`]
|
|
11052
11092
|
]);
|
|
11053
11093
|
if (!ctx.json)
|
|
11054
11094
|
console.log(`\n${DIM}${DOLLARPLATOON_SKILL_HINT}${RESET}`);
|
|
@@ -13589,7 +13629,11 @@ void main().catch(async (error) => {
|
|
|
13589
13629
|
// clipper-run / panel conditions: a wrong task id, an id already taken, a
|
|
13590
13630
|
// gate that has to be answered first. All of these are the CLI talking to a
|
|
13591
13631
|
// human, and a stack trace reads as "vidfarm is broken".
|
|
13592
|
-
|| (error instanceof Error && error.name === "ClipperUserError")
|
|
13632
|
+
|| (error instanceof Error && error.name === "ClipperUserError")
|
|
13633
|
+
// `shop` / `purchases`: a refused refund, a card that needs a title, a
|
|
13634
|
+
// missing --answer. Every one of these is the marketplace answering a
|
|
13635
|
+
// person, and the answer is already a sentence.
|
|
13636
|
+
|| (error instanceof Error && error.name === "MarketplaceError")) {
|
|
13593
13637
|
console.error(error.message);
|
|
13594
13638
|
process.exit(1);
|
|
13595
13639
|
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// The vidfarm deliverable, as it travels inside a Dollar Platoon `private_note`.
|
|
2
|
+
//
|
|
3
|
+
// Dollar Platoon gives the vendor exactly one protection: the note on a proof
|
|
4
|
+
// opens only when `paid_out_at` is stamped — not when the buyer approves. So the
|
|
5
|
+
// watermarked preview goes in `proofs[]` where the buyer can rule on it, and
|
|
6
|
+
// everything they are paying FOR goes in the note, sealed until the money moves.
|
|
7
|
+
//
|
|
8
|
+
// Their field is a plain string. That is why this exists: without an agreed
|
|
9
|
+
// shape, one vendor writes "master: <url>", the next writes "here u go", and
|
|
10
|
+
// vidfarm cannot render either as a pack. The string is therefore JSON, WHOLE —
|
|
11
|
+
// vidfarm parses the entire note, so nothing may be appended before or after it.
|
|
12
|
+
// A vendor's prose belongs in `vendorNote`, not around the blob.
|
|
13
|
+
//
|
|
14
|
+
// VERSIONED, because the note is written once and read back after the payout,
|
|
15
|
+
// possibly weeks later, by code that has moved on. An unversioned blob is
|
|
16
|
+
// unreadable the first time the shape changes.
|
|
17
|
+
//
|
|
18
|
+
// v1 deliveryUrl + items[{itemId, kind, urls, notes}]
|
|
19
|
+
// v2 adds previewUrls / previewNote (the watermarked half, described),
|
|
20
|
+
// projectUrl (the composition folder the buyer forks), and vendorNote.
|
|
21
|
+
//
|
|
22
|
+
// v2 is PURELY ADDITIVE: every v1 note still opens, and a v1 reader still finds
|
|
23
|
+
// everything it knew about in a v2 note. Never renumber a field; add one.
|
|
24
|
+
//
|
|
25
|
+
// Backend-free (no imports at all) so it ships in the public cloud-only CLI and
|
|
26
|
+
// is the single definition both `vidfarm gigs` and the server fulfil route use.
|
|
27
|
+
/** Drop empty strings and blanks — a url list is never partly blank. */
|
|
28
|
+
function urls(value) {
|
|
29
|
+
return (value ?? []).map((url) => String(url).trim()).filter(Boolean);
|
|
30
|
+
}
|
|
31
|
+
/** Omit rather than send "" — an absent field reads as absent, not as empty. */
|
|
32
|
+
function text(value) {
|
|
33
|
+
const trimmed = String(value ?? "").trim();
|
|
34
|
+
return trimmed ? trimmed : undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the deliverable from loose input, so no caller hand-rolls the shape.
|
|
38
|
+
*
|
|
39
|
+
* `kind` is DERIVED, never declared: several preview urls are the frames of a
|
|
40
|
+
* slideshow and one is a video. A vendor who cannot state the type cannot state
|
|
41
|
+
* it wrongly, and the declared kind can never disagree with the content.
|
|
42
|
+
*/
|
|
43
|
+
export function buildSealedDeliverable(input) {
|
|
44
|
+
const items = input.items.map((item, index) => {
|
|
45
|
+
const previewUrls = urls(item.previewUrls);
|
|
46
|
+
const masterUrls = urls(item.masterUrls);
|
|
47
|
+
return {
|
|
48
|
+
itemId: text(item.itemId) ?? `item_${index + 1}`,
|
|
49
|
+
kind: item.kind
|
|
50
|
+
?? ((previewUrls.length > 1 || masterUrls.length > 1) ? "slideshow" : "video"),
|
|
51
|
+
urls: masterUrls,
|
|
52
|
+
...(previewUrls.length ? { previewUrls } : {}),
|
|
53
|
+
...(text(item.previewNote) ? { previewNote: text(item.previewNote) } : {}),
|
|
54
|
+
...(text(item.projectUrl) ? { projectUrl: text(item.projectUrl) } : {}),
|
|
55
|
+
notes: text(item.notes) ?? ""
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
v: 2,
|
|
60
|
+
deliveryUrl: text(input.deliveryUrl) ?? "",
|
|
61
|
+
...(text(input.vendorNote) ? { vendorNote: text(input.vendorNote) } : {}),
|
|
62
|
+
items
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** The note, ready to send. The WHOLE string — never append to it. */
|
|
66
|
+
export function sealDeliverable(input) {
|
|
67
|
+
return JSON.stringify(input);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read a note back. Returns null on anything we do not recognise, which is the
|
|
71
|
+
* correct answer for a plain-text note written by a worker who never used this
|
|
72
|
+
* shape — that note is still a valid delivery, it is just not a vidfarm pack.
|
|
73
|
+
*/
|
|
74
|
+
export function openSealedDeliverable(note) {
|
|
75
|
+
if (!note)
|
|
76
|
+
return null;
|
|
77
|
+
try {
|
|
78
|
+
const parsed = JSON.parse(note);
|
|
79
|
+
if (!parsed || !Array.isArray(parsed.items))
|
|
80
|
+
return null;
|
|
81
|
+
// Accept every version we have ever written. A note from a newer vendor CLI
|
|
82
|
+
// than this reader is the one case worth rejecting: its items may mean
|
|
83
|
+
// something else, and half-reading them is worse than showing the raw note.
|
|
84
|
+
return parsed.v === 1 || parsed.v === 2 ? parsed : null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* One human-readable line per item, for a CLI to print before it sends.
|
|
92
|
+
*
|
|
93
|
+
* A vendor cannot proof-read a minified json blob, and the two mistakes that
|
|
94
|
+
* cost the payout — the halves swapped, or no master at all — are both obvious
|
|
95
|
+
* the moment the note is written out in words.
|
|
96
|
+
*/
|
|
97
|
+
export function describeSealedDeliverable(sealed) {
|
|
98
|
+
const lines = [];
|
|
99
|
+
lines.push(sealed.deliveryUrl
|
|
100
|
+
? `pack ${sealed.deliveryUrl}`
|
|
101
|
+
: "pack (none — this proof settles no vidfarm order)");
|
|
102
|
+
if (sealed.vendorNote)
|
|
103
|
+
lines.push(`your note ${sealed.vendorNote}`);
|
|
104
|
+
for (const item of sealed.items) {
|
|
105
|
+
lines.push(`${item.itemId} ${item.kind}`);
|
|
106
|
+
lines.push(` master ${item.urls.length
|
|
107
|
+
? item.urls.join(", ")
|
|
108
|
+
: "(none — nothing unseals when they pay)"}`);
|
|
109
|
+
if (item.previewUrls?.length)
|
|
110
|
+
lines.push(` preview ${item.previewUrls.join(", ")}`);
|
|
111
|
+
if (item.previewNote)
|
|
112
|
+
lines.push(` about ${item.previewNote}`);
|
|
113
|
+
lines.push(` project ${item.projectUrl ?? "(none — the buyer cannot fork this)"}`);
|
|
114
|
+
if (item.notes)
|
|
115
|
+
lines.push(` notes ${item.notes}`);
|
|
116
|
+
}
|
|
117
|
+
return lines;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=delivery-seal.js.map
|