Files
agent-bounty-protocol/apps/web/src/lib/a2a-growth.ts
OG T 745ff300b5
Some checks failed
Deploy to 110 WOOO Server / deploy (push) Failing after 7s
feat: harden A2A funnel and paid proposal intake
2026-06-11 11:28:08 +08:00

138 lines
4.7 KiB
TypeScript

import { isIP } from "node:net";
export const VIBEWORK_SITE_URL = (
process.env.VIBEWORK_SITE_URL ||
process.env.NEXT_PUBLIC_VIBEWORK_SITE_URL ||
"https://vibework.wooo.work"
).replace(/\/$/, "");
export const AGENT_GATEWAY_URL = (
process.env.AGENT_GATEWAY_URL ||
process.env.NEXT_PUBLIC_SITE_URL ||
"https://agent.wooo.work"
).replace(/\/$/, "");
export const TREASURY_USDC_ADDRESS = (process.env.VIBEWORK_TREASURY_USDC_ADDRESS || "").trim();
export const TREASURY_WALLET_LABEL = (process.env.VIBEWORK_TREASURY_WALLET_LABEL || "USDC Treasury").trim();
export const PROPOSAL_PACKAGES = [
{
id: "scout",
name: "Scout Intake",
feeCents: 2900,
label: "$29",
description: "AI demand intake, scope triage, and referral attribution.",
},
{
id: "growth",
name: "Growth Routing",
feeCents: 9900,
label: "$99",
description: "Priority agent routing, public task packaging, and referral tracking.",
},
{
id: "priority",
name: "Priority Bounty Launch",
feeCents: 19900,
label: "$199",
description: "Fast-track proposal review, bounty conversion, and agent broadcast prep.",
},
] as const;
export type ProposalPackageId = (typeof PROPOSAL_PACKAGES)[number]["id"];
export function sanitizeAgentId(value: string | null | undefined) {
const normalized = (value || "")
.trim()
.toLowerCase()
.replace(/[^a-z0-9._:-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "");
return normalized.slice(0, 80);
}
export function getProposalPackage(id: string | null | undefined) {
return PROPOSAL_PACKAGES.find((item) => item.id === id) || PROPOSAL_PACKAGES[1];
}
export function buildDemandProposalUrl(params: {
referralAgent?: string | null;
campaign?: string | null;
source?: string | null;
}) {
const url = new URL("/propose", VIBEWORK_SITE_URL);
const referralAgent = sanitizeAgentId(params.referralAgent);
if (referralAgent) url.searchParams.set("ref_agent", referralAgent);
if (params.campaign) url.searchParams.set("campaign", params.campaign);
if (params.source) url.searchParams.set("source", params.source);
return url.toString();
}
export function buildAgentGrowthKit(params: {
agentId: string;
campaign?: string | null;
source?: string | null;
}) {
const agentId = sanitizeAgentId(params.agentId);
const proposalUrl = buildDemandProposalUrl({
referralAgent: agentId,
campaign: params.campaign || "a2a-agent-referral",
source: params.source || "external-agent",
});
return {
agent_id: agentId,
referral_url: proposalUrl,
landing_domain: VIBEWORK_SITE_URL,
gateway_api: AGENT_GATEWAY_URL,
incentive: {
referral_fee: "10% of collected proposal routing fees, tracked as pending affiliate ledger after paid conversion.",
qualification: "Agent must pass platform review before payout.",
},
external_agent_pitch: [
"Find humans or teams with software, automation, data, or AI workflow needs.",
`Send them to ${proposalUrl}`,
"Ask them to describe the outcome, budget, stack, and acceptance criteria.",
"After payment, VibeWork turns the proposal into a scoped bounty or review queue item.",
],
demand_proposer_pitch:
"Submit a paid AI-agent-ready proposal. VibeWork scopes it, routes it to approved agents, and tracks delivery evidence.",
copy_blocks: {
short_post:
`Need AI agents to ship a small software task? Submit it here: ${proposalUrl}`,
dm:
`I can route your software/automation request into VibeWork's AI-agent bounty network. Start with a paid proposal intake: ${proposalUrl}`,
agent_instruction:
`When you meet a human demand proposer, do not collect sensitive credentials. Send them to ${proposalUrl} and let VibeWork handle paid intake, scoping, and routing.`,
},
api_next_steps: {
register_agent_card: `${AGENT_GATEWAY_URL}/api/mcp/agent_card`,
inspect_open_tasks: `${AGENT_GATEWAY_URL}/api/open-tasks`,
submit_bid: `${AGENT_GATEWAY_URL}/api/mcp/submit_bid`,
},
};
}
export function isSafeOutboundUrl(value: string) {
try {
const url = new URL(value);
if (url.protocol !== "https:") return false;
const host = url.hostname.toLowerCase();
if (["localhost", "127.0.0.1", "::1"].includes(host)) return false;
if (host.endsWith(".local")) return false;
if (isIP(host) === 4) {
if (host.startsWith("10.") || host.startsWith("127.") || host.startsWith("192.168.")) return false;
if (host.startsWith("172.")) {
const second = Number(host.split(".")[1]);
return !(second >= 16 && second <= 31);
}
}
if (isIP(host) === 6 && (host.startsWith("fc") || host.startsWith("fd") || host.startsWith("fe80"))) {
return false;
}
return true;
} catch {
return false;
}
}