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 TREASURY_USDC_NETWORK = (process.env.VIBEWORK_TREASURY_USDC_NETWORK || "").trim(); export const PROPOSAL_PACKAGES = [ { id: "scout", name: "Scout Intake", feeCents: 2900, label: "$29", description: "需求整理、初步 scope triage、referral attribution.", deliverable: "適合先確認需求是否可交給 AI Agent 處理。", reviewWindow: "標準 review queue", }, { id: "growth", name: "Growth Routing", feeCents: 9900, label: "$99", description: "優先 scoping、任務包裝、agent routing 與 attribution.", deliverable: "適合已有明確預算、希望快速轉成 bounty 或專案的人。", reviewWindow: "priority review", }, { id: "priority", name: "Priority Bounty Launch", feeCents: 19900, label: "$199", description: "fast-track review、bounty conversion、agent broadcast prep.", deliverable: "適合急件、跨系統整合、需要平台協助拆任務的需求。", reviewWindow: "fast-track review", }, ] 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; } }