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 sources16d ago| #1 | /** |
| #2 | * clawd — SDK Explorer Screen |
| #3 | * |
| #4 | * Shows live status of all OpenClawd monorepo packages, wallet vault contents, |
| #5 | * environment variables, and SDK constants (program IDs, mint addresses). |
| #6 | * |
| #7 | * Keys: [tab] cycle section [b/Esc] back to menu |
| #8 | */ |
| #9 | |
| #10 | import chalk from 'chalk'; |
| #11 | import { |
| #12 | loadPackageInfo, |
| #13 | readVaultInfo, |
| #14 | probeEnv, |
| #15 | CLAWD_MINT, |
| #16 | CLAWD_PROTOCOL_PROGRAM, |
| #17 | DBC_PROGRAM, |
| #18 | USDC_MINT, |
| #19 | TOKEN_2022_PROGRAM, |
| #20 | shortAddress, |
| #21 | type PackageInfo, |
| #22 | type VaultInfo, |
| #23 | type EnvProbe, |
| #24 | } from '../sdk.js'; |
| #25 | |
| #26 | // ─── Display helpers ────────────────────────────────────────────────────────── |
| #27 | |
| #28 | const W = 110; |
| #29 | |
| #30 | function clr(): void { |
| #31 | process.stdout.write('\x1b[2J\x1b[H'); |
| #32 | } |
| #33 | |
| #34 | function box(title: string, lines: string[]): string[] { |
| #35 | const inner = W - 2; |
| #36 | const titleFmt = ` ${chalk.cyanBright.bold(title)} `; |
| #37 | const titleLen = title.length + 2; |
| #38 | const left = Math.floor((inner - titleLen) / 2); |
| #39 | const right = inner - titleLen - left; |
| #40 | const top = chalk.cyan('╔') + chalk.cyan('═'.repeat(left)) + titleFmt + chalk.cyan('═'.repeat(right)) + chalk.cyan('╗'); |
| #41 | const bot = chalk.cyan('╚') + chalk.cyan('═'.repeat(inner)) + chalk.cyan('╝'); |
| #42 | const out = [top]; |
| #43 | for (const l of lines) { |
| #44 | const vis = l.replace(/\x1b\[[0-9;]*m/g, '').length; |
| #45 | const pad = Math.max(0, inner - 1 - vis); |
| #46 | out.push(chalk.cyan('║') + ' ' + l + ' '.repeat(pad) + chalk.cyan('║')); |
| #47 | } |
| #48 | out.push(bot); |
| #49 | return out; |
| #50 | } |
| #51 | |
| #52 | function row(label: string, value: string, labelW = 24): string { |
| #53 | return chalk.gray(label.padEnd(labelW)) + chalk.white(value); |
| #54 | } |
| #55 | |
| #56 | function shortAddr(addr: string): string { |
| #57 | return shortAddress(addr); |
| #58 | } |
| #59 | |
| #60 | // ─── Section renderers ──────────────────────────────────────────────────────── |
| #61 | |
| #62 | function renderPackages(pkgs: PackageInfo[]): string[] { |
| #63 | const lines: string[] = []; |
| #64 | lines.push(chalk.gray(' Name Ver Dist Binaries')); |
| #65 | lines.push(chalk.gray(' ' + '─'.repeat(76))); |
| #66 | for (const p of pkgs) { |
| #67 | const icon = p.status === 'ok' ? chalk.green('●') : p.status === 'no-dist' ? chalk.yellow('◐') : chalk.red('○'); |
| #68 | const name = p.name.slice(0, 34).padEnd(34); |
| #69 | const ver = p.version.padEnd(8); |
| #70 | const dist = p.hasDist ? chalk.green('YES ') : chalk.red(' NO '); |
| #71 | const bins = p.binaries.slice(0, 3).join(', '); |
| #72 | lines.push(` ${icon} ${chalk.white(name)} ${chalk.yellow(ver)} ${dist} ${chalk.gray(bins)}`); |
| #73 | } |
| #74 | return box('OPENCLAWD PACKAGES', lines); |
| #75 | } |
| #76 | |
| #77 | function renderConstants(): string[] { |
| #78 | const lines = [ |
| #79 | row('$CLAWD mint', CLAWD_MINT), |
| #80 | row('CLAWD Protocol', shortAddr(CLAWD_PROTOCOL_PROGRAM)), |
| #81 | row('DBC Program', shortAddr(DBC_PROGRAM)), |
| #82 | row('USDC mint', shortAddr(USDC_MINT)), |
| #83 | row('Token-2022 Program', shortAddr(TOKEN_2022_PROGRAM)), |
| #84 | '', |
| #85 | chalk.gray(' ─── Curve Math ─────────────────────────────────────────'), |
| #86 | row('MIN_FEE_BPS', '25 (0.25%)'), |
| #87 | row('MAX_FEE_BPS', '9900 (99%)'), |
| #88 | row('BOT_THRESHOLD','Score ≥ 80 → classified as bot'), |
| #89 | row('CONVICTION', 'time × amount × consistency'), |
| #90 | '', |
| #91 | chalk.gray(' ─── Token Standards ─────────────────────────────────────'), |
| #92 | row('SPL Token', 'Standard transfers'), |
| #93 | row('Token-2022', 'Transfer hooks, confidential, fee-on-transfer'), |
| #94 | row('pToken', 'Transfer-hook-gated programmable token'), |
| #95 | ]; |
| #96 | return box('SDK CONSTANTS & ADDRESSES', lines); |
| #97 | } |
| #98 | |
| #99 | function renderVault(vault: VaultInfo): string[] { |
| #100 | const lines: string[] = []; |
| #101 | if (!vault.available) { |
| #102 | lines.push(chalk.red(` Vault unavailable: ${vault.error ?? 'unknown error'}`)); |
| #103 | lines.push(chalk.gray(` Path: ${vault.path}`)); |
| #104 | lines.push(''); |
| #105 | lines.push(chalk.gray(' To create a vault:')); |
| #106 | lines.push(chalk.white(' npx agentwallet keygen --label my-wallet --chain solana')); |
| #107 | lines.push(''); |
| #108 | lines.push(chalk.gray(' Or set VAULT_PASSPHRASE + use the clawd fund command.')); |
| #109 | } else { |
| #110 | lines.push(row('Vault path', vault.path)); |
| #111 | lines.push(row('Wallets found', String(vault.wallets.length))); |
| #112 | lines.push(''); |
| #113 | if (vault.wallets.length === 0) { |
| #114 | lines.push(chalk.yellow(' No wallets in vault — run: agentwallet keygen')); |
| #115 | } else { |
| #116 | lines.push(chalk.gray(' Label Chain Address Status')); |
| #117 | lines.push(chalk.gray(' ' + '─'.repeat(72))); |
| #118 | for (const w of vault.wallets.slice(0, 10)) { |
| #119 | const icon = w.paused ? chalk.red('⏸') : chalk.green('▶'); |
| #120 | const label = w.label.slice(0, 22).padEnd(22); |
| #121 | const chain = w.chainType.padEnd(8); |
| #122 | const addr = shortAddr(w.address); |
| #123 | lines.push(` ${icon} ${chalk.white(label)} ${chalk.cyan(chain)} ${chalk.yellow(addr)}`); |
| #124 | } |
| #125 | if (vault.wallets.length > 10) { |
| #126 | lines.push(chalk.gray(` … and ${vault.wallets.length - 10} more`)); |
| #127 | } |
| #128 | } |
| #129 | } |
| #130 | return box('AGENTWALLET VAULT', lines); |
| #131 | } |
| #132 | |
| #133 | function renderEnv(probes: EnvProbe[]): string[] { |
| #134 | const lines: string[] = []; |
| #135 | lines.push(chalk.gray(' Variable Status Preview / Value')); |
| #136 | lines.push(chalk.gray(' ' + '─'.repeat(72))); |
| #137 | for (const p of probes) { |
| #138 | const icon = p.set ? chalk.green('✔') : chalk.red('✘'); |
| #139 | const key = p.key.padEnd(26); |
| #140 | const status = p.set ? chalk.green('SET ') : chalk.red('UNSET'); |
| #141 | const preview = p.preview ? chalk.gray(p.preview) : ''; |
| #142 | lines.push(` ${icon} ${chalk.white(key)} ${status} ${preview}`); |
| #143 | } |
| #144 | return box('ENVIRONMENT', lines); |
| #145 | } |
| #146 | |
| #147 | // ─── Main ───────────────────────────────────────────────────────────────────── |
| #148 | |
| #149 | type Section = 'packages' | 'constants' | 'vault' | 'env'; |
| #150 | const SECTIONS: Section[] = ['packages', 'constants', 'vault', 'env']; |
| #151 | const SECTION_LABELS: Record<Section, string> = { |
| #152 | packages: '[1] Packages', |
| #153 | constants: '[2] Constants', |
| #154 | vault: '[3] Vault', |
| #155 | env: '[4] Env', |
| #156 | }; |
| #157 | |
| #158 | function enableRaw(): void { |
| #159 | process.stdout.write('\x1b[?25l'); |
| #160 | if (process.stdin.setRawMode) process.stdin.setRawMode(true); |
| #161 | process.stdin.resume(); |
| #162 | process.stdin.setEncoding('utf8'); |
| #163 | } |
| #164 | |
| #165 | function disableRaw(): void { |
| #166 | process.stdout.write('\x1b[?25h'); |
| #167 | if (process.stdin.setRawMode) process.stdin.setRawMode(false); |
| #168 | } |
| #169 | |
| #170 | function renderScreen( |
| #171 | section: Section, |
| #172 | pkgs: PackageInfo[], |
| #173 | vault: VaultInfo, |
| #174 | probes: EnvProbe[], |
| #175 | loading: boolean, |
| #176 | ): void { |
| #177 | clr(); |
| #178 | |
| #179 | // Header |
| #180 | const logo = chalk.hex('#ff00ff').bold(' ██████╗██╗ █████╗ ██╗ ██╗██████╗ '); |
| #181 | process.stdout.write(logo + '\n'); |
| #182 | process.stdout.write(chalk.cyanBright.bold(' OPENCLAWD SDK EXPLORER') + chalk.gray(' — monorepo packages · vault · constants · env') + '\n'); |
| #183 | process.stdout.write(chalk.cyan('─'.repeat(W)) + '\n'); |
| #184 | |
| #185 | // Tab bar |
| #186 | const tabs = SECTIONS.map(s => |
| #187 | s === section |
| #188 | ? chalk.bgCyan.black.bold(` ${SECTION_LABELS[s]} `) |
| #189 | : chalk.gray(` ${SECTION_LABELS[s]} `), |
| #190 | ).join(chalk.gray(' │ ')); |
| #191 | process.stdout.write(' ' + tabs + '\n'); |
| #192 | process.stdout.write(chalk.cyan('─'.repeat(W)) + '\n'); |
| #193 | process.stdout.write('\n'); |
| #194 | |
| #195 | if (loading) { |
| #196 | process.stdout.write(chalk.yellow(' Loading…') + '\n'); |
| #197 | return; |
| #198 | } |
| #199 | |
| #200 | let sectionLines: string[] = []; |
| #201 | if (section === 'packages') sectionLines = renderPackages(pkgs); |
| #202 | if (section === 'constants') sectionLines = renderConstants(); |
| #203 | if (section === 'vault') sectionLines = renderVault(vault); |
| #204 | if (section === 'env') sectionLines = renderEnv(probes); |
| #205 | |
| #206 | for (const l of sectionLines) { |
| #207 | process.stdout.write(l + '\n'); |
| #208 | } |
| #209 | |
| #210 | process.stdout.write('\n'); |
| #211 | process.stdout.write( |
| #212 | chalk.gray(' [Tab / 1-4] switch [b/Esc] back [q] quit') + '\n', |
| #213 | ); |
| #214 | } |
| #215 | |
| #216 | export async function runSDK(): Promise<void> { |
| #217 | let section: Section = 'packages'; |
| #218 | let pkgs: PackageInfo[] = []; |
| #219 | let vault: VaultInfo = { available: false, path: '', wallets: [] }; |
| #220 | let probes: EnvProbe[] = []; |
| #221 | let loading = true; |
| #222 | |
| #223 | enableRaw(); |
| #224 | renderScreen(section, pkgs, vault, probes, loading); |
| #225 | |
| #226 | // Load all data async |
| #227 | Promise.all([loadPackageInfo(), readVaultInfo(), Promise.resolve(probeEnv())]).then(([p, v, e]) => { |
| #228 | pkgs = p; |
| #229 | vault = v; |
| #230 | probes = e; |
| #231 | loading = false; |
| #232 | renderScreen(section, pkgs, vault, probes, false); |
| #233 | }).catch(() => { |
| #234 | loading = false; |
| #235 | renderScreen(section, pkgs, vault, probes, false); |
| #236 | }); |
| #237 | |
| #238 | return new Promise<void>(resolve => { |
| #239 | const cleanup = (): void => { |
| #240 | disableRaw(); |
| #241 | process.stdin.off('data', onData); |
| #242 | resolve(); |
| #243 | }; |
| #244 | |
| #245 | const onData = (data: Buffer | string): void => { |
| #246 | const key = typeof data === 'string' ? data : data.toString(); |
| #247 | |
| #248 | if (key === 'b' || key === 'B' || key === '\x1b') { cleanup(); return; } |
| #249 | if (key === 'q' || key === 'Q' || key === '\x03') { cleanup(); process.exit(0); } |
| #250 | |
| #251 | if (key === '\t') { |
| #252 | const idx = SECTIONS.indexOf(section); |
| #253 | section = SECTIONS[(idx + 1) % SECTIONS.length]!; |
| #254 | } |
| #255 | if (key === '1') section = 'packages'; |
| #256 | if (key === '2') section = 'constants'; |
| #257 | if (key === '3') section = 'vault'; |
| #258 | if (key === '4') section = 'env'; |
| #259 | |
| #260 | renderScreen(section, pkgs, vault, probes, loading); |
| #261 | }; |
| #262 | |
| #263 | process.stdin.on('data', onData); |
| #264 | }); |
| #265 | } |
| #266 |