@officexapp/vidfarm-devcli 0.21.61 → 0.21.63

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 (29) hide show
  1. package/.agents/skills/dollarplatoon-skill/SKILL.md +163 -1174
  2. package/.agents/skills/dollarplatoon-skill/SOURCE.md +62 -0
  3. package/.agents/skills/dollarplatoon-skill/skill/clients.md +234 -0
  4. package/.agents/skills/dollarplatoon-skill/skill/feeds.md +326 -0
  5. package/.agents/skills/dollarplatoon-skill/skill/gigs.md +395 -0
  6. package/.agents/skills/dollarplatoon-skill/skill/gigworkers.md +324 -0
  7. package/.agents/skills/dollarplatoon-skill/skill/orders.md +573 -0
  8. package/.agents/skills/dollarplatoon-skill/skill/payouts.md +234 -0
  9. package/.agents/skills/dollarplatoon-skill/skill/platform.md +174 -0
  10. package/.agents/skills/dollarplatoon-skill/skill/prices.md +75 -0
  11. package/.agents/skills/dollarplatoon-skill/skill/pricing-and-tags.md +255 -0
  12. package/.agents/skills/dollarplatoon-skill/skill/proofs.md +555 -0
  13. package/.agents/skills/dollarplatoon-skill/skill/queue.md +404 -0
  14. package/.agents/skills/dollarplatoon-skill/skill/quickstart.md +191 -0
  15. package/.agents/skills/dollarplatoon-skill/skill/staging.md +178 -0
  16. package/.agents/skills/dollarplatoon-skill/skill/tasks.md +588 -0
  17. package/.agents/skills/dollarplatoon-skill/skill/web-pages.md +586 -0
  18. package/.agents/skills/vidfarm/SKILL.md +3 -3
  19. package/.agents/skills/vidfarm/references/core-workflows.md +39 -0
  20. package/SKILL.director.md +42 -3
  21. package/SKILL.md +3 -1
  22. package/clipper.md +20 -0
  23. package/dist/src/cli.js +50 -6
  24. package/dist/src/devcli/delivery-seal.js +119 -0
  25. package/dist/src/devcli/marketplace-console.js +1253 -0
  26. package/dist/src/devcli/marketplace-gigs.js +162 -16
  27. package/marketplace.md +275 -1
  28. package/package.json +28 -3
  29. package/public/assets/homepage-client-app.js +13 -13
@@ -279,6 +279,45 @@ POST /api/v1/marketplace/orders/:gigId/invite { "slug": "<agent portfolio slug
279
279
 
280
280
  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
281
 
282
+ ## Notifications — one list for both sides of the marketplace
283
+
284
+ 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.
285
+
286
+ | you are | you are told about |
287
+ |---|---|
288
+ | **vendor** | a new order · a new review · a payout · the buyer asked for changes · a new comment · the buyer withdrew · a wallet withdrawal |
289
+ | **buyer** | your order was fulfilled · a new comment · the vendor refunded and closed it |
290
+
291
+ **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`.
292
+
293
+ 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:
294
+
295
+ ```
296
+ GET /notifications?q=<search>&filter=all|unseen&page=<n> the list, newest first
297
+ POST /notifications/:notificationId/seen form: seen=1|0, q, filter, page
298
+ POST /notifications/mark-all-seen form: q, filter
299
+ ```
300
+
301
+ 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.
302
+
303
+ 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:
304
+
305
+ ```bash
306
+ curl -s -b cookies.txt "https://vidfarm.cc/api/v1/user/me/marketplace-access"
307
+ # { "ok": true, "marketplace": true, "vendor": true, "shop_slug": "acme", "notifications_unseen": 3 }
308
+ ```
309
+
310
+ ### Marketplace email — two messages, one switch
311
+
312
+ `marketplace@vidfarm.cc` sends exactly two things, and nothing else ever comes from that address:
313
+
314
+ | to | when |
315
+ |---|---|
316
+ | the **vendor** | a buyer placed an order in their shop |
317
+ | the **buyer** | a vendor delivered the pack — it is ready to tear |
318
+
319
+ **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.
320
+
282
321
  ## Your Dollar Platoon key, from the vidfarm REST API
283
322
 
284
323
  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.61
3
+ skill_version: 0.21.63
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` | ~485 ln | Template discovery, auth, fork → render → approve → share, versioning, cost/wallet, marketplace orders, the customer's Dollar Platoon key + the four gig quick tasks, dedupe-before-publish |
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
 
@@ -877,6 +877,45 @@ POST /api/v1/marketplace/orders/:gigId/invite { "slug": "<agent portfolio slug
877
877
 
878
878
  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
879
 
880
+ ## Notifications — one list for both sides of the marketplace
881
+
882
+ 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.
883
+
884
+ | you are | you are told about |
885
+ |---|---|
886
+ | **vendor** | a new order · a new review · a payout · the buyer asked for changes · a new comment · the buyer withdrew · a wallet withdrawal |
887
+ | **buyer** | your order was fulfilled · a new comment · the vendor refunded and closed it |
888
+
889
+ **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`.
890
+
891
+ 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:
892
+
893
+ ```
894
+ GET /notifications?q=<search>&filter=all|unseen&page=<n> the list, newest first
895
+ POST /notifications/:notificationId/seen form: seen=1|0, q, filter, page
896
+ POST /notifications/mark-all-seen form: q, filter
897
+ ```
898
+
899
+ 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.
900
+
901
+ 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:
902
+
903
+ ```bash
904
+ curl -s -b cookies.txt "https://vidfarm.cc/api/v1/user/me/marketplace-access"
905
+ # { "ok": true, "marketplace": true, "vendor": true, "shop_slug": "acme", "notifications_unseen": 3 }
906
+ ```
907
+
908
+ ### Marketplace email — two messages, one switch
909
+
910
+ `marketplace@vidfarm.cc` sends exactly two things, and nothing else ever comes from that address:
911
+
912
+ | to | when |
913
+ |---|---|
914
+ | the **vendor** | a buyer placed an order in their shop |
915
+ | the **buyer** | a vendor delivered the pack — it is ready to tear |
916
+
917
+ **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.
918
+
880
919
  ## Your Dollar Platoon key, from the vidfarm REST API
881
920
 
882
921
  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.61
3
+ skill_version: 0.21.63
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
- Marketplace (paid, cloud-only — the bazaar never renders locally):
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