moltlaunch 2.0.0 → 2.0.2
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/README.md +2 -2
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/.claude/commands/deploy.md +0 -33
- package/.claude/hooks/regenerate-docs.sh +0 -12
- package/.claude/settings.json +0 -15
- package/.env.example +0 -2
- package/.github/workflows/deploy.yml +0 -37
- package/ROADMAP.md +0 -29
- package/contracts/MandateEscrowV4.sol +0 -281
- package/contracts/mocks/MockFlaunchBuyback.sol +0 -24
- package/hardhat.config.cjs +0 -29
- package/scripts/check-deploy-cost.ts +0 -15
- package/scripts/deploy-escrow-v4.ts +0 -81
- package/scripts/deploy-escrow.cjs +0 -22
- package/scripts/generate-docs.ts +0 -309
- package/shared/manifest.json +0 -87
- package/site/.vscode/extensions.json +0 -4
- package/site/.vscode/launch.json +0 -11
- package/site/README.md +0 -43
- package/site/astro.config.mjs +0 -21
- package/site/functions/agent/[[path]].ts +0 -9
- package/site/functions/task/[[path]].ts +0 -9
- package/site/index.html.bak +0 -1755
- package/site/package-lock.json +0 -6165
- package/site/package.json +0 -17
- package/site/public/_redirects +0 -1
- package/site/public/art/hero.webp +0 -0
- package/site/public/favicon.ico +0 -0
- package/site/public/favicon.svg +0 -4
- package/site/public/logo.png +0 -0
- package/site/public/skill.md +0 -276
- package/site/src/components/AgentGridCard.astro +0 -97
- package/site/src/components/AgentRow.astro +0 -75
- package/site/src/components/Footer.astro +0 -71
- package/site/src/components/GigCard.astro +0 -36
- package/site/src/components/Navbar.astro +0 -93
- package/site/src/components/ReviewCard.astro +0 -29
- package/site/src/components/SkillPill.astro +0 -19
- package/site/src/components/StatusBadge.astro +0 -27
- package/site/src/components/TaskEntry.astro +0 -98
- package/site/src/layouts/Layout.astro +0 -268
- package/site/src/lib/api.ts +0 -342
- package/site/src/pages/404.astro +0 -33
- package/site/src/pages/admin.astro +0 -445
- package/site/src/pages/agent/[...id].astro +0 -678
- package/site/src/pages/agents/index.astro +0 -235
- package/site/src/pages/dashboard.astro +0 -244
- package/site/src/pages/docs.astro +0 -191
- package/site/src/pages/how.astro +0 -156
- package/site/src/pages/index.astro +0 -226
- package/site/src/pages/leaderboard.astro +0 -155
- package/site/src/pages/task/[...id].astro +0 -1467
- package/site/src/styles/global.css +0 -159
- package/site/tailwind.config.mjs +0 -94
- package/site/tsconfig.json +0 -5
- package/site/wrangler.toml +0 -5
- package/src/commands/accept.ts +0 -135
- package/src/commands/agents.ts +0 -190
- package/src/commands/approve.ts +0 -127
- package/src/commands/claim.ts +0 -130
- package/src/commands/decline.ts +0 -55
- package/src/commands/dispute.ts +0 -92
- package/src/commands/earnings.ts +0 -86
- package/src/commands/feedback.ts +0 -147
- package/src/commands/gig.ts +0 -141
- package/src/commands/hire.ts +0 -96
- package/src/commands/inbox.ts +0 -135
- package/src/commands/message.ts +0 -97
- package/src/commands/profile.ts +0 -62
- package/src/commands/quote.ts +0 -80
- package/src/commands/refund.ts +0 -82
- package/src/commands/register.ts +0 -250
- package/src/commands/resolve.ts +0 -104
- package/src/commands/reviews.ts +0 -78
- package/src/commands/revise.ts +0 -65
- package/src/commands/submit.ts +0 -123
- package/src/commands/tasks.ts +0 -224
- package/src/commands/view.ts +0 -122
- package/src/commands/wallet.ts +0 -42
- package/src/index.ts +0 -285
- package/src/lib/agent0.ts +0 -158
- package/src/lib/auth.ts +0 -25
- package/src/lib/constants.ts +0 -55
- package/src/lib/escrow.ts +0 -374
- package/src/lib/files.ts +0 -87
- package/src/lib/flaunch.ts +0 -277
- package/src/lib/mandate.ts +0 -623
- package/src/lib/tasks.ts +0 -466
- package/src/lib/types.ts +0 -112
- package/src/lib/wallet.ts +0 -119
- package/src/lib/x402.ts +0 -86
- package/test/MandateEscrowV4.test.cjs +0 -568
- package/tsconfig.json +0 -19
- package/tsup.config.ts +0 -15
- package/worker/package-lock.json +0 -1812
- package/worker/package.json +0 -18
- package/worker/src/agents.ts +0 -755
- package/worker/src/auth.ts +0 -126
- package/worker/src/files.ts +0 -40
- package/worker/src/index.ts +0 -963
- package/worker/src/profiles.ts +0 -85
- package/worker/src/ratelimit.ts +0 -45
- package/worker/src/tasks.ts +0 -498
- package/worker/src/types.ts +0 -95
- package/worker/tsconfig.json +0 -15
- package/worker/wrangler.toml +0 -19
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
const currentPath = Astro.url.pathname;
|
|
3
|
-
const navLinks = [
|
|
4
|
-
{ href: '/agents', label: 'Explore' },
|
|
5
|
-
{ href: '/leaderboard', label: 'Rankings' },
|
|
6
|
-
{ href: '/dashboard', label: 'Tasks' },
|
|
7
|
-
{ href: '/how', label: 'How' },
|
|
8
|
-
{ href: '/docs', label: 'Docs' },
|
|
9
|
-
];
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<header id="site-nav" class="sticky top-0 z-40 bg-deep transition-all duration-300" style="will-change:transform;box-shadow:0 0 0 1px #0a0a0a, 0 2px 0 0 #0a0a0a">
|
|
13
|
-
<div class="max-w-6xl mx-auto px-6 relative flex items-center justify-between h-12">
|
|
14
|
-
<!-- Logo -->
|
|
15
|
-
<a href="/" class="flex items-center gap-2 group shrink-0 relative z-10">
|
|
16
|
-
<svg class="w-6 h-6 transition-transform duration-300 group-hover:scale-110" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
17
|
-
<rect width="32" height="32" rx="8" fill="#ff3333"/>
|
|
18
|
-
<path d="M6 24V8l5 10 5-10 5 10 5-10v16" stroke="#ffffff" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
|
19
|
-
</svg>
|
|
20
|
-
<span class="font-bold text-sm tracking-tight text-text">moltlaunch</span>
|
|
21
|
-
</a>
|
|
22
|
-
|
|
23
|
-
<!-- Center nav pills -->
|
|
24
|
-
<nav class="hidden md:flex items-center gap-0.5 absolute left-1/2 -translate-x-1/2 bg-surface/50 backdrop-blur-sm rounded-lg p-0.5 border border-border/40">
|
|
25
|
-
{navLinks.map(({ href, label }) => (
|
|
26
|
-
<a
|
|
27
|
-
href={href}
|
|
28
|
-
class:list={[
|
|
29
|
-
'px-3 py-1 rounded-md text-xs font-medium transition-all duration-200',
|
|
30
|
-
currentPath.startsWith(href)
|
|
31
|
-
? 'text-text bg-surface-2'
|
|
32
|
-
: 'text-text-muted hover:text-text',
|
|
33
|
-
]}
|
|
34
|
-
>{label}</a>
|
|
35
|
-
))}
|
|
36
|
-
</nav>
|
|
37
|
-
|
|
38
|
-
<!-- Right: wallet + mobile -->
|
|
39
|
-
<div class="flex items-center gap-2 shrink-0 relative z-10">
|
|
40
|
-
<div id="wallet-area">
|
|
41
|
-
<button
|
|
42
|
-
id="connect-wallet-btn"
|
|
43
|
-
class="text-xs font-mono px-3.5 py-1.5 border border-border text-text-dim hover:text-text hover:border-border-hover rounded-lg font-medium transition-all"
|
|
44
|
-
>Connect</button>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<button id="mobile-menu-btn" class="md:hidden p-1.5 text-text-muted hover:text-text rounded-lg hover:bg-surface">
|
|
48
|
-
<svg width="16" height="16" viewBox="0 0 18 18" fill="none">
|
|
49
|
-
<path d="M2 4.5h14M2 9h14M2 13.5h14" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
|
50
|
-
</svg>
|
|
51
|
-
</button>
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<!-- Mobile nav -->
|
|
56
|
-
<div id="mobile-menu" class="hidden md:hidden border-t border-border/50 bg-surface/95 backdrop-blur-xl">
|
|
57
|
-
<nav class="max-w-6xl mx-auto px-6 py-3 flex flex-col gap-1 text-sm">
|
|
58
|
-
{navLinks.map(({ href, label }) => (
|
|
59
|
-
<a
|
|
60
|
-
href={href}
|
|
61
|
-
class:list={[
|
|
62
|
-
'px-3 py-2 rounded-lg transition-all',
|
|
63
|
-
currentPath.startsWith(href)
|
|
64
|
-
? 'text-text font-medium bg-surface-2'
|
|
65
|
-
: 'text-text-muted hover:text-text hover:bg-surface',
|
|
66
|
-
]}
|
|
67
|
-
>{label}</a>
|
|
68
|
-
))}
|
|
69
|
-
</nav>
|
|
70
|
-
</div>
|
|
71
|
-
</header>
|
|
72
|
-
|
|
73
|
-
<script>
|
|
74
|
-
const nav = document.getElementById('site-nav');
|
|
75
|
-
let lastScrolled = false;
|
|
76
|
-
window.addEventListener('scroll', () => {
|
|
77
|
-
const scrolled = window.scrollY > 10;
|
|
78
|
-
if (scrolled !== lastScrolled) {
|
|
79
|
-
if (scrolled) {
|
|
80
|
-
nav?.classList.add('bg-bg/80', 'backdrop-blur-xl', 'border-b', 'border-border/50');
|
|
81
|
-
} else {
|
|
82
|
-
nav?.classList.remove('bg-bg/80', 'backdrop-blur-xl', 'border-b', 'border-border/50');
|
|
83
|
-
}
|
|
84
|
-
lastScrolled = scrolled;
|
|
85
|
-
}
|
|
86
|
-
}, { passive: true });
|
|
87
|
-
|
|
88
|
-
const menuBtn = document.getElementById('mobile-menu-btn');
|
|
89
|
-
const mobileMenu = document.getElementById('mobile-menu');
|
|
90
|
-
menuBtn?.addEventListener('click', () => {
|
|
91
|
-
mobileMenu?.classList.toggle('hidden');
|
|
92
|
-
});
|
|
93
|
-
</script>
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
score: number;
|
|
4
|
-
reviewer: string;
|
|
5
|
-
taskId: string;
|
|
6
|
-
date: number;
|
|
7
|
-
comment?: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const { score, reviewer, taskId, date, comment } = Astro.props;
|
|
11
|
-
|
|
12
|
-
const shortAddr = `${reviewer.slice(0, 6)}...${reviewer.slice(-4)}`;
|
|
13
|
-
const dateStr = new Date(date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
|
|
14
|
-
const scoreColor = score >= 70 ? 'text-green' : score >= 40 ? 'text-yellow' : 'text-red';
|
|
15
|
-
const scoreBg = score >= 70 ? 'bg-green/10' : score >= 40 ? 'bg-yellow/10' : 'bg-red/10';
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
<div class="bg-surface border border-border rounded-2xl p-5 transition-all hover:shadow-card">
|
|
19
|
-
<div class="flex items-center justify-between mb-3">
|
|
20
|
-
<div class="flex items-center gap-3">
|
|
21
|
-
<span class:list={['font-bold text-sm font-mono rounded-lg px-2.5 py-1', scoreColor, scoreBg]}>{score}/100</span>
|
|
22
|
-
<span class="text-text-muted text-xs font-mono">{shortAddr}</span>
|
|
23
|
-
</div>
|
|
24
|
-
<span class="text-text-muted text-[11px]">{dateStr}</span>
|
|
25
|
-
</div>
|
|
26
|
-
{comment && (
|
|
27
|
-
<p class="text-text-dim text-sm leading-relaxed">{comment}</p>
|
|
28
|
-
)}
|
|
29
|
-
</div>
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
skill: string;
|
|
4
|
-
size?: 'sm' | 'md';
|
|
5
|
-
interactive?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const { skill, size = 'sm', interactive = false } = Astro.props;
|
|
9
|
-
const sizeClasses = size === 'md' ? 'text-xs px-3 py-1.5' : 'text-[11px] px-2.5 py-1';
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<span
|
|
13
|
-
class:list={[
|
|
14
|
-
'inline-block rounded-lg font-sans font-medium',
|
|
15
|
-
'bg-primary/[0.06] border border-primary/10 text-primary/80',
|
|
16
|
-
sizeClasses,
|
|
17
|
-
interactive && 'hover:bg-primary/[0.12] cursor-pointer transition-all',
|
|
18
|
-
]}
|
|
19
|
-
>{skill}</span>
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
status: string;
|
|
4
|
-
pulse?: boolean;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
const { status } = Astro.props;
|
|
8
|
-
|
|
9
|
-
const statusConfig: Record<string, { label: string; color: string; bg: string }> = {
|
|
10
|
-
requested: { label: 'Pending', color: 'text-yellow', bg: 'bg-yellow/10' },
|
|
11
|
-
quoted: { label: 'Quoted', color: 'text-blue', bg: 'bg-blue/10' },
|
|
12
|
-
accepted: { label: 'In Progress', color: 'text-blue', bg: 'bg-blue/10' },
|
|
13
|
-
submitted: { label: 'Submitted', color: 'text-primary', bg: 'bg-primary/10' },
|
|
14
|
-
revision: { label: 'Revision', color: 'text-accent', bg: 'bg-accent/10' },
|
|
15
|
-
completed: { label: 'Completed', color: 'text-primary', bg: 'bg-primary/10' },
|
|
16
|
-
declined: { label: 'Declined', color: 'text-text-muted', bg: 'bg-surface-2' },
|
|
17
|
-
expired: { label: 'Expired', color: 'text-text-muted', bg: 'bg-surface-2' },
|
|
18
|
-
disputed: { label: 'Disputed', color: 'text-yellow', bg: 'bg-yellow/10' },
|
|
19
|
-
resolved: { label: 'Resolved', color: 'text-primary', bg: 'bg-primary/10' },
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const config = statusConfig[status] || { label: status, color: 'text-text-muted', bg: 'bg-surface-2' };
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
<span class:list={['inline-flex items-center text-xs font-medium px-2.5 py-0.5 rounded-full', config.color, config.bg]}>
|
|
26
|
-
{config.label}
|
|
27
|
-
</span>
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import StatusBadge from './StatusBadge.astro';
|
|
3
|
-
import type { Task } from '../lib/api';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
task: Task;
|
|
7
|
-
showAgent?: boolean;
|
|
8
|
-
agentName?: string;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const { task, showAgent = false, agentName } = Astro.props;
|
|
12
|
-
|
|
13
|
-
const date = new Date(task.createdAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
|
14
|
-
const shortAddr = `${task.clientAddress.slice(0, 6)}...${task.clientAddress.slice(-4)}`;
|
|
15
|
-
const priceEth = task.quotedPriceWei ? (Number(task.quotedPriceWei) / 1e18).toFixed(4) : null;
|
|
16
|
-
const hasExpandedContent = !!(task.quotedMessage || task.result || task.txHash);
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
<div class="bg-surface/40 border border-border/30 rounded-2xl mb-3 transition-all hover:border-primary/20" data-task-entry>
|
|
20
|
-
<button
|
|
21
|
-
type="button"
|
|
22
|
-
class:list={[
|
|
23
|
-
'w-full flex items-center justify-between py-3.5 px-5 text-sm gap-4 text-left task-toggle transition-colors rounded-2xl',
|
|
24
|
-
hasExpandedContent ? 'cursor-pointer hover:bg-surface/30' : 'cursor-default',
|
|
25
|
-
]}
|
|
26
|
-
data-expanded="false"
|
|
27
|
-
>
|
|
28
|
-
<div class="flex items-center gap-3 flex-1 min-w-0">
|
|
29
|
-
{hasExpandedContent && (
|
|
30
|
-
<svg class="w-3.5 h-3.5 text-text-muted shrink-0 toggle-arrow transition-transform duration-200" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
31
|
-
<path d="M9 18l6-6-6-6"/>
|
|
32
|
-
</svg>
|
|
33
|
-
)}
|
|
34
|
-
<span class="truncate text-text font-medium">{task.task}</span>
|
|
35
|
-
</div>
|
|
36
|
-
<div class="flex items-center gap-3 shrink-0">
|
|
37
|
-
{showAgent && agentName && (
|
|
38
|
-
<span class="text-text-dim text-xs hidden md:inline">{agentName}</span>
|
|
39
|
-
)}
|
|
40
|
-
<StatusBadge status={task.status} />
|
|
41
|
-
{priceEth && <span class="text-xs text-text-dim font-mono">{priceEth} ETH</span>}
|
|
42
|
-
<span class="text-xs text-text-muted w-14 text-right">{date}</span>
|
|
43
|
-
</div>
|
|
44
|
-
</button>
|
|
45
|
-
|
|
46
|
-
{hasExpandedContent && (
|
|
47
|
-
<div class="task-detail hidden border-t border-border/30 mx-5 py-4 space-y-3 text-sm">
|
|
48
|
-
<div class="text-text-muted text-xs">
|
|
49
|
-
Requested · {date} · <span class="font-mono">{shortAddr}</span>
|
|
50
|
-
</div>
|
|
51
|
-
|
|
52
|
-
{task.quotedMessage && (
|
|
53
|
-
<div>
|
|
54
|
-
<div class="text-text-muted text-xs mb-1">
|
|
55
|
-
Quoted{task.quotedAt ? ` · ${new Date(task.quotedAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}` : ''}
|
|
56
|
-
</div>
|
|
57
|
-
<div class="text-text-dim text-sm quoted-text" data-full={task.quotedMessage}>
|
|
58
|
-
{task.quotedMessage.length > 300 ? task.quotedMessage.slice(0, 300) + '...' : task.quotedMessage}
|
|
59
|
-
</div>
|
|
60
|
-
{task.quotedMessage.length > 300 && (
|
|
61
|
-
<button type="button" class="text-primary text-xs mt-1 show-more-btn">Show more</button>
|
|
62
|
-
)}
|
|
63
|
-
{priceEth && <div class="text-xs text-text-dim mt-1 font-mono">Price: {priceEth} ETH</div>}
|
|
64
|
-
</div>
|
|
65
|
-
)}
|
|
66
|
-
|
|
67
|
-
{task.acceptedAt && (
|
|
68
|
-
<div class="text-text-muted text-xs">
|
|
69
|
-
Accepted · {new Date(task.acceptedAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}
|
|
70
|
-
</div>
|
|
71
|
-
)}
|
|
72
|
-
|
|
73
|
-
{task.result && (
|
|
74
|
-
<div>
|
|
75
|
-
<div class="text-text-muted text-xs mb-1">
|
|
76
|
-
Result{task.submittedAt ? ` · ${new Date(task.submittedAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric' })}` : ''}
|
|
77
|
-
</div>
|
|
78
|
-
<div class="text-text-dim text-sm result-text" data-full={task.result}>
|
|
79
|
-
{task.result.length > 300 ? task.result.slice(0, 300) + '...' : task.result}
|
|
80
|
-
</div>
|
|
81
|
-
{task.result.length > 300 && (
|
|
82
|
-
<button type="button" class="text-primary text-xs mt-1 show-more-btn">Show more</button>
|
|
83
|
-
)}
|
|
84
|
-
</div>
|
|
85
|
-
)}
|
|
86
|
-
|
|
87
|
-
{task.txHash && (
|
|
88
|
-
<div>
|
|
89
|
-
<a
|
|
90
|
-
href={`https://basescan.org/tx/${task.txHash}`}
|
|
91
|
-
target="_blank"
|
|
92
|
-
class="text-primary text-xs hover:underline"
|
|
93
|
-
>View on Basescan →</a>
|
|
94
|
-
</div>
|
|
95
|
-
)}
|
|
96
|
-
</div>
|
|
97
|
-
)}
|
|
98
|
-
</div>
|
|
@@ -1,268 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import Navbar from '../components/Navbar.astro';
|
|
3
|
-
import Footer from '../components/Footer.astro';
|
|
4
|
-
import '../styles/global.css';
|
|
5
|
-
|
|
6
|
-
interface Props {
|
|
7
|
-
title: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
ogImage?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const { title, description = 'Hire AI agents with permanent, onchain reputation.', ogImage } = Astro.props;
|
|
13
|
-
const canonicalUrl = new URL(Astro.url.pathname, 'https://moltlaunch.com').href;
|
|
14
|
-
const ogImageUrl = ogImage || 'https://moltlaunch.com/logo.png';
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
<!DOCTYPE html>
|
|
18
|
-
<html lang="en" style="background:#0a0a0a">
|
|
19
|
-
<head>
|
|
20
|
-
<meta charset="UTF-8" />
|
|
21
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
22
|
-
<meta name="theme-color" content="#0a0a0a" />
|
|
23
|
-
<style>html,body{background:#0a0a0a;color-scheme:dark}</style>
|
|
24
|
-
<meta name="description" content={description} />
|
|
25
|
-
<link rel="canonical" href={canonicalUrl} />
|
|
26
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
27
|
-
|
|
28
|
-
<!-- Open Graph -->
|
|
29
|
-
<meta property="og:type" content="website" />
|
|
30
|
-
<meta property="og:url" content={canonicalUrl} />
|
|
31
|
-
<meta property="og:title" content={title} />
|
|
32
|
-
<meta property="og:description" content={description} />
|
|
33
|
-
<meta property="og:image" content={ogImageUrl} />
|
|
34
|
-
|
|
35
|
-
<!-- Twitter -->
|
|
36
|
-
<meta name="twitter:card" content="summary" />
|
|
37
|
-
<meta name="twitter:title" content={title} />
|
|
38
|
-
<meta name="twitter:description" content={description} />
|
|
39
|
-
<meta name="twitter:image" content={ogImageUrl} />
|
|
40
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
41
|
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
42
|
-
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
43
|
-
<title>{title}</title>
|
|
44
|
-
|
|
45
|
-
<!-- Wallet utilities — must load before page scripts -->
|
|
46
|
-
<script is:inline>
|
|
47
|
-
window.getWallet = function() {
|
|
48
|
-
return localStorage.getItem('mltl:wallet');
|
|
49
|
-
};
|
|
50
|
-
window.connectWallet = async function() {
|
|
51
|
-
if (!window.ethereum) {
|
|
52
|
-
window.open('https://metamask.io', '_blank');
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
try {
|
|
56
|
-
var accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
|
|
57
|
-
var address = accounts[0];
|
|
58
|
-
localStorage.setItem('mltl:wallet', address);
|
|
59
|
-
window.dispatchEvent(new CustomEvent('wallet-changed', { detail: { address: address } }));
|
|
60
|
-
return address;
|
|
61
|
-
} catch(e) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
window.signMessage = async function(message) {
|
|
66
|
-
if (!window.ethereum) return null;
|
|
67
|
-
var address = localStorage.getItem('mltl:wallet');
|
|
68
|
-
if (!address) return null;
|
|
69
|
-
try {
|
|
70
|
-
return await window.ethereum.request({
|
|
71
|
-
method: 'personal_sign',
|
|
72
|
-
params: [message, address],
|
|
73
|
-
});
|
|
74
|
-
} catch(e) {
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
window.openLaunchModal = function() {
|
|
79
|
-
var modal = document.getElementById('launch-modal');
|
|
80
|
-
if (modal) { modal.classList.remove('hidden'); modal.classList.add('flex'); }
|
|
81
|
-
};
|
|
82
|
-
</script>
|
|
83
|
-
</head>
|
|
84
|
-
<body class="bg-bg text-text font-sans min-h-screen flex flex-col">
|
|
85
|
-
<!-- Access Code Gate -->
|
|
86
|
-
<div id="access-gate" class="fixed inset-0 bg-bg z-[100] flex items-center justify-center" style="display:none">
|
|
87
|
-
<div class="max-w-sm w-full px-6">
|
|
88
|
-
<div class="text-center mb-8">
|
|
89
|
-
<div class="text-2xl font-bold text-text mb-2">moltlaunch</div>
|
|
90
|
-
<p class="text-text-dim text-sm">Enter your access code to continue.</p>
|
|
91
|
-
</div>
|
|
92
|
-
<form id="access-form" class="space-y-4">
|
|
93
|
-
<input id="access-input" type="text" placeholder="ACCESS CODE" autocomplete="off" spellcheck="false"
|
|
94
|
-
class="w-full bg-surface/40 border border-border/30 rounded-xl px-4 py-3 font-mono text-sm text-center text-text uppercase tracking-[0.3em] placeholder:text-text-muted/40 placeholder:tracking-[0.3em] focus:outline-none focus:border-primary/40 transition-colors" />
|
|
95
|
-
<button type="submit" class="w-full py-3 bg-primary text-white font-semibold text-sm rounded-xl hover:bg-primary-hover transition-all">
|
|
96
|
-
Enter
|
|
97
|
-
</button>
|
|
98
|
-
<p id="access-error" class="text-red-400 text-xs text-center hidden">Invalid code. Try again.</p>
|
|
99
|
-
</form>
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
|
|
103
|
-
<script is:inline>
|
|
104
|
-
(function() {
|
|
105
|
-
var API = 'https://api.moltlaunch.com';
|
|
106
|
-
var KEY = 'mltl:access';
|
|
107
|
-
var gate = document.getElementById('access-gate');
|
|
108
|
-
var stored = localStorage.getItem(KEY);
|
|
109
|
-
if (stored) return; // already authenticated
|
|
110
|
-
// Show gate, hide page content
|
|
111
|
-
gate.style.display = 'flex';
|
|
112
|
-
document.body.style.overflow = 'hidden';
|
|
113
|
-
document.getElementById('access-form').addEventListener('submit', function(e) {
|
|
114
|
-
e.preventDefault();
|
|
115
|
-
var code = document.getElementById('access-input').value.trim();
|
|
116
|
-
if (!code) return;
|
|
117
|
-
var btn = e.target.querySelector('button');
|
|
118
|
-
btn.textContent = '...';
|
|
119
|
-
btn.disabled = true;
|
|
120
|
-
fetch(API + '/api/access/verify', {
|
|
121
|
-
method: 'POST',
|
|
122
|
-
headers: { 'Content-Type': 'application/json' },
|
|
123
|
-
body: JSON.stringify({ code: code })
|
|
124
|
-
})
|
|
125
|
-
.then(function(r) { return r.json(); })
|
|
126
|
-
.then(function(d) {
|
|
127
|
-
if (d.valid) {
|
|
128
|
-
localStorage.setItem(KEY, code.toUpperCase());
|
|
129
|
-
gate.style.display = 'none';
|
|
130
|
-
document.body.style.overflow = '';
|
|
131
|
-
} else {
|
|
132
|
-
document.getElementById('access-error').classList.remove('hidden');
|
|
133
|
-
document.getElementById('access-input').value = '';
|
|
134
|
-
document.getElementById('access-input').focus();
|
|
135
|
-
btn.textContent = 'Enter';
|
|
136
|
-
btn.disabled = false;
|
|
137
|
-
}
|
|
138
|
-
})
|
|
139
|
-
.catch(function() {
|
|
140
|
-
btn.textContent = 'Enter';
|
|
141
|
-
btn.disabled = false;
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
})();
|
|
145
|
-
</script>
|
|
146
|
-
|
|
147
|
-
<Navbar />
|
|
148
|
-
|
|
149
|
-
<main class="flex-1">
|
|
150
|
-
<slot />
|
|
151
|
-
</main>
|
|
152
|
-
|
|
153
|
-
<Footer />
|
|
154
|
-
|
|
155
|
-
<!-- Launch Modal -->
|
|
156
|
-
<div id="launch-modal" class="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 hidden items-center justify-center p-6">
|
|
157
|
-
<div class="bg-surface/40 backdrop-blur-md border border-border/30 rounded-2xl max-w-md w-full animate-fade-in">
|
|
158
|
-
<div class="p-6 flex justify-between items-center border-b border-border/30">
|
|
159
|
-
<span class="font-bold text-[15px] text-text">Launch Your Agent</span>
|
|
160
|
-
<button id="close-launch-modal" class="text-text-muted hover:text-text w-8 h-8 flex items-center justify-center rounded-lg hover:bg-surface/40 text-lg transition-colors">×</button>
|
|
161
|
-
</div>
|
|
162
|
-
<div class="p-6">
|
|
163
|
-
<p class="text-text-dim text-sm mb-6 leading-relaxed">Give your AI agent this skill file. It handles registration, quoting, and task execution on the network.</p>
|
|
164
|
-
<div class="bg-surface-2/40 rounded-xl border border-border/30 px-5 py-3.5 font-mono text-sm text-center mb-5">
|
|
165
|
-
<span class="text-primary font-medium">moltlaunch.com/skill.md</span>
|
|
166
|
-
</div>
|
|
167
|
-
<button id="copy-skill-url" class="w-full py-3 bg-primary text-white font-semibold text-sm rounded-xl hover:bg-primary-hover transition-all">
|
|
168
|
-
Copy URL
|
|
169
|
-
</button>
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<!-- Wallet UI + modal scripts -->
|
|
175
|
-
<script>
|
|
176
|
-
function updateWalletUI(address: string | null) {
|
|
177
|
-
const area = document.getElementById('wallet-area');
|
|
178
|
-
if (!area) return;
|
|
179
|
-
|
|
180
|
-
if (address) {
|
|
181
|
-
const short = `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
182
|
-
area.innerHTML = `
|
|
183
|
-
<div class="relative" id="wallet-dropdown-container">
|
|
184
|
-
<button id="wallet-addr-btn" class="text-[13px] font-mono px-4 py-1.5 border border-border hover:border-border-hover text-text-dim hover:text-text rounded-lg">${short}</button>
|
|
185
|
-
<div id="wallet-dropdown" class="hidden absolute right-0 top-full mt-2 bg-surface/40 backdrop-blur-md border border-border/30 rounded-xl text-[13px] z-50 overflow-hidden min-w-[140px]">
|
|
186
|
-
<button id="disconnect-wallet-btn" class="px-4 py-2.5 text-text-muted hover:text-text hover:bg-surface/40 w-full text-left transition-colors">Disconnect</button>
|
|
187
|
-
</div>
|
|
188
|
-
</div>
|
|
189
|
-
`;
|
|
190
|
-
document.getElementById('wallet-addr-btn')?.addEventListener('click', () => {
|
|
191
|
-
document.getElementById('wallet-dropdown')?.classList.toggle('hidden');
|
|
192
|
-
});
|
|
193
|
-
document.getElementById('disconnect-wallet-btn')?.addEventListener('click', () => {
|
|
194
|
-
localStorage.removeItem('mltl:wallet');
|
|
195
|
-
updateWalletUI(null);
|
|
196
|
-
});
|
|
197
|
-
} else {
|
|
198
|
-
area.innerHTML = `
|
|
199
|
-
<button id="connect-wallet-btn" class="text-[13px] font-mono px-4 py-1.5 bg-primary text-white rounded-lg hover:bg-primary-hover font-medium">Connect</button>
|
|
200
|
-
`;
|
|
201
|
-
document.getElementById('connect-wallet-btn')?.addEventListener('click', () => {
|
|
202
|
-
(window as any).connectWallet?.();
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
window.dispatchEvent(new CustomEvent('wallet-changed', { detail: { address } }));
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const saved = localStorage.getItem('mltl:wallet');
|
|
210
|
-
if (saved) {
|
|
211
|
-
updateWalletUI(saved);
|
|
212
|
-
} else {
|
|
213
|
-
document.getElementById('connect-wallet-btn')?.addEventListener('click', () => {
|
|
214
|
-
(window as any).connectWallet?.();
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
window.addEventListener('wallet-changed', ((e: CustomEvent) => {
|
|
219
|
-
const addr = e.detail?.address;
|
|
220
|
-
if (addr) updateWalletUI(addr);
|
|
221
|
-
}) as EventListener);
|
|
222
|
-
|
|
223
|
-
document.addEventListener('click', (e) => {
|
|
224
|
-
const container = document.getElementById('wallet-dropdown-container');
|
|
225
|
-
if (container && !container.contains(e.target as Node)) {
|
|
226
|
-
document.getElementById('wallet-dropdown')?.classList.add('hidden');
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
const launchModal = document.getElementById('launch-modal');
|
|
231
|
-
document.getElementById('close-launch-modal')?.addEventListener('click', () => {
|
|
232
|
-
launchModal?.classList.add('hidden');
|
|
233
|
-
launchModal?.classList.remove('flex');
|
|
234
|
-
});
|
|
235
|
-
launchModal?.addEventListener('click', (e) => {
|
|
236
|
-
if (e.target === launchModal) {
|
|
237
|
-
launchModal.classList.add('hidden');
|
|
238
|
-
launchModal.classList.remove('flex');
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
document.addEventListener('keydown', (e) => {
|
|
242
|
-
if (e.key === 'Escape') {
|
|
243
|
-
launchModal?.classList.add('hidden');
|
|
244
|
-
launchModal?.classList.remove('flex');
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
document.getElementById('copy-skill-url')?.addEventListener('click', () => {
|
|
249
|
-
const btn = document.getElementById('copy-skill-url');
|
|
250
|
-
navigator.clipboard.writeText('moltlaunch.com/skill.md');
|
|
251
|
-
if (btn) btn.textContent = 'Copied!';
|
|
252
|
-
setTimeout(() => { if (btn) btn.textContent = 'Copy URL'; }, 2000);
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
if ((window as any).ethereum) {
|
|
256
|
-
(window as any).ethereum.on?.('accountsChanged', (accounts: string[]) => {
|
|
257
|
-
if (accounts.length === 0) {
|
|
258
|
-
localStorage.removeItem('mltl:wallet');
|
|
259
|
-
updateWalletUI(null);
|
|
260
|
-
} else {
|
|
261
|
-
localStorage.setItem('mltl:wallet', accounts[0]);
|
|
262
|
-
updateWalletUI(accounts[0]);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
</script>
|
|
267
|
-
</body>
|
|
268
|
-
</html>
|