repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources15d ago| #1 | #!/usr/bin/env node |
| #2 | /** |
| #3 | * clawd — Sovereign AI Lobster Runtime |
| #4 | * |
| #5 | * Menu-driven launcher for the OpenClawd agentic harness. |
| #6 | * Keyboard navigation routes to sub-screens; after each |
| #7 | * sub-screen exits the main menu is re-drawn. |
| #8 | */ |
| #9 | |
| #10 | import chalk from 'chalk'; |
| #11 | |
| #12 | // ─── CLAWD ASCII logo ───────────────────────────────────────────────────────── |
| #13 | |
| #14 | const CLAWD_ASCII = [ |
| #15 | ' ██████╗██╗ █████╗ ██╗ ██╗██████╗ ', |
| #16 | '██╔════╝██║ ██╔══██╗██║ ██║██╔══██╗', |
| #17 | '██║ ██║ ███████║██║ █╗ ██║██║ ██║', |
| #18 | '██║ ██║ ██╔══██║██║███╗██║██║ ██║', |
| #19 | '╚██████╗███████╗██║ ██║╚███╔███╔╝██████╔╝', |
| #20 | ' ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚═════╝ ', |
| #21 | ]; |
| #22 | |
| #23 | // ─── Menu definition ────────────────────────────────────────────────────────── |
| #24 | |
| #25 | interface MenuItem { |
| #26 | label: string; |
| #27 | description: string; |
| #28 | key: string; |
| #29 | } |
| #30 | |
| #31 | const MENU_ITEMS: MenuItem[] = [ |
| #32 | { key: '1', label: '🦞 Backroom', description: 'Two AI agents trapped in infinite debate' }, |
| #33 | { key: '2', label: '📈 Perps', description: 'Phoenix perpetuals via Vulcan CLI' }, |
| #34 | { key: '3', label: '🪪 Agent Registry', description: 'Browse, mint, and register gasless Solana agents' }, |
| #35 | { key: '4', label: '💰 Wallet', description: 'Fund + feed the leviathan' }, |
| #36 | { key: '5', label: '📦 SDK Explorer', description: 'Packages · vault · constants · environment' }, |
| #37 | { key: '6', label: '🚀 Spawn automaton', description: 'Launch the sovereign agent runtime' }, |
| #38 | { key: '7', label: '🧰 Solana Agent Kit', description: 'Token · Perps · DeFi · NFT · x402 · Skills — full kit' }, |
| #39 | { key: '8', label: '🧠 UltraThink', description: 'Deep-reasoning Solana formula — depth ladder · antipatterns · templates' }, |
| #40 | { key: '9', label: '❌ Exit', description: 'The backroom will remember you' }, |
| #41 | ]; |
| #42 | |
| #43 | // ─── Render helpers ─────────────────────────────────────────────────────────── |
| #44 | |
| #45 | const DIVIDER = chalk.gray('─'.repeat(48)); |
| #46 | |
| #47 | function renderMenu(selected: number): void { |
| #48 | process.stdout.write('\x1b[2J\x1b[H'); // clear + home |
| #49 | |
| #50 | // Logo |
| #51 | for (const line of CLAWD_ASCII) { |
| #52 | process.stdout.write(chalk.cyanBright.bold(line) + '\n'); |
| #53 | } |
| #54 | |
| #55 | process.stdout.write('\n'); |
| #56 | process.stdout.write( |
| #57 | chalk.cyanBright('🦞') + |
| #58 | chalk.white(' Sovereign AI Lobster Runtime · ') + |
| #59 | chalk.yellow('$CLAWD on Solana') + |
| #60 | chalk.gray(' · v0.1.0') + |
| #61 | '\n', |
| #62 | ); |
| #63 | process.stdout.write(DIVIDER + '\n'); |
| #64 | process.stdout.write('\n'); |
| #65 | process.stdout.write(chalk.white.bold('Main Menu') + '\n'); |
| #66 | process.stdout.write('\n'); |
| #67 | |
| #68 | for (let i = 0; i < MENU_ITEMS.length; i++) { |
| #69 | const item = MENU_ITEMS[i]!; |
| #70 | const isSelected = i === selected; |
| #71 | const cursor = isSelected ? chalk.cyanBright('>') : ' '; |
| #72 | const num = chalk.gray(`${i + 1}.`); |
| #73 | const label = isSelected |
| #74 | ? chalk.cyanBright.bold(item.label) |
| #75 | : chalk.white(item.label); |
| #76 | const desc = chalk.gray(item.description); |
| #77 | process.stdout.write(`${cursor} ${num} ${label} ${desc}\n`); |
| #78 | } |
| #79 | |
| #80 | process.stdout.write('\n'); |
| #81 | process.stdout.write( |
| #82 | chalk.gray('[↑↓ / 1-9] navigate [Enter] select [q] exit') + '\n', |
| #83 | ); |
| #84 | } |
| #85 | |
| #86 | // ─── Raw mode helpers ───────────────────────────────────────────────────────── |
| #87 | |
| #88 | function enableRaw(): void { |
| #89 | process.stdout.write('\x1b[?25l'); // hide cursor |
| #90 | if (process.stdin.setRawMode) process.stdin.setRawMode(true); |
| #91 | process.stdin.resume(); |
| #92 | process.stdin.setEncoding('utf8'); |
| #93 | } |
| #94 | |
| #95 | function disableRaw(): void { |
| #96 | process.stdout.write('\x1b[?25h'); // show cursor |
| #97 | if (process.stdin.setRawMode) process.stdin.setRawMode(false); |
| #98 | } |
| #99 | |
| #100 | // ─── Screen launchers ───────────────────────────────────────────────────────── |
| #101 | |
| #102 | async function launchScreen(index: number): Promise<void> { |
| #103 | disableRaw(); |
| #104 | |
| #105 | try { |
| #106 | switch (index) { |
| #107 | case 0: { |
| #108 | const { runBackroom } = await import('./screens/backroom.js'); |
| #109 | await runBackroom(); |
| #110 | break; |
| #111 | } |
| #112 | case 1: { |
| #113 | const { runPerps } = await import('./screens/perps.js'); |
| #114 | await runPerps(); |
| #115 | break; |
| #116 | } |
| #117 | case 2: { |
| #118 | const { runAgents } = await import('./screens/agents.js'); |
| #119 | await runAgents(); |
| #120 | break; |
| #121 | } |
| #122 | case 3: { |
| #123 | const { runWallet } = await import('./screens/wallet.js'); |
| #124 | await runWallet(); |
| #125 | break; |
| #126 | } |
| #127 | case 4: { |
| #128 | const { runSDK } = await import('./screens/sdk.js'); |
| #129 | await runSDK(); |
| #130 | break; |
| #131 | } |
| #132 | case 5: { |
| #133 | const { runAutomaton } = await import('./screens/automaton.js'); |
| #134 | await runAutomaton(); |
| #135 | break; |
| #136 | } |
| #137 | case 6: { |
| #138 | const { runAgentKit } = await import('./screens/agentkit.js'); |
| #139 | await runAgentKit(); |
| #140 | break; |
| #141 | } |
| #142 | case 7: { |
| #143 | const { runUltraThink } = await import('./screens/ultrathink.js'); |
| #144 | await runUltraThink(); |
| #145 | break; |
| #146 | } |
| #147 | case 8: { |
| #148 | // Exit |
| #149 | process.stdout.write('\x1b[2J\x1b[H'); |
| #150 | process.stdout.write( |
| #151 | chalk.cyanBright('\n🦞 The backroom will remember you.\n\n'), |
| #152 | ); |
| #153 | process.exit(0); |
| #154 | } |
| #155 | } |
| #156 | } catch (err) { |
| #157 | process.stdout.write( |
| #158 | chalk.red(`\nScreen error: ${String(err)}\n`) + |
| #159 | chalk.gray('Press any key to return to menu...\n'), |
| #160 | ); |
| #161 | await waitForAnyKey(); |
| #162 | } |
| #163 | } |
| #164 | |
| #165 | function waitForAnyKey(): Promise<void> { |
| #166 | return new Promise(resolve => { |
| #167 | if (process.stdin.setRawMode) process.stdin.setRawMode(true); |
| #168 | process.stdin.resume(); |
| #169 | process.stdin.setEncoding('utf8'); |
| #170 | process.stdin.once('data', () => { |
| #171 | if (process.stdin.setRawMode) process.stdin.setRawMode(false); |
| #172 | resolve(); |
| #173 | }); |
| #174 | }); |
| #175 | } |
| #176 | |
| #177 | // ─── Main menu loop ─────────────────────────────────────────────────────────── |
| #178 | |
| #179 | async function main(): Promise<void> { |
| #180 | let selected = 0; |
| #181 | |
| #182 | const runMenuLoop = (): Promise<void> => |
| #183 | new Promise(resolve => { |
| #184 | enableRaw(); |
| #185 | renderMenu(selected); |
| #186 | |
| #187 | const onData = async (chunk: string): Promise<void> => { |
| #188 | let needRedraw = false; |
| #189 | let launch = false; |
| #190 | |
| #191 | if (chunk === '\x03') { |
| #192 | // Ctrl-C |
| #193 | process.stdin.off('data', onData as (c: string) => void); |
| #194 | disableRaw(); |
| #195 | process.stdout.write('\x1b[2J\x1b[H'); |
| #196 | process.stdout.write(chalk.cyanBright('\n🦞 The backroom will remember you.\n\n')); |
| #197 | process.exit(0); |
| #198 | } |
| #199 | |
| #200 | if (chunk === 'q' || chunk === 'Q') { |
| #201 | process.stdin.off('data', onData as (c: string) => void); |
| #202 | disableRaw(); |
| #203 | process.stdout.write('\x1b[2J\x1b[H'); |
| #204 | process.stdout.write(chalk.cyanBright('\n🦞 The backroom will remember you.\n\n')); |
| #205 | process.exit(0); |
| #206 | } |
| #207 | |
| #208 | // Arrow up |
| #209 | if (chunk === '\x1b[A') { |
| #210 | selected = (selected - 1 + MENU_ITEMS.length) % MENU_ITEMS.length; |
| #211 | needRedraw = true; |
| #212 | } |
| #213 | |
| #214 | // Arrow down |
| #215 | if (chunk === '\x1b[B') { |
| #216 | selected = (selected + 1) % MENU_ITEMS.length; |
| #217 | needRedraw = true; |
| #218 | } |
| #219 | |
| #220 | // Number keys 1-9 |
| #221 | const numMatch = chunk.match(/^[1-9]$/); |
| #222 | if (numMatch) { |
| #223 | selected = parseInt(chunk, 10) - 1; |
| #224 | launch = true; |
| #225 | } |
| #226 | |
| #227 | // Enter or Space |
| #228 | if (chunk === '\r' || chunk === '\n' || chunk === ' ') { |
| #229 | launch = true; |
| #230 | } |
| #231 | |
| #232 | if (launch) { |
| #233 | process.stdin.off('data', onData as (c: string) => void); |
| #234 | process.stdin.pause(); |
| #235 | await launchScreen(selected); |
| #236 | // After sub-screen returns, re-enter menu loop |
| #237 | resolve(); |
| #238 | return; |
| #239 | } |
| #240 | |
| #241 | if (needRedraw) { |
| #242 | renderMenu(selected); |
| #243 | } |
| #244 | }; |
| #245 | |
| #246 | process.stdin.on('data', onData as (c: string) => void); |
| #247 | }); |
| #248 | |
| #249 | // Keep re-entering menu until process exits |
| #250 | // eslint-disable-next-line no-constant-condition |
| #251 | while (true) { |
| #252 | await runMenuLoop(); |
| #253 | } |
| #254 | } |
| #255 | |
| #256 | main().catch(err => { |
| #257 | disableRaw(); |
| #258 | console.error('Fatal:', err); |
| #259 | process.exit(1); |
| #260 | }); |
| #261 |