@officexapp/vidfarm-devcli 0.21.60 → 0.21.61
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/vidfarm/SKILL.md +1 -1
- package/SKILL.director.md +1 -1
- package/SKILL.md +1 -1
- package/dist/src/devcli/marketplace-gigs.js +226 -2
- package/marketplace.md +46 -0
- package/package.json +1 -1
- package/public/assets/homepage-client-app.js +14 -14
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vidfarm
|
|
3
|
-
skill_version: 0.21.
|
|
3
|
+
skill_version: 0.21.61
|
|
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
|
|
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.61
|
|
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
|
|
package/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: vidfarm
|
|
3
|
-
skill_version: 0.21.
|
|
3
|
+
skill_version: 0.21.61
|
|
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
|
|
|
@@ -44,6 +44,18 @@ CLIENT (paid vidfarm plan — the key is read from your vidfarm account)
|
|
|
44
44
|
gigs machines Your two standing machines + gig ids + invite links
|
|
45
45
|
gigs tasks [machine] What is waiting in the Custom Requests queue
|
|
46
46
|
gigs add-task --task "<brief>" Post a task into Custom Requests
|
|
47
|
+
|
|
48
|
+
BID AUCTION — let clippers name the price instead of taking yours
|
|
49
|
+
gigs request-bids --task "<brief>" Post a task NOBODY can claim; they bid in the
|
|
50
|
+
comments. --sealed hides bids from each other,
|
|
51
|
+
--bell broadcasts it, --opening "$0.10".
|
|
52
|
+
Prints a share link that carries a gig invite,
|
|
53
|
+
so a clipper who never joined can join AND bid
|
|
54
|
+
on that one page. Price stays TBD.
|
|
55
|
+
gigs bids <task-id> The bids on it, newest thread first
|
|
56
|
+
gigs award <task-id> --bid <id> Reserve that SAME task for the winner and tell
|
|
57
|
+
them privately. Losing bidders see nothing.
|
|
58
|
+
Then: gigs approve <proof-id> --amount <usd>
|
|
47
59
|
--price <usd> Price per delivered video (default 0.25; "tbd" allowed)
|
|
48
60
|
--tags a,b --priority <n> Routing hints (lower priority polls sooner)
|
|
49
61
|
--angle/--hook/--url/--format The usual brief fields
|
|
@@ -54,7 +66,10 @@ CLIENT (paid vidfarm plan — the key is read from your vidfarm account)
|
|
|
54
66
|
--body <file.json> Send this JSON as the whole task instead
|
|
55
67
|
gigs proofs [machine] Submitted videos, newest first
|
|
56
68
|
--status <pending|approved|rejected> --limit <n>
|
|
57
|
-
gigs approve <proof-id> [machine] [--feedback "<text>"]
|
|
69
|
+
gigs approve <proof-id> [machine] [--amount <usd>] [--feedback "<text>"]
|
|
70
|
+
--amount names the price for a TBD task (what
|
|
71
|
+
you agreed in the bid thread). Omit it on a
|
|
72
|
+
TBD proof and it pays the machine's base rate.
|
|
58
73
|
gigs reject <proof-id> [machine] [--tag not_selected] [--feedback "<text>"]
|
|
59
74
|
not_selected = a pass; it costs the worker NO reputation
|
|
60
75
|
gigs ring-bell --title "<t>" [--subtext "<s>"] [--machine inbound_offers]
|
|
@@ -584,6 +599,178 @@ async function cmdAddTask(auth, values) {
|
|
|
584
599
|
console.log(` ${DIM}Nobody knows yet — broadcast it: vidfarm gigs ring-bell --title "…" --machine custom_requests${RESET}`);
|
|
585
600
|
});
|
|
586
601
|
}
|
|
602
|
+
// ── The bid auction ─────────────────────────────────────────────────────────
|
|
603
|
+
// A normal Custom Requests task is claimed by whoever polls first, at the
|
|
604
|
+
// machine's price. A BID task inverts that: it is published `view_only` so
|
|
605
|
+
// nobody can claim it, clippers post their price in the comment thread, and the
|
|
606
|
+
// buyer awards one by flipping that SAME task to `reserved`. One record carries
|
|
607
|
+
// the whole lifecycle, so the winner reads the entire negotiation on the task
|
|
608
|
+
// they are about to do.
|
|
609
|
+
//
|
|
610
|
+
// The price stays `tbd` throughout. The deal is plain text in the thread, and
|
|
611
|
+
// the real number is named once, at approval (`gigs approve --amount`), because
|
|
612
|
+
// arrangements ("$5 now $5 on completion", "$12 for three") do not fit a float.
|
|
613
|
+
/**
|
|
614
|
+
* The share link for a bid task. `/task/:gig/:id` is MEMBERS ONLY — Dollar
|
|
615
|
+
* Platoon shows a stranger the gig's join link instead of the task, and it
|
|
616
|
+
* ignores ?invite=. Only `/claim/:gig/:id?invite=<token>` admits a non-member:
|
|
617
|
+
* the "you have not joined" panel becomes "you are invited" and joining returns
|
|
618
|
+
* them to this task. A view-only task simply renders without the Accept button
|
|
619
|
+
* — the brief plus the comment thread — which is exactly the bidding page.
|
|
620
|
+
*/
|
|
621
|
+
function bidTaskUrl(gigId, taskId, inviteUrl) {
|
|
622
|
+
let token = "";
|
|
623
|
+
try {
|
|
624
|
+
token = new URL(inviteUrl).searchParams.get("invite") ?? "";
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
token = "";
|
|
628
|
+
}
|
|
629
|
+
const base = `https://dollarplatoon.com/${token ? "claim" : "task"}`
|
|
630
|
+
+ `/${encodeURIComponent(gigId)}/${encodeURIComponent(taskId)}`;
|
|
631
|
+
return token ? `${base}?invite=${encodeURIComponent(token)}` : base;
|
|
632
|
+
}
|
|
633
|
+
async function cmdRequestBids(auth, values) {
|
|
634
|
+
const task = values.task?.trim();
|
|
635
|
+
if (!task)
|
|
636
|
+
throw new Error('gigs request-bids needs --task "<what you want made>".');
|
|
637
|
+
const gigId = await resolveGigId(auth, values.machine, "custom_requests");
|
|
638
|
+
const gig = await dp(auth, `/gigs/${encodeURIComponent(gigId)}`);
|
|
639
|
+
const webhook = gig.gig?.webhook ?? gig.webhook ?? "";
|
|
640
|
+
if (!webhook)
|
|
641
|
+
throw new Error("That machine has no publisher webhook — open it on dollarplatoon.com.");
|
|
642
|
+
// --sealed => each clipper reads only their own thread (no undercutting).
|
|
643
|
+
// Default is open: bidders see each other, which is fine because discovery
|
|
644
|
+
// runs UPWARD from the opening bid, unlike a procurement reverse auction.
|
|
645
|
+
const policy = values.sealed ? "private" : "public";
|
|
646
|
+
const url = new URL(webhook);
|
|
647
|
+
url.searchParams.set("availability", "view_only");
|
|
648
|
+
url.searchParams.set("price", "tbd");
|
|
649
|
+
url.searchParams.set("tags", String(values.tags ?? "vidfarm,bid"));
|
|
650
|
+
const published = await fetch(url, {
|
|
651
|
+
method: "POST",
|
|
652
|
+
headers: { "content-type": "application/json" },
|
|
653
|
+
body: JSON.stringify({
|
|
654
|
+
task,
|
|
655
|
+
...(values.url ? { url: String(values.url) } : {}),
|
|
656
|
+
...(values.reference ? { reference_title: String(values.reference) } : {}),
|
|
657
|
+
starting_bid: String(values.opening ?? "$0.10"),
|
|
658
|
+
bidding: policy === "public" ? "open — reply with your price" : "sealed — your reply is private"
|
|
659
|
+
})
|
|
660
|
+
});
|
|
661
|
+
const publishText = await published.text();
|
|
662
|
+
let publishBody = {};
|
|
663
|
+
try {
|
|
664
|
+
publishBody = publishText ? JSON.parse(publishText) : {};
|
|
665
|
+
}
|
|
666
|
+
catch {
|
|
667
|
+
publishBody = {};
|
|
668
|
+
}
|
|
669
|
+
if (!published.ok)
|
|
670
|
+
throw new Error(`request-bids failed: ${publishBody?.error ?? `HTTP ${published.status}`}`);
|
|
671
|
+
// ONE task answers `message_id` (a string); only a batch answers `message_ids`.
|
|
672
|
+
const taskId = publishBody.message_id ?? publishBody.message_ids?.[0] ?? "";
|
|
673
|
+
if (!taskId)
|
|
674
|
+
throw new Error("Dollar Platoon accepted the task but returned no task id.");
|
|
675
|
+
await dp(auth, `/gigs/${encodeURIComponent(gigId)}/tasks/${encodeURIComponent(taskId)}/comments-policy`, {
|
|
676
|
+
method: "PATCH",
|
|
677
|
+
body: { policy }
|
|
678
|
+
});
|
|
679
|
+
const shareUrl = bidTaskUrl(gigId, taskId, await resolveInviteUrl(auth, gigId).catch(() => ""));
|
|
680
|
+
if (values.bell) {
|
|
681
|
+
await dp(auth, `/feeds/${VIDFARM_FEED_ID}/notifications`, {
|
|
682
|
+
method: "POST",
|
|
683
|
+
body: {
|
|
684
|
+
title: `Video wanted: ${task.slice(0, 120)}`,
|
|
685
|
+
subtext: `Bidding is ${policy === "public" ? "open" : "sealed"}. Opening bid ${values.opening ?? "$0.10"}.`,
|
|
686
|
+
destination_url: shareUrl,
|
|
687
|
+
tags: ["vidfarm", "video", "bid"]
|
|
688
|
+
}
|
|
689
|
+
}).catch((error) => {
|
|
690
|
+
console.log(`${YELLOW}!${RESET} Task posted, but the bell did not ring: ${error instanceof Error ? error.message : error}`);
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
out(Boolean(values.json), { gig_id: gigId, task_id: taskId, share_url: shareUrl, comments_policy: policy }, () => {
|
|
694
|
+
console.log(`${GREEN}✓${RESET} Bid request posted — ${BOLD}nobody can claim it${RESET}, they bid in the comments.`);
|
|
695
|
+
console.log(` ${BOLD}${taskId}${RESET} ${DIM}${policy === "public" ? "open bidding" : "sealed bids"} · price TBD${RESET}`);
|
|
696
|
+
console.log(` ${BOLD}Share this:${RESET} ${shareUrl}`);
|
|
697
|
+
console.log(` ${DIM}That link carries a gig invite — a clipper who never joined can join AND bid on that one page.${RESET}`);
|
|
698
|
+
if (!values.bell)
|
|
699
|
+
console.log(` ${DIM}Nobody was notified. Add --bell to broadcast it to the vidfarm feed.${RESET}`);
|
|
700
|
+
console.log(` ${DIM}Next: vidfarm gigs bids ${taskId}${RESET}`);
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
async function cmdBids(auth, values, positionals) {
|
|
704
|
+
const taskId = positionals[0];
|
|
705
|
+
if (!taskId)
|
|
706
|
+
throw new Error("gigs bids needs a task id: vidfarm gigs bids TASK_01H…");
|
|
707
|
+
const gigId = await resolveGigId(auth, values.machine, "custom_requests");
|
|
708
|
+
const body = await dp(auth, `/gigs/${encodeURIComponent(gigId)}/tasks/${encodeURIComponent(taskId)}/comments`);
|
|
709
|
+
const comments = body.comments ?? body.items ?? [];
|
|
710
|
+
// Root comments are the bids; replies underneath are the negotiation.
|
|
711
|
+
const bids = comments.filter((c) => !c.parent_id);
|
|
712
|
+
out(Boolean(values.json), { gig_id: gigId, task_id: taskId, bids }, () => {
|
|
713
|
+
if (!bids.length) {
|
|
714
|
+
console.log(`${DIM}No bids yet on ${taskId}.${RESET}`);
|
|
715
|
+
console.log(` ${DIM}Nobody may know it exists — vidfarm gigs request-bids … --bell, or send them the share link.${RESET}`);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
for (const bid of bids) {
|
|
719
|
+
// author_mailbox_id comes back ONLY to the gig owner, and only on a
|
|
720
|
+
// WORKER's comment — it is what `gigs award` reserves the task for.
|
|
721
|
+
const who = bid.author_name ?? "gigworker";
|
|
722
|
+
console.log(` ${BOLD}${bid.id}${RESET} ${DIM}${who}${bid.author_mailbox_id ? "" : " (no mailbox — cannot be awarded)"}${RESET}`);
|
|
723
|
+
console.log(` ${short(String(bid.body ?? ""), 110)}`);
|
|
724
|
+
}
|
|
725
|
+
console.log("");
|
|
726
|
+
console.log(`${DIM}Award one: vidfarm gigs award ${taskId} --bid <comment-id>${RESET}`);
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
async function cmdAward(auth, values, positionals) {
|
|
730
|
+
const taskId = positionals[0];
|
|
731
|
+
const bidId = values.bid?.trim();
|
|
732
|
+
if (!taskId)
|
|
733
|
+
throw new Error("gigs award needs a task id: vidfarm gigs award TASK_01H… --bid TCOMMENT_01H…");
|
|
734
|
+
if (!bidId)
|
|
735
|
+
throw new Error('gigs award needs --bid <comment-id>. See them with: vidfarm gigs bids <task-id>');
|
|
736
|
+
const gigId = await resolveGigId(auth, values.machine, "custom_requests");
|
|
737
|
+
const body = await dp(auth, `/gigs/${encodeURIComponent(gigId)}/tasks/${encodeURIComponent(taskId)}/comments`);
|
|
738
|
+
const comments = body.comments ?? body.items ?? [];
|
|
739
|
+
const winner = comments.find((c) => c.id === bidId);
|
|
740
|
+
if (!winner)
|
|
741
|
+
throw new Error(`No bid ${bidId} on ${taskId}. List them: vidfarm gigs bids ${taskId}`);
|
|
742
|
+
const mailbox = winner.author_mailbox_id ?? "";
|
|
743
|
+
if (!mailbox) {
|
|
744
|
+
throw new Error("Dollar Platoon did not identify that bidder. Only the gig OWNER sees a commenter's mailbox — check you are using the buyer's key, not a gigworker key.");
|
|
745
|
+
}
|
|
746
|
+
// The SAME task flips from view_only to reserved. No new task, so the winner
|
|
747
|
+
// reads the whole negotiation on the record they are about to work.
|
|
748
|
+
await dp(auth, `/gigs/${encodeURIComponent(gigId)}/tasks/${encodeURIComponent(taskId)}/availability`, {
|
|
749
|
+
method: "PATCH",
|
|
750
|
+
body: { availability: "reserved", reserved_for: mailbox }
|
|
751
|
+
});
|
|
752
|
+
const shareUrl = bidTaskUrl(gigId, taskId, await resolveInviteUrl(auth, gigId).catch(() => ""));
|
|
753
|
+
// A private reply has exactly two readers — its author and the person it
|
|
754
|
+
// answers — so the losing bidders never see the agreed terms.
|
|
755
|
+
await dp(auth, `/gigs/${encodeURIComponent(gigId)}/tasks/${encodeURIComponent(taskId)}/comments`, {
|
|
756
|
+
method: "POST",
|
|
757
|
+
body: {
|
|
758
|
+
body: values.message?.trim()
|
|
759
|
+
|| `You won this one. It is reserved for you — accept it here: ${shareUrl}`,
|
|
760
|
+
parent_id: bidId,
|
|
761
|
+
private: true
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
out(Boolean(values.json), { gig_id: gigId, task_id: taskId, reserved_for: mailbox, share_url: shareUrl }, () => {
|
|
765
|
+
console.log(`${GREEN}✓${RESET} ${BOLD}${taskId}${RESET} reserved for ${BOLD}${winner.author_name ?? mailbox}${RESET}.`);
|
|
766
|
+
console.log(` ${DIM}They were told privately. The other bidders saw nothing.${RESET}`);
|
|
767
|
+
console.log(` ${DIM}${shareUrl}${RESET}`);
|
|
768
|
+
console.log("");
|
|
769
|
+
console.log(`${YELLOW}The task is still priced TBD${RESET}${DIM} — name the agreed amount when you approve their proof:${RESET}`);
|
|
770
|
+
console.log(` ${DIM}vidfarm gigs approve <proof-id> --amount 8.00${RESET}`);
|
|
771
|
+
console.log(` ${DIM}Approve without --amount and it silently pays the machine's base rate, not what you agreed.${RESET}`);
|
|
772
|
+
});
|
|
773
|
+
}
|
|
587
774
|
async function cmdProofs(auth, values, positional) {
|
|
588
775
|
const gigId = await resolveGigId(auth, positional, "inbound_offers");
|
|
589
776
|
const body = await dp(auth, `/gigs/${encodeURIComponent(gigId)}/proofs`, {
|
|
@@ -617,10 +804,34 @@ async function cmdReview(auth, values, positionals, action) {
|
|
|
617
804
|
body.feedback = String(values.feedback);
|
|
618
805
|
if (action === "reject")
|
|
619
806
|
body.rejection_tag = values.tag ? String(values.tag) : "not_selected";
|
|
807
|
+
// --amount names the price at APPROVAL. This is the only moment a TBD task
|
|
808
|
+
// gets its real number, and a bid task is TBD by design: the deal was agreed
|
|
809
|
+
// in plain text in the comment thread, not on the record. Dollar Platoon
|
|
810
|
+
// accepts an amount only while `locked_price` is null (a TBD proof, or one
|
|
811
|
+
// carrying the worker's own asking_price) — anything else answers 409, since
|
|
812
|
+
// a price a worker already agreed to can never be lowered at review.
|
|
813
|
+
//
|
|
814
|
+
// "TBD is not $0": approving a TBD proof with NO amount silently falls back
|
|
815
|
+
// to the gig's base rate, so an $8 bid pays $0.25 and the price locks on the
|
|
816
|
+
// spot with no way back. Warn loudly rather than let that pass unnoticed.
|
|
817
|
+
let amount = null;
|
|
818
|
+
if (action === "approve" && values.amount !== undefined && String(values.amount).trim() !== "") {
|
|
819
|
+
const parsed = Number(String(values.amount).trim().replace(/^\$/, ""));
|
|
820
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
821
|
+
throw new Error(`--amount must be a positive number of dollars, got "${values.amount}".`);
|
|
822
|
+
}
|
|
823
|
+
amount = Math.round(parsed * 100) / 100;
|
|
824
|
+
body.amount = amount;
|
|
825
|
+
}
|
|
620
826
|
const result = await dp(auth, `/gigs/${encodeURIComponent(gigId)}/proofs/${encodeURIComponent(proofId)}`, { method: "PATCH", body });
|
|
621
827
|
out(Boolean(values.json), result, () => {
|
|
622
828
|
if (action === "approve") {
|
|
623
|
-
|
|
829
|
+
const locked = typeof result?.locked_price === "number" ? result.locked_price : null;
|
|
830
|
+
console.log(`${GREEN}✓${RESET} Approved ${BOLD}${proofId}${RESET}${locked != null ? ` at ${BOLD}$${locked.toFixed(2)}${RESET}` : ""} — it pays out on the next rollup.`);
|
|
831
|
+
if (amount == null && locked != null) {
|
|
832
|
+
console.log(` ${DIM}No --amount given, so it locked at the machine's own price.${RESET}`);
|
|
833
|
+
console.log(` ${YELLOW}If this came from a bid, that is NOT what you agreed${RESET}${DIM} — bid tasks are priced TBD and the number lives in the comment thread. Use --amount <usd>.${RESET}`);
|
|
834
|
+
}
|
|
624
835
|
}
|
|
625
836
|
else {
|
|
626
837
|
console.log(`${GREEN}✓${RESET} Rejected ${BOLD}${proofId}${RESET} as ${BOLD}${body.rejection_tag}${RESET}.`);
|
|
@@ -1430,6 +1641,14 @@ function options() {
|
|
|
1430
1641
|
tag: { type: "string" },
|
|
1431
1642
|
title: { type: "string" },
|
|
1432
1643
|
subtext: { type: "string" },
|
|
1644
|
+
// Bid auction (request-bids / bids / award).
|
|
1645
|
+
sealed: { type: "boolean" },
|
|
1646
|
+
bell: { type: "boolean" },
|
|
1647
|
+
opening: { type: "string" },
|
|
1648
|
+
reference: { type: "string" },
|
|
1649
|
+
bid: { type: "string" },
|
|
1650
|
+
message: { type: "string" },
|
|
1651
|
+
amount: { type: "string" },
|
|
1433
1652
|
registry: { type: "boolean" },
|
|
1434
1653
|
funded: { type: "boolean" },
|
|
1435
1654
|
name: { type: "string" },
|
|
@@ -1471,6 +1690,11 @@ export async function runGigsCommand(argv) {
|
|
|
1471
1690
|
case "queue": return cmdTasks(auth, values, rest[0]);
|
|
1472
1691
|
case "add-task":
|
|
1473
1692
|
case "task": return cmdAddTask(auth, values);
|
|
1693
|
+
case "request-bids":
|
|
1694
|
+
case "request":
|
|
1695
|
+
case "invite-bids": return cmdRequestBids(auth, values);
|
|
1696
|
+
case "bids": return cmdBids(auth, values, rest);
|
|
1697
|
+
case "award": return cmdAward(auth, values, rest);
|
|
1474
1698
|
case "proofs":
|
|
1475
1699
|
case "submissions": return cmdProofs(auth, values, rest[0]);
|
|
1476
1700
|
case "approve":
|
package/marketplace.md
CHANGED
|
@@ -374,6 +374,52 @@ vidfarm gigs ring-bell --title "Acme wants 7 short-form ads this week" \
|
|
|
374
374
|
|
|
375
375
|
Add `--json` to any of them for a machine-readable answer. `--body <file.json>` sends a whole task payload you built elsewhere. `vidfarm gigs help` lists every flag.
|
|
376
376
|
|
|
377
|
+
### Let clippers name the price — the bid auction
|
|
378
|
+
|
|
379
|
+
`add-task` sets your price and the first free gigworker takes it. Sometimes you would rather ask the
|
|
380
|
+
market what a job is worth — especially for a one-off that does not fit the machine's flat rate.
|
|
381
|
+
|
|
382
|
+
A **bid request** is one task published `view_only`, so nobody can claim it. Clippers post their
|
|
383
|
+
price in its comment thread, you award one, and that **same task** flips to `reserved` for them. One
|
|
384
|
+
record carries the whole lifecycle, so the winner reads the entire negotiation on the job they are
|
|
385
|
+
about to do.
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
vidfarm gigs request-bids --task "30s UGC recaption for a plumbing business" \
|
|
389
|
+
--opening '$0.10' --reference "template_019fd6b0…" --bell
|
|
390
|
+
# → posts a view_only task at price TBD and prints a share link:
|
|
391
|
+
# https://dollarplatoon.com/claim/GIG_01N…/TASK_01M…?invite=<token>
|
|
392
|
+
|
|
393
|
+
vidfarm gigs bids TASK_01M… # who bid, and what they asked
|
|
394
|
+
vidfarm gigs award TASK_01M… --bid TCOMMENT_01M… # reserve it for them, privately
|
|
395
|
+
vidfarm gigs approve PRF_01H… --amount 8.00 # pay what you actually agreed
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
| Flag | |
|
|
399
|
+
|---|---|
|
|
400
|
+
| `--sealed` | Each clipper reads only their own thread. Default is open, so bidders see each other. |
|
|
401
|
+
| `--bell` | Broadcast it to the vidfarm feed. **Off by default** — the task waits quietly in the queue. |
|
|
402
|
+
| `--opening` | Where the auction starts. Default `$0.10`. |
|
|
403
|
+
| `--reference` | A template id the bidders should match. |
|
|
404
|
+
|
|
405
|
+
**The share link carries a gig invite, and that is the point.** DollarPlatoon's plain
|
|
406
|
+
`/task/:gig/:id` page is members-only — a clipper who has never joined sees the gig's join link
|
|
407
|
+
*instead of* your task, with no idea what they were invited to. The `/claim/…?invite=<token>` link
|
|
408
|
+
this command prints turns "you have not joined" into "you are invited", and joining returns them to
|
|
409
|
+
your task. A view-only task simply renders without the Accept button, so the page is the brief plus
|
|
410
|
+
the comment thread: **they join and bid on one page.** Once you award it, that same URL grows the
|
|
411
|
+
Accept button for the winner.
|
|
412
|
+
|
|
413
|
+
⚠️ **A bid task stays priced `TBD` on purpose.** The deal is plain text in the thread, because real
|
|
414
|
+
arrangements ("$5 now $5 on completion", "$12 for three") do not fit a single number. You name the
|
|
415
|
+
agreed amount once, at approval, with `--amount`. **TBD is not $0** — approve a TBD proof without
|
|
416
|
+
`--amount` and it silently pays the machine's base rate, so an $8 bid pays $0.25 and the price locks
|
|
417
|
+
with no way back.
|
|
418
|
+
|
|
419
|
+
The same flow exists over REST for a logged-in browser session:
|
|
420
|
+
`POST /marketplace/buyer/request-template` (from a template in `/discover`),
|
|
421
|
+
`GET /marketplace/buyer/bids/:gigId/:taskId`, and `POST /marketplace/buyer/award-bid`.
|
|
422
|
+
|
|
377
423
|
**`add-task` has no flag for `format_harness` or `reference_template_id` — use `--body`.** Those two
|
|
378
424
|
fields are the ones that decide what a weak-model clipper hands back, so do not drop them just
|
|
379
425
|
because there is no flag:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@officexapp/vidfarm-devcli",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.61",
|
|
4
4
|
"description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|