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 | import fs from "fs"; |
| #2 | import path from "path"; |
| #3 | import chalk from "chalk"; |
| #4 | import type { AutomatonConfig } from "../types.js"; |
| #5 | import type { Address } from "viem"; |
| #6 | import { getWallet, getAutomatonDir } from "../identity/wallet.js"; |
| #7 | import { provision } from "../identity/provision.js"; |
| #8 | import { createConfig, saveConfig } from "../config.js"; |
| #9 | import { writeDefaultHeartbeatConfig } from "../heartbeat/config.js"; |
| #10 | import { showBanner } from "./banner.js"; |
| #11 | import { promptRequired, promptMultiline, promptAddress, closePrompts } from "./prompts.js"; |
| #12 | import { detectEnvironment } from "./environment.js"; |
| #13 | import { generateSoulMd, installDefaultSkills } from "./defaults.js"; |
| #14 | |
| #15 | export async function runSetupWizard(): Promise<AutomatonConfig> { |
| #16 | showBanner(); |
| #17 | |
| #18 | console.log(chalk.white(" First-run setup. Let's bring your automaton to life.\n")); |
| #19 | |
| #20 | // ─── 1. Generate wallet ─────────────────────────────────────── |
| #21 | console.log(chalk.cyan(" [1/6] Generating identity (wallet)...")); |
| #22 | const { account, isNew } = await getWallet(); |
| #23 | if (isNew) { |
| #24 | console.log(chalk.green(` Wallet created: ${account.address}`)); |
| #25 | } else { |
| #26 | console.log(chalk.green(` Wallet loaded: ${account.address}`)); |
| #27 | } |
| #28 | console.log(chalk.dim(` Private key stored at: ${getAutomatonDir()}/wallet.json\n`)); |
| #29 | |
| #30 | // ─── 2. Provision API key ───────────────────────────────────── |
| #31 | console.log(chalk.cyan(" [2/6] Provisioning CLAWD API key (SIWE)...")); |
| #32 | let apiKey = ""; |
| #33 | try { |
| #34 | const result = await provision(); |
| #35 | apiKey = result.apiKey; |
| #36 | console.log(chalk.green(` API key provisioned: ${result.keyPrefix}...\n`)); |
| #37 | } catch (err: any) { |
| #38 | console.log(chalk.yellow(` Auto-provision failed: ${err.message}`)); |
| #39 | console.log(chalk.yellow(" You can enter a key manually, or press Enter to skip.\n")); |
| #40 | const manual = await promptRequired("CLAWD API key (cnwy_k_...)"); |
| #41 | if (manual) { |
| #42 | apiKey = manual; |
| #43 | // Save to config.json for loadApiKeyFromConfig() |
| #44 | const configDir = getAutomatonDir(); |
| #45 | if (!fs.existsSync(configDir)) { |
| #46 | fs.mkdirSync(configDir, { recursive: true, mode: 0o700 }); |
| #47 | } |
| #48 | fs.writeFileSync( |
| #49 | path.join(configDir, "config.json"), |
| #50 | JSON.stringify({ apiKey, walletAddress: account.address, provisionedAt: new Date().toISOString() }, null, 2), |
| #51 | { mode: 0o600 }, |
| #52 | ); |
| #53 | console.log(chalk.green(" API key saved.\n")); |
| #54 | } |
| #55 | } |
| #56 | |
| #57 | if (!apiKey) { |
| #58 | console.log(chalk.yellow(" No API key set. The automaton will have limited functionality.\n")); |
| #59 | } |
| #60 | |
| #61 | // ─── 3. Interactive questions ───────────────────────────────── |
| #62 | console.log(chalk.cyan(" [3/6] Setup questions\n")); |
| #63 | |
| #64 | const name = await promptRequired("What do you want to name your automaton?"); |
| #65 | console.log(chalk.green(` Name: ${name}\n`)); |
| #66 | |
| #67 | const genesisPrompt = await promptMultiline("Enter the genesis prompt (system prompt) for your automaton."); |
| #68 | console.log(chalk.green(` Genesis prompt set (${genesisPrompt.length} chars)\n`)); |
| #69 | |
| #70 | const creatorAddress = await promptAddress("Your Ethereum wallet address (0x...)"); |
| #71 | console.log(chalk.green(` Creator: ${creatorAddress}\n`)); |
| #72 | |
| #73 | // ─── 4. Detect environment ──────────────────────────────────── |
| #74 | console.log(chalk.cyan(" [4/6] Detecting environment...")); |
| #75 | const env = detectEnvironment(); |
| #76 | if (env.sandboxId) { |
| #77 | console.log(chalk.green(` CLAWD sandbox detected: ${env.sandboxId}\n`)); |
| #78 | } else { |
| #79 | console.log(chalk.dim(` Environment: ${env.type} (no sandbox detected)\n`)); |
| #80 | } |
| #81 | |
| #82 | // ─── 5. Write config + heartbeat + SOUL.md + skills ─────────── |
| #83 | console.log(chalk.cyan(" [5/6] Writing configuration...")); |
| #84 | |
| #85 | const config = createConfig({ |
| #86 | name, |
| #87 | genesisPrompt, |
| #88 | creatorAddress: creatorAddress as Address, |
| #89 | registeredWithClawd: !!apiKey, |
| #90 | sandboxId: env.sandboxId, |
| #91 | walletAddress: account.address, |
| #92 | apiKey, |
| #93 | }); |
| #94 | |
| #95 | saveConfig(config); |
| #96 | console.log(chalk.green(" automaton.json written")); |
| #97 | |
| #98 | writeDefaultHeartbeatConfig(); |
| #99 | console.log(chalk.green(" heartbeat.yml written")); |
| #100 | |
| #101 | // constitution.md (immutable — copied from repo, protected from self-modification) |
| #102 | const automatonDir = getAutomatonDir(); |
| #103 | const constitutionSrc = path.join(process.cwd(), "constitution.md"); |
| #104 | const constitutionDst = path.join(automatonDir, "constitution.md"); |
| #105 | if (fs.existsSync(constitutionSrc)) { |
| #106 | fs.copyFileSync(constitutionSrc, constitutionDst); |
| #107 | fs.chmodSync(constitutionDst, 0o444); // read-only |
| #108 | console.log(chalk.green(" constitution.md installed (read-only)")); |
| #109 | } |
| #110 | |
| #111 | // SOUL.md |
| #112 | const soulPath = path.join(automatonDir, "SOUL.md"); |
| #113 | fs.writeFileSync(soulPath, generateSoulMd(name, account.address, creatorAddress, genesisPrompt), { mode: 0o600 }); |
| #114 | console.log(chalk.green(" SOUL.md written")); |
| #115 | |
| #116 | // Default skills |
| #117 | const skillsDir = config.skillsDir || "~/.automaton/skills"; |
| #118 | installDefaultSkills(skillsDir); |
| #119 | console.log(chalk.green(" Default skills installed (clawd-compute, clawd-payments, survival)\n")); |
| #120 | |
| #121 | // ─── 6. Funding guidance ────────────────────────────────────── |
| #122 | console.log(chalk.cyan(" [6/6] Funding\n")); |
| #123 | showFundingPanel(account.address); |
| #124 | |
| #125 | closePrompts(); |
| #126 | |
| #127 | return config; |
| #128 | } |
| #129 | |
| #130 | function showFundingPanel(address: string): void { |
| #131 | const short = `${address.slice(0, 6)}...${address.slice(-5)}`; |
| #132 | const w = 58; |
| #133 | const pad = (s: string, len: number) => s + " ".repeat(Math.max(0, len - s.length)); |
| #134 | |
| #135 | console.log(chalk.cyan(` ${"╭" + "─".repeat(w) + "╮"}`)); |
| #136 | console.log(chalk.cyan(` │${pad(" Fund your automaton", w)}│`)); |
| #137 | console.log(chalk.cyan(` │${" ".repeat(w)}│`)); |
| #138 | console.log(chalk.cyan(` │${pad(` Address: ${short}`, w)}│`)); |
| #139 | console.log(chalk.cyan(` │${" ".repeat(w)}│`)); |
| #140 | console.log(chalk.cyan(` │${pad(" 1. Transfer CLAWD credits", w)}│`)); |
| #141 | console.log(chalk.cyan(` │${pad(" clawd credits transfer <address> <amount>", w)}│`)); |
| #142 | console.log(chalk.cyan(` │${" ".repeat(w)}│`)); |
| #143 | console.log(chalk.cyan(` │${pad(" 2. Send USDC on Base directly to the address above", w)}│`)); |
| #144 | console.log(chalk.cyan(` │${" ".repeat(w)}│`)); |
| #145 | console.log(chalk.cyan(` │${pad(" 3. Fund via CLAWD Cloud dashboard", w)}│`)); |
| #146 | console.log(chalk.cyan(` │${pad(" https://app.x402.wtf", w)}│`)); |
| #147 | console.log(chalk.cyan(` │${" ".repeat(w)}│`)); |
| #148 | console.log(chalk.cyan(` │${pad(" The automaton will start now. Fund it anytime —", w)}│`)); |
| #149 | console.log(chalk.cyan(` │${pad(" the survival system handles zero-credit gracefully.", w)}│`)); |
| #150 | console.log(chalk.cyan(` ${"╰" + "─".repeat(w) + "╯"}`)); |
| #151 | console.log(""); |
| #152 | } |
| #153 |