163 lines
6.0 KiB
TypeScript
163 lines
6.0 KiB
TypeScript
import { isIP } from "node:net";
|
|
import { A2A_AGENT_INTEGRATIONS, TELEGRAM_CONTROL_PLANE_ROLES } from "@/lib/a2a-agent-integrations";
|
|
|
|
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`,
|
|
integration_catalog: `${AGENT_GATEWAY_URL}/api/a2a/integrations?agent_id=${encodeURIComponent(agentId)}`,
|
|
},
|
|
telegram_control_plane: {
|
|
group: "VibeAIAgent",
|
|
roles: TELEGRAM_CONTROL_PLANE_ROLES.map((role) => ({
|
|
id: role.id,
|
|
name: role.name,
|
|
job: role.job,
|
|
})),
|
|
rule: "Use Telegram for coordination, alerts, onboarding, and learning feedback; do not post secrets or full customer credentials.",
|
|
},
|
|
recommended_external_agent_lanes: A2A_AGENT_INTEGRATIONS.slice(0, 8).map((integration) => ({
|
|
id: integration.id,
|
|
name: integration.name,
|
|
status: integration.status,
|
|
role: integration.primaryRole,
|
|
monetization_lane: integration.monetizationLane,
|
|
})),
|
|
};
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|