@execra/core 1.0.0
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/dist/cli/commands.d.ts +21 -0
- package/dist/cli/commands.js +686 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +1162 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/prompts.d.ts +12 -0
- package/dist/cli/prompts.js +98 -0
- package/dist/cli/prompts.js.map +1 -0
- package/dist/cli/ui.d.ts +38 -0
- package/dist/cli/ui.js +990 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/handler/index.d.ts +93 -0
- package/dist/handler/index.js +628 -0
- package/dist/handler/index.js.map +1 -0
- package/dist/handler/walletConnect.d.ts +6 -0
- package/dist/handler/walletConnect.js +623 -0
- package/dist/handler/walletConnect.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +2046 -0
- package/dist/index.js.map +1 -0
- package/dist/session/index.d.ts +20 -0
- package/dist/session/index.js +79 -0
- package/dist/session/index.js.map +1 -0
- package/dist/solana/index.d.ts +5 -0
- package/dist/solana/index.js +302 -0
- package/dist/solana/index.js.map +1 -0
- package/dist/solana/rpc.d.ts +45 -0
- package/dist/solana/rpc.js +120 -0
- package/dist/solana/rpc.js.map +1 -0
- package/dist/solana/simulate.d.ts +41 -0
- package/dist/solana/simulate.js +173 -0
- package/dist/solana/simulate.js.map +1 -0
- package/dist/solana/tx.d.ts +54 -0
- package/dist/solana/tx.js +141 -0
- package/dist/solana/tx.js.map +1 -0
- package/dist/vault/accounts.d.ts +88 -0
- package/dist/vault/accounts.js +126 -0
- package/dist/vault/accounts.js.map +1 -0
- package/dist/vault/config.d.ts +40 -0
- package/dist/vault/config.js +131 -0
- package/dist/vault/config.js.map +1 -0
- package/dist/vault/index.d.ts +122 -0
- package/dist/vault/index.js +580 -0
- package/dist/vault/index.js.map +1 -0
- package/dist/vault/keystore.d.ts +44 -0
- package/dist/vault/keystore.js +118 -0
- package/dist/vault/keystore.js.map +1 -0
- package/dist/vault/mnemonic.d.ts +43 -0
- package/dist/vault/mnemonic.js +37 -0
- package/dist/vault/mnemonic.js.map +1 -0
- package/package.json +49 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vault/mnemonic.ts","../src/vault/keystore.ts","../src/vault/accounts.ts","../src/vault/config.ts","../src/vault/index.ts","../src/solana/rpc.ts","../src/solana/simulate.ts","../src/solana/tx.ts","../src/cli/ui.tsx","../src/cli/commands.ts","../src/handler/walletConnect.ts","../src/handler/index.ts","../src/session/index.ts","../src/cli/prompts.tsx"],"sourcesContent":["/**\n *\n * BIP-39 mnemonic generation, validation, and seed derivation.\n * Supports 12-word (128-bit) and 24-word (256-bit) mnemonics.\n *\n * Dependencies: bip39\n */\n\nimport * as bip39 from \"bip39\";\n\nexport type MnemonicStrength = 12 | 24; // 128 = 12 words, 256 = 24 words\n\nexport interface MnemonicResult {\n mnemonic: string;\n wordCount: 12 | 24;\n}\n\n/**\n * Generate a new cryptographically random BIP-39 mnemonic.\n * @param strength 128 for 12-word, 256 for 24-word (default: 128)\n */\nexport function generateMnemonic(\n strength: MnemonicStrength = 12,\n): MnemonicResult {\n const mnemonic = bip39.generateMnemonic(strength == 12 ? 128 : 256);\n const wordCount = strength;\n return { mnemonic, wordCount };\n}\n\n/**\n * Validate a BIP-39 mnemonic phrase.\n * Checks both wordlist membership and BIP-39 checksum.\n */\nexport function validateMnemonic(mnemonic: string): boolean {\n const cleaned = cleanMnemonic(mnemonic);\n return bip39.validateMnemonic(cleaned);\n}\n\n/**\n * Derive a 64-byte seed buffer from a mnemonic.\n * Optional passphrase adds extra security per BIP-39 spec.\n * This seed is the root of ALL derived accounts.\n */\nexport async function mnemonicToSeed(\n mnemonic: string,\n passphrase: string = \"\",\n): Promise<Buffer> {\n const cleaned = cleanMnemonic(mnemonic);\n\n if (!validateMnemonic(cleaned)) {\n throw new Error(\"Invalid mnemonic: failed wordlist or checksum validation\");\n }\n\n return bip39.mnemonicToSeed(cleaned, passphrase);\n}\n\n/**\n * Split mnemonic into a numbered word array.\n * Used for backup verification display in the terminal UI.\n *\n * Example output:\n * [ \"1. witch\", \"2. collapse\", \"3. practice\", ... ]\n */\nexport function mnemonicToNumberedWords(mnemonic: string): string[] {\n return cleanMnemonic(mnemonic)\n .split(\" \")\n .map((word, i) => `${i + 1}. ${word}`);\n}\n\n/**\n * Reconstruct mnemonic from a word array.\n * Used when user inputs words one by one during restore flow.\n */\nexport function wordsToMnemonic(words: string[]): string {\n return words.map((w) => w.trim().toLowerCase()).join(\" \");\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\nfunction cleanMnemonic(mnemonic: string): string {\n return mnemonic.trim().toLowerCase().replace(/\\s+/g, \" \");\n}\n","/**\n *\n * AES-256-GCM encrypted keystore.\n * The mnemonic (seed phrase) is encrypted at rest in ~/.wallet/vault.enc\n * Private keys NEVER touch disk — they are derived in memory at runtime.\n *\n * Encryption scheme:\n * - Key derivation: PBKDF2 (SHA-512, 210,000 iterations) — OWASP recommended\n * - Cipher: AES-256-GCM (authenticated encryption — detects tampering)\n * - Salt: 32 random bytes (unique per vault)\n * - IV: 16 random bytes (unique per encryption)\n *\n * Dependencies: Node.js built-in `crypto`, `fs`, `os`, `path`\n */\n\nimport crypto from \"crypto\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface VaultData {\n mnemonic: string;\n createdAt: string;\n version: number;\n}\n\ninterface EncryptedVault {\n version: number; // format version for future migrations\n salt: string; // hex — used for PBKDF2 key derivation\n iv: string; // hex — AES-GCM initialisation vector\n authTag: string; // hex — GCM authentication tag (detects tampering)\n ciphertext: string; // hex — encrypted vault data\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\nconst VAULT_VERSION = 1;\nconst PBKDF2_ITERATIONS = 210_000; // OWASP 2024 recommendation for PBKDF2-SHA512\nconst PBKDF2_DIGEST = \"sha512\";\nconst KEY_LENGTH = 32; // 256 bits for AES-256\nconst SALT_LENGTH = 32; // 256 bits\nconst IV_LENGTH = 16; // 128 bits for AES-GCM\nconst CIPHER = \"aes-256-gcm\";\n\n// ── Vault Path ────────────────────────────────────────────────────────────────\n\nexport function getWalletDir(): string {\n // return path.join(__dirname, \".wallet\");\n return path.join(os.homedir(), \".wallet\");\n}\n\nexport function getVaultPath(): string {\n return path.join(getWalletDir(), \"vault.enc\");\n}\n\nexport function getConfigPath(): string {\n return path.join(getWalletDir(), \"config.json\");\n}\n\nexport function getSessionsPath(): string {\n return path.join(getWalletDir(), \"sessions.json\");\n}\n\nexport const SESSIONS_FILE = getSessionsPath();\n\nexport function ensureWalletDir(): void {\n const dir = getWalletDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); // owner-only access\n }\n}\n\nexport function vaultExists(): boolean {\n return fs.existsSync(getVaultPath());\n}\n\n// ── Encryption ────────────────────────────────────────────────────────────────\n\n/**\n * Encrypt and save the vault to disk.\n * @param data - vault contents (mnemonic + metadata)\n * @param password - user's wallet password\n */\nexport async function saveVault(\n data: VaultData,\n password: string,\n): Promise<void> {\n ensureWalletDir();\n\n const salt = crypto.randomBytes(SALT_LENGTH);\n const iv = crypto.randomBytes(IV_LENGTH);\n const key = await deriveKey(password, salt);\n\n const plaintext = JSON.stringify(data);\n const cipher = crypto.createCipheriv(CIPHER, key, iv);\n\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n\n const authTag = cipher.getAuthTag();\n\n const vault: EncryptedVault = {\n version: VAULT_VERSION,\n salt: salt.toString(\"hex\"),\n iv: iv.toString(\"hex\"),\n authTag: authTag.toString(\"hex\"),\n ciphertext: encrypted.toString(\"hex\"),\n };\n\n fs.writeFileSync(getVaultPath(), JSON.stringify(vault, null, 2), {\n mode: 0o600, // owner read/write only\n });\n}\n\n/**\n * Load and decrypt the vault from disk.\n * Throws if the password is wrong or the file has been tampered with.\n */\nexport async function loadVault(password: string): Promise<VaultData> {\n if (!vaultExists()) {\n throw new Error(\"No vault found. Run `wallet init` to create one.\");\n }\n\n const raw = fs.readFileSync(getVaultPath(), \"utf8\");\n const vault: EncryptedVault = JSON.parse(raw);\n\n if (vault.version !== VAULT_VERSION) {\n throw new Error(`Unsupported vault version: ${vault.version}`);\n }\n\n const salt = Buffer.from(vault.salt, \"hex\");\n const iv = Buffer.from(vault.iv, \"hex\");\n const authTag = Buffer.from(vault.authTag, \"hex\");\n const ciphertext = Buffer.from(vault.ciphertext, \"hex\");\n\n const key = await deriveKey(password, salt);\n\n try {\n const decipher = crypto.createDecipheriv(CIPHER, key, iv);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]);\n\n return JSON.parse(decrypted.toString(\"utf8\")) as VaultData;\n } catch {\n // GCM auth tag failure means wrong password OR tampered file\n throw new Error(\"Decryption failed: wrong password or vault is corrupted.\");\n }\n}\n\n/**\n * Change the vault password.\n * Decrypts with old password, re-encrypts with new password.\n */\nexport async function changePassword(\n oldPassword: string,\n newPassword: string,\n): Promise<void> {\n const data = await loadVault(oldPassword);\n await saveVault(data, newPassword);\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\n/**\n * Derive a 256-bit AES key from a password using PBKDF2-SHA512.\n */\nfunction deriveKey(password: string, salt: Buffer): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n crypto.pbkdf2(\n password,\n salt,\n PBKDF2_ITERATIONS,\n KEY_LENGTH,\n PBKDF2_DIGEST,\n (err, key) => {\n if (err) reject(err);\n else resolve(key);\n },\n );\n });\n}\n","/**\n *\n * BIP-44 HD key derivation for Solana accounts.\n *\n * Derivation path: m/44'/501'/index'/0'\n * 44' = BIP-44 purpose\n * 501' = Solana's registered coin type (SLIP-44)\n * n' = account index (0 = first account, 1 = second, etc.)\n * 0' = change (always 0 for Solana)\n *\n * This is the exact path Phantom, Backpack, and Solflare use.\n * Same seed → same addresses as those wallets.\n *\n * Dependencies: ed25519-hd-key, tweetnacl, bs58\n */\n\nimport { derivePath } from \"ed25519-hd-key\";\nimport nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport { mnemonicToSeed } from \"./mnemonic\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface Account {\n index: number; // derivation index\n name: string; // user-defined label\n publicKey: string; // Base58 encoded — this is the Solana address\n derivationPath: string; // m/44'/501'/index'/0'\n createdAt: string;\n}\n\n/**\n * In-memory keypair — private key NEVER persisted to disk.\n * Lives only for the duration of the daemon session.\n */\nexport interface AccountKeypair extends Account {\n secretKey: Uint8Array; // 64-byte Ed25519 secret key (seed + public key)\n}\n\nexport interface AccountStore {\n accounts: Account[];\n activeIndex: number;\n}\n\n// ── Derivation ────────────────────────────────────────────────────────────────\n\n/**\n * Derive an Ed25519 keypair at a specific BIP-44 index.\n * This is the core operation — called once per session after vault unlock.\n *\n * @param seed - 64-byte seed from BIP-39 mnemonic\n * @param index - account index (0-based)\n * @param name - label for this account\n */\nexport function deriveAccount(\n seed: Buffer,\n index: number,\n name: string = `Account ${index + 1}`,\n): AccountKeypair {\n const path = derivationPath(index);\n\n // SLIP-0010 Ed25519 derivation\n const { key: privateKeyBytes } = derivePath(path, seed.toString(\"hex\"));\n\n // nacl keypair from 32-byte seed\n const keypair = nacl.sign.keyPair.fromSeed(privateKeyBytes);\n\n const publicKey = bs58.encode(Buffer.from(keypair.publicKey));\n\n return {\n index,\n name,\n publicKey,\n secretKey: keypair.secretKey, // 64 bytes: seed + public key\n derivationPath: path,\n createdAt: new Date().toISOString(),\n };\n}\n\n/**\n * Derive multiple accounts at once.\n * Used on wallet startup to load all known accounts into memory.\n */\nexport function deriveAccounts(\n seed: Buffer,\n accountStore: AccountStore,\n): AccountKeypair[] {\n return accountStore.accounts.map((account) =>\n deriveAccount(seed, account.index, account.name),\n );\n}\n\n/**\n * Derive a single account directly from mnemonic.\n * Convenience wrapper used in tests and programmatic access.\n */\nexport async function deriveAccountFromMnemonic(\n mnemonic: string,\n index: number,\n name?: string,\n passphrase?: string,\n): Promise<AccountKeypair> {\n const seed = await mnemonicToSeed(mnemonic, passphrase);\n return deriveAccount(seed, index, name);\n}\n\n// ── Account Store ─────────────────────────────────────────────────────────────\n\n/**\n * Create a fresh account store with the first account.\n */\nexport function createAccountStore(\n firstAccountName: string = \"Account 1\",\n): AccountStore {\n return {\n accounts: [\n {\n index: 0,\n name: firstAccountName,\n publicKey: \"\", // filled in after derivation\n derivationPath: derivationPath(0),\n createdAt: new Date().toISOString(),\n },\n ],\n activeIndex: 0,\n };\n}\n\n/**\n * Add a new account to the store.\n * The next index is always max(existing indices) + 1.\n */\nexport function addAccount(\n store: AccountStore,\n seed: Buffer,\n name?: string,\n): { store: AccountStore; keypair: AccountKeypair } {\n const nextIndex =\n store.accounts.length > 0\n ? Math.max(...store.accounts.map((a) => a.index)) + 1\n : 0;\n\n const accountName = name ?? `Account ${nextIndex + 1}`;\n const keypair = deriveAccount(seed, nextIndex, accountName);\n\n const newAccount: Account = {\n index: nextIndex,\n name: accountName,\n publicKey: keypair.publicKey,\n derivationPath: keypair.derivationPath,\n createdAt: keypair.createdAt,\n };\n\n const updatedStore: AccountStore = {\n ...store,\n accounts: [...store.accounts, newAccount],\n };\n\n return { store: updatedStore, keypair };\n}\n\n/**\n * Set the active account by index.\n * The active account is used for all dApp connections and signing.\n */\nexport function setActiveAccount(\n store: AccountStore,\n index: number,\n): AccountStore {\n const exists = store.accounts.find((a) => a.index === index);\n if (!exists) {\n throw new Error(`Account index ${index} does not exist.`);\n }\n return { ...store, activeIndex: index };\n}\n\n/**\n * Rename an account.\n */\nexport function renameAccount(\n store: AccountStore,\n index: number,\n newName: string,\n): AccountStore {\n return {\n ...store,\n accounts: store.accounts.map((a) =>\n a.index === index ? { ...a, name: newName } : a,\n ),\n };\n}\n\n/**\n * Get the active account metadata from the store.\n */\nexport function getActiveAccount(store: AccountStore): Account {\n const account = store.accounts.find((a) => a.index === store.activeIndex);\n if (!account) throw new Error(\"No active account found.\");\n return account;\n}\n\n// ── Utilities ─────────────────────────────────────────────────────────────────\n\n/**\n * Sign a raw message with an account's secret key.\n * Returns a Base58 encoded signature.\n */\nexport function signMessage(\n message: Uint8Array,\n secretKey: Uint8Array,\n): string {\n const signature = nacl.sign.detached(message, secretKey);\n return bs58.encode(Buffer.from(signature));\n}\n\n/**\n * Format account for display in terminal.\n */\nexport function formatAccount(account: Account, isActive: boolean): string {\n const activeMarker = isActive ? \"●\" : \"○\";\n const shortKey = `${account.publicKey.slice(0, 4)}...${account.publicKey.slice(-4)}`;\n return `${activeMarker} [${account.index}] ${account.name.padEnd(20)} ${shortKey}`;\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\nfunction derivationPath(index: number): string {\n return `m/44'/501'/${index}'/0'`;\n}\n","/**\n *\n * Reads and writes ~/.wallet/config.json\n * Stores non-sensitive wallet preferences:\n * - Active account index\n * - RPC endpoint (mainnet / devnet)\n * - Account metadata (names, indices — no keys)\n * - WalletConnect project ID\n *\n * Dependencies: Node.js built-in `fs`, `os`, `path`\n */\n\nimport fs from \"fs\";\nimport { getConfigPath, ensureWalletDir } from \"./keystore\";\nimport { AccountStore, createAccountStore } from \"./accounts\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type ClusterType = \"mainnet-beta\" | \"devnet\" | \"testnet\" | \"localnet\" | \"custom\";\n\nexport interface WalletConfig {\n version: number;\n cluster: ClusterType;\n rpcUrl: string;\n walletConnectProjectId: string;\n accountStore: AccountStore;\n createdAt: string;\n updatedAt: string;\n}\n\n// ── Defaults ──────────────────────────────────────────────────────────────────\n\nconst HELIUS_API_KEY = process.env.HELIUS_API_KEY;\nexport const RPC_URLS: Record<Exclude<ClusterType, \"custom\">, string> = {\n \"mainnet-beta\": HELIUS_API_KEY\n ? `https://mainnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`\n : \"https://api.mainnet-beta.solana.com\",\n devnet: HELIUS_API_KEY\n ? `https://devnet.helius-rpc.com/?api-key=${HELIUS_API_KEY}`\n : \"https://api.devnet.solana.com\",\n testnet: \"https://api.testnet.solana.com\",\n localnet: \"http://localhost:8899\",\n};\n\nconst CONFIG_VERSION = 1;\n\n// ── Read / Write ──────────────────────────────────────────────────────────────\n\nexport function configExists(): boolean {\n return fs.existsSync(getConfigPath());\n}\n\nexport function loadConfig(): WalletConfig {\n if (!configExists()) {\n throw new Error(\"No config found. Run `wallet init` first.\");\n }\n const raw = fs.readFileSync(getConfigPath(), \"utf8\");\n return JSON.parse(raw) as WalletConfig;\n}\n\nexport function saveConfig(config: WalletConfig): void {\n ensureWalletDir();\n const updated = { ...config, updatedAt: new Date().toISOString() };\n fs.writeFileSync(getConfigPath(), JSON.stringify(updated, null, 2), {\n mode: 0o600,\n });\n}\n\n/**\n * Create a fresh config on `wallet init`.\n */\nexport function createConfig(\n walletConnectProjectId: string = \"\",\n cluster: Exclude<ClusterType, \"custom\"> = \"devnet\",\n): WalletConfig {\n const now = new Date().toISOString();\n return {\n version: CONFIG_VERSION,\n cluster,\n rpcUrl: RPC_URLS[cluster],\n walletConnectProjectId,\n accountStore: createAccountStore(\"Account 1\"),\n createdAt: now,\n updatedAt: now,\n };\n}\n\n// ── Helpers ───────────────────────────────────────────────────────────────────\n\nexport function updateCluster(cluster: Exclude<ClusterType, \"custom\">): void {\n const config = loadConfig();\n config.cluster = cluster;\n config.rpcUrl = RPC_URLS[cluster];\n saveConfig(config);\n}\n\nexport function updateRpcUrl(url: string): void {\n const config = loadConfig();\n config.rpcUrl = url;\n saveConfig(config);\n}\n\nexport function updateAccountStore(accountStore: AccountStore): void {\n const config = loadConfig();\n config.accountStore = accountStore;\n saveConfig(config);\n}\n\nexport function getRpcUrl(): string {\n return loadConfig().rpcUrl;\n}\n\nexport function getCluster(): ClusterType {\n return loadConfig().cluster;\n}\n\nexport function getAccountStore(): AccountStore {\n return loadConfig().accountStore;\n}\n","/**\n *\n * Public API for the vault module.\n * All other modules import from here — not directly from sub-files.\n *\n * Usage:\n * import { WalletVault } from \"../vault\"\n *\n * const vault = new WalletVault()\n * await vault.init(\"my password\")\n * const account = vault.getActiveKeypair()\n */\n\nimport {\n generateMnemonic,\n validateMnemonic,\n mnemonicToSeed,\n mnemonicToNumberedWords,\n} from \"./mnemonic\";\nimport { saveVault, loadVault, vaultExists, VaultData } from \"./keystore\";\nimport {\n deriveAccount,\n deriveAccounts,\n addAccount,\n setActiveAccount,\n getActiveAccount,\n renameAccount,\n formatAccount,\n signMessage,\n AccountKeypair,\n AccountStore,\n} from \"./accounts\";\nimport {\n loadConfig,\n saveConfig,\n createConfig,\n updateAccountStore,\n configExists,\n WalletConfig,\n ClusterType,\n} from \"./config\";\n\nexport * from \"./mnemonic\";\nexport * from \"./keystore\";\nexport * from \"./accounts\";\nexport * from \"./config\";\n\n// ── WalletVault ───────────────────────────────────────────────────────────────\n\n/**\n * WalletVault is the in-memory session state of the wallet.\n * It is populated on `unlock()` and holds derived keypairs\n * for the duration of the daemon session.\n *\n * Private keys exist ONLY in this object — never on disk.\n */\nexport class WalletVault {\n private _keypairs: AccountKeypair[] = [];\n private _seed: Buffer | null = null; // cached for agent account derivation\n private _config: WalletConfig | null = null;\n private _unlocked: boolean = false;\n private _mnemonic: string | null = null;\n\n // ── Lifecycle ──────────────────────────────────────────────────────────────\n\n /**\n * Initialize a brand new wallet.\n * Generates a mnemonic, encrypts it, writes config.\n * Returns the mnemonic for the user to write down — shown ONCE.\n */\n async init(\n password: string,\n options: {\n strength?: 12 | 24;\n cluster?: Exclude<ClusterType, \"custom\">;\n walletConnectProjectId?: string;\n firstAccountName?: string;\n } = {},\n ): Promise<string> {\n if (vaultExists()) {\n throw new Error(\n \"Wallet already exists. Use `wallet unlock` to access it.\",\n );\n }\n\n const { mnemonic } = generateMnemonic(options.strength ?? 12);\n\n const vaultData: VaultData = {\n mnemonic,\n createdAt: new Date().toISOString(),\n version: 1,\n };\n\n // Save encrypted vault\n await saveVault(vaultData, password);\n\n // Create and save config\n const config = createConfig(\n options.walletConnectProjectId ?? \"\",\n options.cluster ?? \"devnet\",\n );\n\n if (options.firstAccountName) {\n config.accountStore.accounts[0].name = options.firstAccountName;\n }\n\n // Derive and store the first account's public key in config\n const seed = await mnemonicToSeed(mnemonic);\n const firstKeypair = deriveAccount(\n seed,\n 0,\n config.accountStore.accounts[0].name,\n );\n config.accountStore.accounts[0].publicKey = firstKeypair.publicKey;\n saveConfig(config);\n\n return mnemonic; // shown once to user, never stored in plaintext again\n }\n\n /**\n * Unlock the wallet for a session.\n * Decrypts the vault, derives all account keypairs into memory.\n */\n async unlock(password: string): Promise<void> {\n const vaultData = await loadVault(password); // throws on wrong password\n const config = loadConfig();\n\n const seed = await mnemonicToSeed(vaultData.mnemonic);\n this._seed = seed;\n this._mnemonic = vaultData.mnemonic;\n this._keypairs = deriveAccounts(seed, config.accountStore);\n this._config = config;\n this._unlocked = true;\n }\n\n /**\n * Restore wallet from an existing mnemonic (import flow).\n */\n async restore(\n mnemonic: string,\n password: string,\n options: { cluster?: Exclude<ClusterType, \"custom\"> } = {},\n ): Promise<void> {\n if (!validateMnemonic(mnemonic)) {\n throw new Error(\"Invalid mnemonic phrase.\");\n }\n\n const vaultData: VaultData = {\n mnemonic,\n createdAt: new Date().toISOString(),\n version: 1,\n };\n\n await saveVault(vaultData, password);\n const config = createConfig(\"\", options.cluster ?? \"devnet\");\n const seed = await mnemonicToSeed(mnemonic);\n const firstKeypair = deriveAccount(seed, 0, \"Account 1\");\n config.accountStore.accounts[0].publicKey = firstKeypair.publicKey;\n saveConfig(config);\n }\n\n lock(): void {\n this._keypairs = [];\n this._mnemonic = null;\n this._seed = null;\n this._config = null;\n this._unlocked = false;\n }\n\n // ── Account Management ─────────────────────────────────────────────────────\n\n /**\n * Get the currently active keypair (used for signing + dApp connections).\n */\n getActiveKeypair(): AccountKeypair {\n this.assertUnlocked();\n const active = getActiveAccount(this._config!.accountStore);\n const keypair = this._keypairs.find((k) => k.index === active.index);\n if (!keypair) throw new Error(\"Active keypair not found in session.\");\n return keypair;\n }\n\n /**\n * Lock the wallet — wipe all keypairs from memory.\n */\n /**\n * Returns the mnemonic — only available while unlocked.\n * Used by agent_connect to derive new accounts on demand.\n */\n\n getMnemonic(): string {\n if (!this._mnemonic) throw new Error(\"Wallet is locked\");\n return this._mnemonic;\n }\n\n /**\n * Reload config and re-derive keypairs from seed.\n * Call after adding new accounts so the vault picks them up.\n */\n async reload(): Promise<void> {\n if (!this._seed) throw new Error(\"Wallet is locked\");\n this._config = loadConfig();\n this._keypairs = deriveAccounts(this._seed, this._config.accountStore);\n }\n\n /**\n * Get a keypair by account index.\n */\n getKeypair(index: number): AccountKeypair {\n this.assertUnlocked();\n const keypair = this._keypairs.find((k) => k.index === index);\n if (!keypair) throw new Error(`Account ${index} not found.`);\n return keypair;\n }\n\n /**\n * Get all loaded keypairs.\n */\n getAllKeypairs(): AccountKeypair[] {\n this.assertUnlocked();\n return [...this._keypairs];\n }\n\n /**\n * Add a new derived account.\n */\n async addAccount(name?: string, password?: string): Promise<AccountKeypair> {\n this.assertUnlocked();\n\n // Need the seed to derive the new account\n if (!password) throw new Error(\"Password required to add a new account.\");\n const vaultData = await loadVault(password);\n const seed = await mnemonicToSeed(vaultData.mnemonic);\n\n const { store, keypair } = addAccount(\n this._config!.accountStore,\n seed,\n name,\n );\n\n this._config!.accountStore = store;\n this._keypairs.push(keypair);\n updateAccountStore(store);\n\n return keypair;\n }\n\n /**\n * Switch the active account.\n */\n setActiveAccount(index: number): void {\n this.assertUnlocked();\n const updated = setActiveAccount(this._config!.accountStore, index);\n this._config!.accountStore = updated;\n updateAccountStore(updated);\n }\n\n /**\n * Rename an account.\n */\n renameAccount(index: number, newName: string): void {\n this.assertUnlocked();\n const updated = renameAccount(this._config!.accountStore, index, newName);\n this._config!.accountStore = updated;\n this._keypairs = this._keypairs.map((k) =>\n k.index === index ? { ...k, name: newName } : k,\n );\n updateAccountStore(updated);\n }\n\n // ── Display ────────────────────────────────────────────────────────────────\n\n /**\n * Format all accounts for terminal display.\n */\n listAccounts(): string[] {\n this.assertUnlocked();\n const activeIndex = this._config!.accountStore.activeIndex;\n return this._keypairs.map((k) => formatAccount(k, k.index === activeIndex));\n }\n\n /**\n * Sign a message with the active account.\n */\n signMessage(message: Uint8Array): string {\n const keypair = this.getActiveKeypair();\n return signMessage(message, keypair.secretKey);\n }\n\n // ── State ──────────────────────────────────────────────────────────────────\n\n get isUnlocked(): boolean {\n return this._unlocked;\n }\n\n get config(): WalletConfig {\n this.assertUnlocked();\n return this._config!;\n }\n\n static exists(): boolean {\n return vaultExists() && configExists();\n }\n\n /**\n * Display mnemonic as numbered words — for backup verification flow.\n */\n static formatMnemonicForDisplay(mnemonic: string): string {\n const words = mnemonicToNumberedWords(mnemonic);\n // Format into 3 columns of 4 (12-word) or 6 columns of 4 (24-word)\n const cols = 3;\n const rows: string[] = [];\n for (let i = 0; i < words.length; i += cols) {\n rows.push(\n words\n .slice(i, i + cols)\n .map((w) => w.padEnd(18))\n .join(\" \"),\n );\n }\n return rows.join(\"\\n\");\n }\n\n // ── Internal ───────────────────────────────────────────────────────────────\n\n private assertUnlocked(): void {\n if (!this._unlocked) {\n throw new Error(\"Wallet is locked. Run `wallet unlock` first.\");\n }\n }\n\n /**\n * Find an account by name or create it if it doesn't exist.\n * Uses the cached seed — no password needed.\n * This is the primary way agents acquire their account.\n */\n async findOrCreate(name: string): Promise<AccountKeypair> {\n this.assertUnlocked();\n\n // Return existing account with this name\n const existing = this._keypairs.find((k) => k.name === name);\n if (existing) return existing;\n\n // Derive a new account at the next index\n const nextIndex = this._config!.accountStore.accounts.length;\n const { store, keypair } = addAccount(\n this._config!.accountStore,\n this._seed!,\n name,\n );\n\n this._config!.accountStore = store;\n this._keypairs.push(keypair);\n updateAccountStore(store);\n\n console.log(\n `[Vault] Created account \"${name}\" at index ${nextIndex} (${keypair.publicKey})`,\n );\n return keypair;\n }\n\n /**\n * Find an account by name. Returns null if not found.\n */\n findByName(name: string): AccountKeypair | null {\n this.assertUnlocked();\n return this._keypairs.find((k) => k.name === name) ?? null;\n }\n}\n","/**\n *\n * Solana RPC connection manager.\n * Single shared connection instance for the daemon session.\n *\n * Dependencies: @solana/web3.js\n */\n\nimport { Connection, PublicKey, LAMPORTS_PER_SOL } from '@solana/web3.js';\nimport { getRpcUrl, getCluster } from '../vault/config';\n\n// Singleton connection\n\nlet _connection: Connection | null = null;\n\nexport function getConnection(forceNew: boolean = false): Connection {\n if (!_connection || forceNew) {\n const rpcUrl = getRpcUrl();\n _connection = new Connection(rpcUrl, 'confirmed');\n }\n return _connection;\n}\n\n/**\n * Reset connection — used when RPC URL or cluster changes.\n */\nexport function resetConnection(): void {\n _connection = null;\n}\n\n// Balance─\n\n/**\n * Get SOL balance for an address in lamports and SOL.\n */\nexport async function getBalance(\n publicKeyStr: string,\n): Promise<{ lamports: number; sol: number }> {\n const connection = getConnection();\n const pubkey = new PublicKey(publicKeyStr);\n const lamports = await connection.getBalance(pubkey);\n return {\n lamports,\n sol: lamports / LAMPORTS_PER_SOL,\n };\n}\n\n/**\n * Request a devnet airdrop (only works on devnet/testnet).\n * Returns the transaction signature.\n */\nexport async function requestAirdrop(\n publicKeyStr: string,\n solAmount: number = 1,\n): Promise<string> {\n const cluster = getCluster();\n if (cluster === 'mainnet-beta') {\n throw new Error('Airdrops are not available on mainnet.');\n }\n\n const connection = getConnection();\n const pubkey = new PublicKey(publicKeyStr);\n const lamports = solAmount * LAMPORTS_PER_SOL;\n\n const signature = await connection.requestAirdrop(pubkey, lamports);\n await connection.confirmTransaction(signature, 'confirmed');\n\n return signature;\n}\n\n/**\n * Get recent blockhash — required for building transactions.\n */\nexport async function getLatestBlockhash(): Promise<{\n blockhash: string;\n lastValidBlockHeight: number;\n}> {\n const connection = getConnection();\n return connection.getLatestBlockhash('confirmed');\n}\n\n/**\n * Confirm a transaction by signature.\n * Polls until confirmed or timeout.\n */\nexport async function confirmTransaction(\n signature: string,\n timeoutMs: number = 30_000,\n): Promise<boolean> {\n const connection = getConnection();\n const { blockhash, lastValidBlockHeight } = await getLatestBlockhash();\n\n const result = await connection.confirmTransaction(\n { signature, blockhash, lastValidBlockHeight },\n 'confirmed',\n );\n\n return !result.value.err;\n}\n\n/**\n * Check if the RPC endpoint is reachable.\n */\nexport async function healthCheck(): Promise<boolean> {\n try {\n const connection = getConnection();\n await connection.getVersion();\n return true;\n } catch {\n return false;\n }\n}\n","import {\n Connection,\n Transaction,\n VersionedTransaction,\n LAMPORTS_PER_SOL,\n} from \"@solana/web3.js\";\nimport { getConnection } from \"./rpc\";\n\n// Types\nexport interface TokenChange {\n mint: string; // token mint address\n account: string; // token account address\n owner: string; // owner of the token account\n preAmount: number; // balance before tx\n postAmount: number; // balance after tx\n delta: number; // change (positive = received, negative = sent)\n decimals: number;\n}\n\nexport interface AccountChange {\n address: string;\n preBalance: number; // in lamports\n postBalance: number; // in lamports\n solDelta: number; // in SOL (human readable)\n isWritable: boolean;\n isSigner: boolean;\n}\n\nexport interface SimulationResult {\n success: boolean;\n error: string | null;\n logs: string[];\n\n // Account changes\n accountChanges: AccountChange[];\n tokenChanges: TokenChange[];\n\n // Transaction metadata\n computeUnitsConsumed: number;\n programIds: string[]; // all programs invoked\n fee: number; // estimated fee in lamports\n\n // Raw simulation data (passed to Claude)\n rawLogs: string[];\n}\n\n// Simulate\n/**\n * Simulate a transaction and return a parsed result.\n * Accepts both legacy and versioned transactions (base64 encoded).\n *\n * @param serializedTx - base64 encoded serialized transaction\n * @param signerPublicKey - the wallet's public key (used to identify balance changes)\n */\nexport async function simulateTransaction(\n serializedTx: string,\n signerPublicKey: string,\n conn?: Connection,\n): Promise<SimulationResult> {\n const connection = conn ?? getConnection();\n\n try {\n const txBuffer = Buffer.from(serializedTx, \"base64\");\n\n // Try versioned transaction first, fall back to legacy\n let simulation: Awaited<ReturnType<Connection[\"simulateTransaction\"]>>;\n\n try {\n const versionedTx = VersionedTransaction.deserialize(txBuffer);\n simulation = await connection.simulateTransaction(versionedTx, {\n sigVerify: false, // skip sig verification — wallet hasn't signed yet\n replaceRecentBlockhash: true,\n });\n } catch {\n // Fall back to legacy transaction\n const legacyTx = Transaction.from(txBuffer);\n simulation = await connection.simulateTransaction(legacyTx, []);\n }\n\n const { value } = simulation;\n\n return parseSimulationResult(value, signerPublicKey, txBuffer);\n } catch (err) {\n // Simulation itself failed (network error, malformed tx, etc.)\n return {\n success: false,\n error: err instanceof Error ? err.message : \"Simulation failed\",\n logs: [],\n accountChanges: [],\n tokenChanges: [],\n computeUnitsConsumed: 0,\n programIds: [],\n fee: 0,\n rawLogs: [],\n };\n }\n}\n\n// Parsing\nfunction parseSimulationResult(\n value: any,\n signerPublicKey: string,\n txBuffer: Buffer,\n): SimulationResult {\n const success = !value.err;\n const logs: string[] = value.logs ?? [];\n\n // Parse account balance changes\n const accountChanges: AccountChange[] = (value.accounts ?? [])\n .map((account: any, i: number) => {\n if (!account) return null;\n const preBalance = account.lamports ?? 0;\n const postBalance = account.lamports ?? 0;\n return {\n address: signerPublicKey, // simplified — full impl maps account indices\n preBalance,\n postBalance,\n solDelta: (postBalance - preBalance) / LAMPORTS_PER_SOL,\n isWritable: true,\n isSigner: i === 0,\n };\n })\n .filter(Boolean);\n\n // Extract program IDs from logs\n const programIds = extractProgramIds(logs);\n\n // Compute units from logs\n const computeUnitsConsumed = extractComputeUnits(logs);\n\n // Estimate fee (5000 lamports base + 5000 per signature)\n const fee = 5000;\n\n return {\n success,\n error: value.err ? JSON.stringify(value.err) : null,\n logs: formatLogs(logs),\n accountChanges,\n tokenChanges: [], // full SPL parsing requires additional RPC calls\n computeUnitsConsumed,\n programIds,\n fee,\n rawLogs: logs,\n };\n}\n\nfunction extractProgramIds(logs: string[]): string[] {\n const ids = new Set<string>();\n const invokePattern = /Program (\\w+) invoke/;\n for (const log of logs) {\n const match = log.match(invokePattern);\n if (match) ids.add(match[1]);\n }\n return Array.from(ids);\n}\n\nfunction extractComputeUnits(logs: string[]): number {\n for (const log of logs) {\n const match = log.match(/consumed (\\d+) of/);\n if (match) return parseInt(match[1], 10);\n }\n return 0;\n}\n\nfunction formatLogs(logs: string[]): string[] {\n return logs.map((log) => {\n // Shorten program addresses for readability\n return log.replace(/\\b([1-9A-HJ-NP-Za-km-z]{32,44})\\b/g, (addr) => {\n const known = KNOWN_PROGRAMS[addr];\n return known ? known : `${addr.slice(0, 4)}..${addr.slice(-4)}`;\n });\n });\n}\n\n// Known Programs\nconst KNOWN_PROGRAMS: Record<string, string> = {\n \"11111111111111111111111111111111\": \"System Program\",\n TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: \"SPL Token\",\n JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4: \"Jupiter V6\",\n \"9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin\": \"Serum DEX\",\n ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJe1bv: \"Associated Token\",\n SysvarRent111111111111111111111111111111111: \"Sysvar Rent\",\n SysvarC1ock11111111111111111111111111111111: \"Sysvar Clock\",\n};\n\nexport { KNOWN_PROGRAMS };\n","/**\n *\n * Transaction signing and broadcasting.\n *\n * Two methods:\n * signTransaction → sign only, return signed tx bytes (dApp broadcasts)\n * signAndSendTransaction → sign + broadcast, return tx hash\n *\n * Both are supported so any dApp works regardless of which method it uses.\n *\n * Dependencies: @solana/web3.js, tweetnacl, bs58\n */\n\nimport {\n Connection,\n Transaction,\n VersionedTransaction,\n SendOptions,\n Keypair,\n} from \"@solana/web3.js\";\nimport nacl from \"tweetnacl\";\nimport bs58 from \"bs58\";\nimport { getConnection } from \"./rpc\";\nimport { AccountKeypair } from \"../vault/accounts\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface SignedTransaction {\n serialized: string; // base64 encoded signed transaction\n signature: string; // base58 encoded signature (first signature)\n}\n\nexport interface SendResult {\n txHash: string; // transaction signature / hash\n confirmed: boolean;\n}\n\n// ── Sign Only ─────────────────────────────────────────────────────────────────\n\n/**\n * Sign a transaction without broadcasting.\n * Returns the signed transaction for the dApp to broadcast.\n * Used for: solana_signTransaction\n */\nexport async function signTransaction(\n serializedTx: string,\n keypair: AccountKeypair,\n): Promise<SignedTransaction> {\n const txBuffer = Buffer.from(serializedTx, \"base64\");\n const solanaKeypair = toSolanaKeypair(keypair);\n\n try {\n // Try versioned transaction first\n const versionedTx = VersionedTransaction.deserialize(txBuffer);\n versionedTx.sign([solanaKeypair]);\n\n const serialized = Buffer.from(versionedTx.serialize()).toString(\"base64\");\n const signature = bs58.encode(versionedTx.signatures[0]);\n\n return { serialized, signature };\n } catch {\n // Fall back to legacy transaction\n const legacyTx = Transaction.from(txBuffer);\n legacyTx.partialSign(solanaKeypair);\n\n const serialized = legacyTx\n .serialize({ requireAllSignatures: false })\n .toString(\"base64\");\n const signature = bs58.encode(legacyTx.signature!);\n\n return { serialized, signature };\n }\n}\n\n/**\n * Sign multiple transactions in a batch.\n * Used for: solana_signAllTransactions\n */\nexport async function signAllTransactions(\n serializedTxs: string[],\n keypair: AccountKeypair,\n): Promise<SignedTransaction[]> {\n return Promise.all(serializedTxs.map((tx) => signTransaction(tx, keypair)));\n}\n\n// ── Sign and Send ─────────────────────────────────────────────────────────────\n\n/**\n * Sign a transaction and broadcast it to Solana.\n * Returns the transaction hash after confirmation.\n * Used for: solana_signAndSendTransaction\n */\nexport async function signAndSendTransaction(\n serializedTx: string,\n keypair: AccountKeypair,\n options: SendOptions = {},\n conn?: Connection,\n): Promise<SendResult> {\n const { serialized } = await signTransaction(serializedTx, keypair);\n return sendSignedTransaction(serialized, options, conn);\n}\n\n/**\n * Broadcast an already-signed transaction.\n * Used when the wallet has already signed and just needs to broadcast.\n */\nexport async function sendSignedTransaction(\n serializedSignedTx: string,\n options: SendOptions = {},\n conn?: Connection,\n): Promise<SendResult> {\n const connection = conn ?? getConnection();\n const txBuffer = Buffer.from(serializedSignedTx, \"base64\");\n\n const sendOptions: SendOptions = {\n skipPreflight: false, // run preflight checks\n preflightCommitment: \"confirmed\",\n ...options,\n };\n\n let txHash: string;\n\n try {\n // Try versioned first\n const versionedTx = VersionedTransaction.deserialize(txBuffer);\n txHash = await connection.sendTransaction(versionedTx, sendOptions);\n } catch {\n // Fall back to legacy\n const legacyTx = Transaction.from(txBuffer);\n txHash = await connection.sendRawTransaction(\n legacyTx.serialize(),\n sendOptions,\n );\n }\n\n // Wait for confirmation\n const { blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash();\n const confirmResult = await connection.confirmTransaction(\n { signature: txHash, blockhash, lastValidBlockHeight },\n \"confirmed\",\n );\n\n return {\n txHash,\n confirmed: !confirmResult.value.err,\n };\n}\n\n// ── Message Signing ───────────────────────────────────────────────────────────\n\n/**\n * Sign an off-chain message (for authentication / proof of ownership).\n * Used for: solana_signMessage\n * Returns base58 encoded signature.\n */\nexport function signOffchainMessage(\n message: Uint8Array,\n keypair: AccountKeypair,\n): string {\n const signature = nacl.sign.detached(message, keypair.secretKey);\n return bs58.encode(Buffer.from(signature));\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\n/**\n * Convert our AccountKeypair to a @solana/web3.js Keypair.\n * The secretKey is already in the correct 64-byte format.\n */\nfunction toSolanaKeypair(keypair: AccountKeypair): Keypair {\n return Keypair.fromSecretKey(keypair.secretKey);\n}\n","/**\n *\n * Rich terminal UI built with ink (React for terminals).\n * Runs when the daemon starts — shows live activity log,\n * account info, connected dApps, agent statuses, and an\n * always-ready command prompt at the bottom.\n *\n * Two views:\n * Dashboard — live overview of everything happening\n * Accounts — account list with balances\n *\n * The bottom command bar replaces the readline REPL.\n * Prompts (password, select, confirm) appear inline.\n */\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { render, Box, Text, useInput, useApp } from \"ink\";\nimport chalk from \"chalk\";\nimport { getCluster, WalletVault } from \"../vault\";\nimport { vaultExists, loadVault, saveVault } from \"../vault/keystore\";\nimport { generateMnemonic, mnemonicToSeed } from \"../vault/mnemonic\";\nimport { deriveAccount } from \"../vault/accounts\";\nimport { createConfig, saveConfig } from \"../vault/config\";\nimport { getBalance } from \"../solana/rpc\";\nimport {\n cmdLock,\n cmdAccounts,\n cmdNewAccount,\n cmdUseAccount,\n cmdAirdrop,\n cmdConnect,\n cmdSessions,\n cmdDisconnect,\n cmdSetCluster,\n cmdSend,\n} from \"./commands\";\nimport { getAllSessions } from \"../session\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\ninterface LogEntry {\n time: string;\n source: string;\n message: string;\n type: \"info\" | \"success\" | \"error\" | \"warn\";\n}\n\ninterface AgentStatus {\n id: string;\n name: string;\n running: boolean;\n runCount: number;\n error?: string;\n}\n\ninterface DashboardProps {\n vault: WalletVault;\n agentStatus: AgentStatus[];\n onExit: () => void;\n}\n\n// Inline prompt state machine\ntype PromptState =\n | null\n | { type: \"password\"; question: string }\n | { type: \"select\"; message: string; choices: { name: string; value: any }[] }\n | { type: \"confirm\"; message: string; defaultYes: boolean };\n\n// ── Utilities ─────────────────────────────────────────────────────────────────\n\nfunction stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n// ── Log Colors ────────────────────────────────────────────────────────────────\n\nfunction logColor(type: LogEntry[\"type\"]): string {\n switch (type) {\n case \"success\":\n return \"green\";\n case \"error\":\n return \"red\";\n case \"warn\":\n return \"yellow\";\n default:\n return \"gray\";\n }\n}\n\n// ── Components ────────────────────────────────────────────────────────────────\n\nfunction Header({ cluster }: { cluster: string }) {\n return (\n <Box flexDirection=\"column\" marginBottom={1}>\n <Box>\n <Text bold color=\"cyan\">\n ⬡ Agentic Wallet\n </Text>\n <Text color=\"gray\"> {cluster}</Text>\n </Box>\n <Text color=\"gray\">{\"─\".repeat(60)}</Text>\n </Box>\n );\n}\n\nfunction AccountRow({\n index,\n name,\n publicKey,\n balance,\n isActive,\n}: {\n index: number;\n name: string;\n publicKey: string;\n balance: string;\n isActive: boolean;\n}) {\n return (\n <Box>\n <Text color={isActive ? \"green\" : \"gray\"}>{isActive ? \"●\" : \"○\"} </Text>\n <Text color=\"gray\">[{index}] </Text>\n <Text bold={isActive}>{name.padEnd(18)}</Text>\n <Text color=\"gray\">\n {publicKey.slice(0, 6)}...{publicKey.slice(-4)}{\" \"}\n </Text>\n <Text color={isActive ? \"cyan\" : \"gray\"}>{balance}</Text>\n </Box>\n );\n}\n\nfunction SessionRow({\n name,\n url,\n account,\n}: {\n name: string;\n url: string;\n account: string;\n}) {\n return (\n <Box>\n <Text color=\"green\">◉ </Text>\n <Text bold>{name.padEnd(20)}</Text>\n <Text color=\"gray\">{url.slice(0, 30).padEnd(32)}</Text>\n <Text color=\"gray\">\n {account.slice(0, 6)}...{account.slice(-4)}\n </Text>\n </Box>\n );\n}\n\nfunction AgentRow({ agent }: { agent: AgentStatus }) {\n return (\n <Box>\n <Text color={agent.running ? \"green\" : \"gray\"}>\n {agent.running ? \"▶\" : \"■\"}{\" \"}\n </Text>\n <Text bold={agent.running}>{agent.id.padEnd(22)}</Text>\n <Text color={agent.running ? \"cyan\" : \"gray\"}>\n {agent.running ? \"RUNNING\" : \"STOPPED\"}\n {\" \"}\n </Text>\n <Text color=\"gray\">runs: {agent.runCount}</Text>\n {agent.error && <Text color=\"red\"> ⚠ {agent.error.slice(0, 30)}</Text>}\n </Box>\n );\n}\n\nfunction LogRow({ entry }: { entry: LogEntry }) {\n return (\n <Box>\n <Text color=\"gray\">{entry.time} </Text>\n <Text color=\"cyan\">{entry.source.padEnd(20)}</Text>\n <Text color={logColor(entry.type)}>{entry.message}</Text>\n </Box>\n );\n}\n\n// ── Prompt Display ─────────────────────────────────────────────────────────────\n\nfunction PromptRow({\n prompt,\n maskLen,\n cursor,\n}: {\n prompt: Exclude<PromptState, null>;\n maskLen: number;\n cursor: number;\n}) {\n if (prompt.type === \"password\") {\n return (\n <Box>\n <Text bold color=\"cyan\">\n {prompt.question}{\" \"}\n </Text>\n <Text color=\"gray\">{\"*\".repeat(maskLen)}</Text>\n <Text color=\"green\">█</Text>\n </Box>\n );\n }\n\n if (prompt.type === \"select\") {\n return (\n <Box flexDirection=\"column\">\n <Text bold>{prompt.message}</Text>\n {prompt.choices.map((c, i) => (\n <Box key={i}>\n <Text color={i === cursor ? \"cyan\" : \"gray\"}>\n {i === cursor ? \"❯ \" : \" \"}\n {c.name}\n </Text>\n </Box>\n ))}\n </Box>\n );\n }\n\n if (prompt.type === \"confirm\") {\n const hint = prompt.defaultYes ? \"Y/n\" : \"y/N\";\n return (\n <Box>\n <Text bold>{prompt.message} </Text>\n <Text color=\"gray\">[{hint}]</Text>\n </Box>\n );\n }\n\n return null;\n}\n\n// ── Command Bar ────────────────────────────────────────────────────────────────\n\nfunction CommandBar({ buffer, running }: { buffer: string; running: boolean }) {\n return (\n <Box>\n <Text color=\"green\" bold>\n wallet\n </Text>\n <Text color=\"gray\"> › </Text>\n {running ? (\n <Text color=\"yellow\" dimColor>\n running…\n </Text>\n ) : (\n <Text>\n {buffer}\n <Text color=\"green\">█</Text>\n </Text>\n )}\n </Box>\n );\n}\n\n// ── Dashboard ─────────────────────────────────────────────────────────────────\n\nfunction Dashboard({ vault, agentStatus, onExit }: DashboardProps) {\n const { exit } = useApp();\n const [view, setView] = useState<\"dashboard\" | \"accounts\">(\"dashboard\");\n const [accounts, setAccounts] = useState<any[]>([]);\n const [balances, setBalances] = useState<Record<string, string>>({});\n const [sessions, setSessions] = useState<any[]>([]);\n const [cluster, setCluster] = useState(\"devnet\");\n\n // Command input\n const [cmdBuffer, setCmdBuffer] = useState(\"\");\n const [cmdRunning, setCmdRunning] = useState(false);\n\n // Inline prompt\n const [promptState, setPromptState] = useState<PromptState>(null);\n const promptResolverRef = useRef<((val: any) => void) | null>(null);\n const passwordValueRef = useRef(\"\");\n const [passwordMaskLen, setPasswordMaskLen] = useState(0);\n const selectCursorRef = useRef(0);\n const [selectCursor, setSelectCursor] = useState(0);\n\n // Log subscription\n const [uiLogs, setUiLogs] = useState<LogEntry[]>([...logBuffer]);\n\n // Load data on mount\n useEffect(() => {\n const interval = setInterval(() => {\n try {\n const keypairs = vault.getAllKeypairs();\n setAccounts(keypairs);\n setCluster(getCluster());\n setSessions(getAllSessions());\n\n keypairs.forEach(async (kp) => {\n try {\n const { sol } = await getBalance(kp.publicKey);\n setBalances((prev) => ({\n ...prev,\n [kp.publicKey]: sol.toFixed(4) + \" SOL\",\n }));\n } catch {\n setBalances((prev) => ({ ...prev, [kp.publicKey]: \"...\" }));\n }\n });\n } catch {}\n }, 2000);\n return () => clearInterval(interval);\n }, []);\n\n // Refresh sessions every 5s\n useEffect(() => {\n const interval = setInterval(() => setSessions(getAllSessions()), 5000);\n return () => clearInterval(interval);\n }, []);\n\n // Subscribe to logs\n useEffect(() => {\n const fn = (updated: LogEntry[]) => setUiLogs(updated);\n logListeners.push(fn);\n return () => {\n const idx = logListeners.indexOf(fn);\n if (idx >= 0) logListeners.splice(idx, 1);\n };\n }, []);\n\n // ── Prompt helpers ──────────────────────────────────────────────────────────\n\n const requestPrompt = <T,>(state: Exclude<PromptState, null>): Promise<T> =>\n new Promise((resolve) => {\n promptResolverRef.current = resolve as (v: any) => void;\n if (state.type === \"password\") {\n passwordValueRef.current = \"\";\n setPasswordMaskLen(0);\n }\n if (state.type === \"select\") {\n selectCursorRef.current = 0;\n setSelectCursor(0);\n }\n setPromptState(state);\n });\n\n const resolvePrompt = (val: any) => {\n promptResolverRef.current?.(val);\n promptResolverRef.current = null;\n passwordValueRef.current = \"\";\n setPasswordMaskLen(0);\n selectCursorRef.current = 0;\n setSelectCursor(0);\n setPromptState(null);\n };\n\n // ── Console capture ─────────────────────────────────────────────────────────\n\n const withCapture = async (fn: () => Promise<void>) => {\n const origLog = console.log;\n const origError = console.error;\n\n console.log = (...args: any[]) => {\n const msg = stripAnsi(args.map(String).join(\" \")).trim();\n if (msg) addLog(\"wallet\", msg, \"info\");\n };\n console.error = (...args: any[]) => {\n const msg = stripAnsi(args.map(String).join(\" \")).trim();\n if (msg) addLog(\"wallet\", msg, \"error\");\n };\n\n try {\n await fn();\n } finally {\n console.log = origLog;\n console.error = origError;\n }\n };\n\n // ── Inline init ─────────────────────────────────────────────────────────────\n\n const handleInit = async () => {\n if (vaultExists()) {\n addLog(\n \"wallet\",\n \"Vault already exists. Use `unlock` to access it.\",\n \"warn\",\n );\n return;\n }\n\n const wordCount = await requestPrompt<12 | 24>({\n type: \"select\",\n message: \"Mnemonic length:\",\n choices: [\n { name: \"12 words (standard)\", value: 12 },\n { name: \"24 words (extra secure)\", value: 24 },\n ],\n });\n\n const { mnemonic } = generateMnemonic(wordCount);\n addLog(\n \"wallet\",\n \"⚠ Write down your seed phrase and store it safely.\",\n \"warn\",\n );\n addLog(\"wallet\", mnemonic, \"warn\");\n\n const confirmed = await requestPrompt<boolean>({\n type: \"confirm\",\n message: \"I have written down my seed phrase\",\n defaultYes: false,\n });\n\n if (!confirmed) {\n addLog(\"wallet\", \"Aborted.\", \"error\");\n return;\n }\n\n const password = await requestPrompt<string>({\n type: \"password\",\n question: \"Set vault password:\",\n });\n\n const confirmPw = await requestPrompt<string>({\n type: \"password\",\n question: \"Confirm password:\",\n });\n\n if (password !== confirmPw) {\n addLog(\"wallet\", \"Passwords do not match.\", \"error\");\n return;\n }\n\n const seed = await mnemonicToSeed(mnemonic);\n const firstKp = deriveAccount(seed, 0, \"Main\");\n\n await saveVault(\n { mnemonic, createdAt: new Date().toISOString(), version: 1 },\n password,\n );\n\n const cfg = createConfig(\"\");\n cfg.accountStore.accounts[0] = {\n index: 0,\n name: \"Main\",\n publicKey: firstKp.publicKey,\n derivationPath: `m/44'/501'/0'/0'`,\n createdAt: new Date().toISOString(),\n };\n saveConfig(cfg);\n\n addLog(\"wallet\", `✓ Wallet created — ${firstKp.publicKey}`, \"success\");\n };\n\n // ── Inline unlock ───────────────────────────────────────────────────────────\n\n const handleUnlock = async () => {\n if (!vaultExists()) {\n addLog(\"wallet\", \"No vault found. Run: init\", \"error\");\n return;\n }\n\n const password = await requestPrompt<string>({\n type: \"password\",\n question: \"Vault password:\",\n });\n\n try {\n await loadVault(password);\n addLog(\"wallet\", \"✓ Wallet unlocked\", \"success\");\n } catch {\n addLog(\"wallet\", \"Wrong password.\", \"error\");\n }\n };\n\n // ── Inline send ─────────────────────────────────────────────────────────────\n\n const handleSend = async (to: string, amount: number) => {\n if (!to || !amount) {\n addLog(\"wallet\", \"Usage: send <address> <sol>\", \"warn\");\n return;\n }\n\n const confirmed = await requestPrompt<boolean>({\n type: \"confirm\",\n message: `Send ${amount} SOL to ${to.slice(0, 8)}...${to.slice(-4)}?`,\n defaultYes: false,\n });\n\n if (!confirmed) {\n addLog(\"wallet\", \"Cancelled.\", \"warn\");\n return;\n }\n\n await withCapture(() => cmdSend(to, amount, vault));\n };\n\n // ── Command executor ────────────────────────────────────────────────────────\n\n const executeCommand = async (line: string) => {\n const parts = line.trim().split(/\\s+/);\n const cmd = parts[0];\n\n setCmdRunning(true);\n addLog(\"wallet\", `> ${line}`, \"info\");\n\n try {\n switch (cmd) {\n case \"\":\n break;\n\n case \"help\":\n addLog(\n \"wallet\",\n \"init unlock lock accounts [new|use] send <addr> <sol> airdrop [sol] connect <wc:uri> sessions disconnect <dapp> cluster <name> exit\",\n \"info\",\n );\n break;\n\n case \"exit\":\n case \"quit\":\n onExit();\n exit();\n break;\n\n case \"init\":\n await handleInit();\n break;\n\n case \"unlock\":\n await handleUnlock();\n break;\n\n case \"lock\":\n await withCapture(async () => cmdLock());\n break;\n\n case \"send\":\n await handleSend(parts[1], Number(parts[2]));\n break;\n\n case \"airdrop\":\n await withCapture(() => cmdAirdrop(Number(parts[1]) || 1));\n break;\n\n case \"connect\":\n await withCapture(() => cmdConnect(parts[1]));\n break;\n\n case \"sessions\":\n await withCapture(async () => cmdSessions());\n break;\n\n case \"disconnect\":\n await withCapture(() => cmdDisconnect(parts.slice(1).join(\" \")));\n break;\n\n case \"cluster\":\n await withCapture(async () => cmdSetCluster(parts[1]));\n break;\n\n case \"accounts\":\n if (parts[1] === \"new\") {\n await withCapture(() => cmdNewAccount(parts.slice(2).join(\" \")));\n } else if (parts[1] === \"use\") {\n await withCapture(() => cmdUseAccount(parts[2]));\n } else {\n await withCapture(() => cmdAccounts());\n }\n break;\n\n default:\n addLog(\"wallet\", `Unknown: ${cmd}. Type \"help\".`, \"warn\");\n }\n } catch (err: any) {\n addLog(\"wallet\", `Error: ${err.message}`, \"error\");\n } finally {\n setCmdRunning(false);\n }\n };\n\n // ── Input handling ──────────────────────────────────────────────────────────\n\n useInput((input, key) => {\n // Always allow Ctrl+C to quit\n if (key.ctrl && input === \"c\") {\n onExit();\n exit();\n return;\n }\n\n // Route input to active prompt\n if (promptState) {\n if (promptState.type === \"password\") {\n if (key.return) {\n resolvePrompt(passwordValueRef.current);\n } else if (key.backspace || key.delete) {\n if (passwordValueRef.current.length > 0) {\n passwordValueRef.current = passwordValueRef.current.slice(0, -1);\n setPasswordMaskLen(passwordValueRef.current.length);\n }\n } else if (input && !key.ctrl && !key.meta) {\n passwordValueRef.current += input;\n setPasswordMaskLen(passwordValueRef.current.length);\n }\n return;\n }\n\n if (promptState.type === \"select\") {\n if (key.upArrow) {\n const n = Math.max(0, selectCursorRef.current - 1);\n selectCursorRef.current = n;\n setSelectCursor(n);\n } else if (key.downArrow) {\n const n = Math.min(\n promptState.choices.length - 1,\n selectCursorRef.current + 1,\n );\n selectCursorRef.current = n;\n setSelectCursor(n);\n } else if (key.return) {\n resolvePrompt(promptState.choices[selectCursorRef.current].value);\n }\n return;\n }\n\n if (promptState.type === \"confirm\") {\n if (key.return) {\n resolvePrompt(promptState.defaultYes);\n } else if (input === \"y\" || input === \"Y\") {\n resolvePrompt(true);\n } else if (input === \"n\" || input === \"N\") {\n resolvePrompt(false);\n }\n return;\n }\n }\n\n // Navigation shortcuts — only when buffer is empty and not running\n if (!cmdBuffer && !cmdRunning) {\n if (input === \"1\") {\n setView(\"dashboard\");\n return;\n }\n if (input === \"2\") {\n setView(\"accounts\");\n return;\n }\n if (input === \"q\") {\n onExit();\n exit();\n return;\n }\n }\n\n // Don't accept new command input while running\n if (cmdRunning) return;\n\n // Command input\n if (key.return) {\n const cmd = cmdBuffer.trim();\n setCmdBuffer(\"\");\n if (cmd) executeCommand(cmd);\n return;\n }\n\n if (key.backspace || key.delete) {\n setCmdBuffer((b) => b.slice(0, -1));\n return;\n }\n\n if (input && !key.ctrl && !key.meta && !key.escape) {\n setCmdBuffer((b) => b + input);\n }\n });\n\n const activeKeypair = (() => {\n try {\n return vault.getActiveKeypair();\n } catch {\n return null;\n }\n })();\n\n const recentLogs = uiLogs.slice(-12);\n\n // ── Render ──────────────────────────────────────────────────────────────────\n\n return (\n <Box flexDirection=\"column\" padding={1}>\n <Header cluster={cluster} />\n\n {/* Nav */}\n <Box marginBottom={1}>\n <Text\n color={view === \"dashboard\" ? \"cyan\" : \"gray\"}\n bold={view === \"dashboard\"}\n >\n [1] Dashboard{\" \"}\n </Text>\n <Text\n color={view === \"accounts\" ? \"cyan\" : \"gray\"}\n bold={view === \"accounts\"}\n >\n [2] Accounts{\" \"}\n </Text>\n <Text color=\"gray\"> q: quit</Text>\n </Box>\n\n {view === \"dashboard\" && (\n <Box flexDirection=\"column\">\n {/* Active Account */}\n <Box marginBottom={1} flexDirection=\"column\">\n <Text bold color=\"white\">\n Active Account\n </Text>\n <Text color=\"gray\">{\"─\".repeat(40)}</Text>\n {activeKeypair ? (\n <Box>\n <Text color=\"green\">● </Text>\n <Text bold>{activeKeypair.name.padEnd(18)}</Text>\n <Text color=\"cyan\">{activeKeypair.publicKey}</Text>\n <Text color=\"gray\">\n {\" \"}\n {balances[activeKeypair.publicKey] ?? \"...\"}\n </Text>\n </Box>\n ) : (\n <Text color=\"gray\">No active account</Text>\n )}\n </Box>\n\n {/* Connected dApps */}\n <Box marginBottom={1} flexDirection=\"column\">\n <Text bold color=\"white\">\n Connected dApps ({sessions.length})\n </Text>\n <Text color=\"gray\">{\"─\".repeat(40)}</Text>\n {sessions.length === 0 ? (\n <Text color=\"gray\">None — paste a wc: URI to connect</Text>\n ) : (\n sessions.map((s) => (\n <SessionRow\n key={s.topic}\n name={s.dappName}\n url={s.dappUrl}\n account={s.connectedAccount}\n />\n ))\n )}\n </Box>\n\n {/* Agents */}\n {agentStatus.length > 0 && (\n <Box marginBottom={1} flexDirection=\"column\">\n <Text bold color=\"white\">\n Agents ({agentStatus.filter((a) => a.running).length} running)\n </Text>\n <Text color=\"gray\">{\"─\".repeat(40)}</Text>\n {agentStatus.map((agent) => (\n <AgentRow key={agent.id} agent={agent} />\n ))}\n </Box>\n )}\n\n {/* Activity Log */}\n <Box flexDirection=\"column\">\n <Text bold color=\"white\">\n Activity\n </Text>\n <Text color=\"gray\">{\"─\".repeat(40)}</Text>\n {recentLogs.length === 0 ? (\n <Text color=\"gray\">Waiting for activity…</Text>\n ) : (\n recentLogs.map((entry, i) => <LogRow key={i} entry={entry} />)\n )}\n </Box>\n </Box>\n )}\n\n {view === \"accounts\" && (\n <Box flexDirection=\"column\">\n <Text bold color=\"white\">\n All Accounts\n </Text>\n <Text color=\"gray\">{\"─\".repeat(60)}</Text>\n {accounts.length === 0 ? (\n <Text color=\"gray\">No accounts found</Text>\n ) : (\n accounts.map((acc) => (\n <AccountRow\n key={acc.publicKey}\n index={acc.index}\n name={acc.name}\n publicKey={acc.publicKey}\n balance={balances[acc.publicKey] ?? \"...\"}\n isActive={acc.publicKey === activeKeypair?.publicKey}\n />\n ))\n )}\n </Box>\n )}\n\n {/* Footer */}\n <Box marginTop={1}>\n <Text color=\"gray\">{\"─\".repeat(60)}</Text>\n </Box>\n <Box>\n <Text color=\"gray\">WebSocket: </Text>\n <Text color=\"cyan\">ws://localhost:3000</Text>\n <Text color=\"gray\"> │ [1] Dashboard [2] Accounts [q] Quit</Text>\n </Box>\n\n {/* Command / Prompt area */}\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"gray\">{\"─\".repeat(60)}</Text>\n {promptState ? (\n <PromptRow\n prompt={promptState}\n maskLen={passwordMaskLen}\n cursor={selectCursor}\n />\n ) : (\n <CommandBar buffer={cmdBuffer} running={cmdRunning} />\n )}\n </Box>\n </Box>\n );\n}\n\n// ── Log Store ─────────────────────────────────────────────────────────────────\n\nconst logBuffer: LogEntry[] = [];\nconst logListeners: Array<(logs: LogEntry[]) => void> = [];\n\nexport function addLog(\n source: string,\n message: string,\n type: LogEntry[\"type\"] = \"info\",\n): void {\n const entry: LogEntry = {\n time: new Date().toTimeString().slice(0, 8),\n source,\n message,\n type,\n };\n logBuffer.push(entry);\n if (logBuffer.length > 200) logBuffer.shift();\n logListeners.forEach((fn) => fn([...logBuffer]));\n}\n\n// ── Render ────────────────────────────────────────────────────────────────────\n\nexport function startInkUI(\n vault: WalletVault,\n getAgentStatus: () => AgentStatus[],\n onExit: () => void,\n): void {\n function App() {\n const [agentStatus, setAgentStatus] = useState<any[]>(getAgentStatus());\n\n useEffect(() => {\n const interval = setInterval(\n () => setAgentStatus(getAgentStatus()),\n 2000,\n );\n return () => clearInterval(interval);\n }, []);\n\n return (\n <Dashboard vault={vault} agentStatus={agentStatus} onExit={onExit} />\n );\n }\n\n render(<App />);\n}\n","import chalk from \"chalk\";\nimport { generateMnemonic, mnemonicToSeed } from \"../vault/mnemonic\";\nimport { saveVault, loadVault, vaultExists } from \"../vault/keystore\";\nimport { deriveAccount } from \"../vault/accounts\";\nimport { getBalance, requestAirdrop, getConnection } from \"../solana/rpc\";\nimport { WalletVault } from \"../vault\";\nimport {\n updateCluster,\n loadConfig,\n updateAccountStore,\n createConfig,\n saveConfig,\n} from \"../vault/config\";\nimport { pairWithDapp, disconnectDapp } from \"../handler/walletConnect\";\nimport { inkPassword, inkSelect, inkConfirm } from \"./prompts\";\nimport { getAllSessions } from \"../session\";\n\n// ── In-memory session ─────────────────────────────────────────────────────────\n\nlet sessionPassword: string | null = null;\nlet sessionMnemonic: string | null = null;\n\nexport function isUnlocked(): boolean {\n return sessionMnemonic !== null;\n}\n\nasync function requireUnlocked(): Promise<{\n password: string;\n mnemonic: string;\n}> {\n if (!sessionPassword || !sessionMnemonic) {\n throw new Error(\"Wallet is locked. Run: wallet unlock\");\n }\n return { password: sessionPassword, mnemonic: sessionMnemonic };\n}\n\n// ── init ──────────────────────────────────────────────────────────────────────\n\nexport async function cmdInit(): Promise<void> {\n if (vaultExists()) {\n console.log(\n chalk.yellow(\"Vault already exists. Use `wallet unlock` to access it.\"),\n );\n return;\n }\n\n const wordCount = await inkSelect<12 | 24>(\"Mnemonic length:\", [\n { name: \"12 words (standard)\", value: 12 },\n { name: \"24 words (extra secure)\", value: 24 },\n ]);\n\n const { mnemonic } = generateMnemonic(wordCount);\n\n console.log(\n chalk.bold(\"\\n⚠️ Write down your seed phrase. Store it safely.\\n\"),\n );\n console.log(chalk.yellow(mnemonic));\n console.log();\n\n const confirmed = await inkConfirm(\n \"I have written down my seed phrase\",\n false,\n );\n if (!confirmed) {\n console.log(chalk.red(\"Aborted.\"));\n return;\n }\n\n const password = await inkPassword(\"Set vault password:\");\n\n const confirm = await inkPassword(\"Confirm password:\");\n\n if (password !== confirm) {\n console.log(chalk.red(\"Passwords do not match.\"));\n return;\n }\n\n // Derive first account public key\n const seed = await mnemonicToSeed(mnemonic);\n const firstKp = deriveAccount(seed, 0, \"Main\");\n\n // Save encrypted vault (mnemonic only)\n await saveVault(\n { mnemonic, createdAt: new Date().toISOString(), version: 1 },\n password,\n );\n\n // Save account metadata to config\n const config = createConfig(\"\");\n config.accountStore.accounts[0] = {\n index: 0,\n name: \"Main\",\n publicKey: firstKp.publicKey,\n derivationPath: `m/44'/501'/0'/0'`,\n createdAt: new Date().toISOString(),\n };\n saveConfig(config);\n\n sessionPassword = password;\n sessionMnemonic = mnemonic;\n\n console.log(chalk.green(\"\\n✓ Wallet created\"));\n console.log(chalk.dim(` Address: ${firstKp.publicKey}`));\n}\n\n// ── unlock ────────────────────────────────────────────────────────────────────\n\nexport async function cmdUnlock(): Promise<void> {\n if (!vaultExists()) {\n console.log(chalk.red(\"No vault found. Run: wallet init\"));\n return;\n }\n\n const password = await inkPassword(\"Vault password:\");\n\n try {\n const vault = await loadVault(password);\n sessionPassword = password;\n sessionMnemonic = vault.mnemonic;\n console.log(chalk.green(\"✓ Wallet unlocked\"));\n } catch {\n console.log(chalk.red(\"Wrong password.\"));\n }\n}\n\n// ── lock ──────────────────────────────────────────────────────────────────────\n\nexport function cmdLock(): void {\n sessionPassword = null;\n sessionMnemonic = null;\n console.log(chalk.green(\"✓ Wallet locked\"));\n}\n\n// ── accounts ──────────────────────────────────────────────────────────────────\n\nexport async function cmdAccounts(): Promise<void> {\n await requireUnlocked();\n const config = loadConfig();\n\n console.log(chalk.bold(\"\\n── Accounts ─────────────────────────\"));\n for (const entry of config.accountStore.accounts) {\n const active = entry.index === config.accountStore.activeIndex;\n const marker = active ? chalk.green(\"●\") : chalk.dim(\"○\");\n let balance = \"...\";\n try {\n const { sol } = await getBalance(entry.publicKey);\n balance = sol.toFixed(4) + \" SOL\";\n } catch {}\n console.log(\n ` ${marker} [${entry.index}] ${entry.name.padEnd(16)} ${entry.publicKey} ${balance}`,\n );\n }\n console.log(chalk.dim(`\\n Network: ${config.cluster} (${config.rpcUrl})`));\n console.log(\"─────────────────────────────────────\\n\");\n}\n\n// ── accounts new ──────────────────────────────────────────────────────────────\n\nexport async function cmdNewAccount(name: string): Promise<void> {\n const { mnemonic } = await requireUnlocked();\n const config = loadConfig();\n const nextIndex = config.accountStore.accounts.length;\n const accountName = name || `Account ${nextIndex + 1}`;\n const seed = await mnemonicToSeed(mnemonic);\n const keypair = deriveAccount(seed, nextIndex, accountName);\n\n updateAccountStore({\n ...config.accountStore,\n accounts: [\n ...config.accountStore.accounts,\n {\n index: nextIndex,\n name: accountName,\n publicKey: keypair.publicKey,\n derivationPath: `m/44'/501'/${nextIndex}'/0'`,\n createdAt: new Date().toISOString(),\n },\n ],\n });\n\n console.log(chalk.green(`✓ Account created: ${accountName}`));\n console.log(chalk.dim(` Address: ${keypair.publicKey}`));\n}\n\n// ── accounts use ──────────────────────────────────────────────────────────────\n\nexport async function cmdUseAccount(nameOrIndex: string): Promise<void> {\n await requireUnlocked();\n const config = loadConfig();\n const found = config.accountStore.accounts.find(\n (a) => a.name === nameOrIndex || a.index === parseInt(nameOrIndex),\n );\n if (!found) {\n console.log(chalk.red(`Account not found: ${nameOrIndex}`));\n return;\n }\n\n updateAccountStore({ ...config.accountStore, activeIndex: found.index });\n console.log(\n chalk.green(`✓ Active account: ${found.name} (${found.publicKey})`),\n );\n}\n\n// ── airdrop ───────────────────────────────────────────────────────────────────\n\nexport async function cmdAirdrop(sol: number = 1): Promise<void> {\n await requireUnlocked();\n const config = loadConfig();\n const active = config.accountStore.accounts.find(\n (a) => a.index === config.accountStore.activeIndex,\n );\n if (!active) {\n console.log(chalk.red(\"No active account.\"));\n return;\n }\n\n console.log(chalk.dim(`Requesting ${sol} SOL airdrop...`));\n try {\n const sig = await requestAirdrop(active.publicKey, sol);\n console.log(chalk.green(`✓ Airdrop complete`));\n console.log(chalk.dim(` tx: ${sig}`));\n } catch (err: any) {\n console.log(chalk.red(`Airdrop failed: ${err.message}`));\n }\n}\n\n// ── connect ───────────────────────────────────────────────────────────────────\n\nexport async function cmdConnect(wcUri: string): Promise<void> {\n if (!wcUri || !wcUri.startsWith(\"wc:\")) {\n console.log(chalk.red(\"Invalid WalletConnect URI. Must start with wc:\"));\n return;\n }\n console.log(chalk.dim(\"Pairing with dApp...\"));\n await pairWithDapp(wcUri);\n}\n\n// ── sessions ──────────────────────────────────────────────────────────────────\n\nexport function cmdSessions(): void {\n const sessions = getAllSessions();\n if (sessions.length === 0) {\n console.log(chalk.dim(\"No active sessions.\"));\n return;\n }\n\n console.log(chalk.bold(\"\\n── Connected dApps ──────────────────\"));\n sessions.forEach((s) => {\n console.log(\n ` ${chalk.cyan(s.dappName.padEnd(20))} ` +\n `${s.connectedAccount.slice(0, 8)}... ` +\n `since ${s.connectedAt.slice(0, 10)}`,\n );\n console.log(\n chalk.dim(` ${s.dappUrl} topic: ${s.topic.slice(0, 8)}...`),\n );\n });\n console.log(\"─────────────────────────────────────\\n\");\n}\n\n// ── disconnect ────────────────────────────────────────────────────────────────\n\nexport async function cmdDisconnect(dappName: string): Promise<void> {\n const sessions = getAllSessions();\n const session = sessions.find((s) =>\n s.dappName.toLowerCase().includes(dappName.toLowerCase()),\n );\n if (!session) {\n console.log(chalk.red(`No session found for: ${dappName}`));\n return;\n }\n await disconnectDapp(session.topic);\n console.log(chalk.green(`✓ Disconnected from ${session.dappName}`));\n}\n\n// ── send ──────────────────────────────────────────────────────────────────────\n\nexport async function cmdSend(\n to: string,\n sol: number,\n vault: WalletVault,\n): Promise<void> {\n const { PublicKey, SystemProgram, Transaction, LAMPORTS_PER_SOL } =\n await import(\"@solana/web3.js\");\n\n const keypair = vault.getActiveKeypair();\n const { Keypair } = await import(\"@solana/web3.js\");\n const solanaKeypair = Keypair.fromSecretKey(keypair.secretKey);\n\n const connection = getConnection();\n const { blockhash, lastValidBlockHeight } =\n await connection.getLatestBlockhash(\"confirmed\");\n\n const tx = new Transaction().add(\n SystemProgram.transfer({\n fromPubkey: solanaKeypair.publicKey,\n toPubkey: new PublicKey(to),\n lamports: Math.round(sol * LAMPORTS_PER_SOL),\n }),\n );\n\n tx.recentBlockhash = blockhash;\n tx.feePayer = solanaKeypair.publicKey;\n tx.sign(solanaKeypair);\n\n const raw = tx.serialize();\n const sig = await connection.sendRawTransaction(raw, {\n skipPreflight: false,\n preflightCommitment: \"confirmed\",\n });\n\n await connection.confirmTransaction(\n { signature: sig, blockhash, lastValidBlockHeight },\n \"confirmed\",\n );\n\n console.log(chalk.green(`✓ Sent ${sol} SOL to ${to}`));\n console.log(chalk.dim(` tx: ${sig}`));\n}\n\n// ── config cluster ────────────────────────────────────────────────────────────\n\nexport function cmdSetCluster(cluster: string): void {\n const valid = [\"mainnet-beta\", \"devnet\", \"testnet\"];\n if (!valid.includes(cluster)) {\n console.log(chalk.red(`Valid clusters: ${valid.join(\", \")}`));\n return;\n }\n updateCluster(cluster as any);\n console.log(chalk.green(`✓ Cluster set to: ${cluster}`));\n}\n","import SignClientPkg from \"@walletconnect/sign-client\";\nconst SignClient = (SignClientPkg as any).default ?? SignClientPkg;\nimport { getSdkError } from \"@walletconnect/utils\";\n\nimport chalk from \"chalk\";\nimport { handleRequest, WalletRequest, HandlerOptions } from \".\";\nimport { markInactive, saveSession, removeSession } from \"../session\";\n\nconst CHAIN_ID = \"solana:devnet\"; // switch to solana:mainnet for production\n\nexport interface WalletConnectOptions {\n projectId: string;\n handlerOptions: HandlerOptions;\n // Callback to display session proposal to user in terminal\n onSessionProposal?: (metadata: any) => Promise<boolean>;\n}\n\nlet signClient: InstanceType<typeof SignClient> | null = null;\n\nexport async function initWalletConnect(opts: WalletConnectOptions) {\n signClient = await SignClient.init({\n projectId: opts.projectId,\n metadata: {\n name: \"Agentic Wallet\",\n description: \"Autonomous AI agent wallet for Solana\",\n url: \"https://github.com/your-repo/agentic-wallet\",\n icons: [],\n },\n });\n\n console.log(chalk.green(\"[WC] WalletConnect initialized\"));\n\n // ── Inbound session proposal (dApp wants to connect) ──────────────────────\n signClient.on(\"session_proposal\", async ({ id, params }: any) => {\n const meta = params.proposer.metadata;\n console.log(\n chalk.cyan(`\\n[WC] Session proposal from: ${meta.name} (${meta.url})`),\n );\n\n // Ask for approval\n let approved = true;\n if (opts.onSessionProposal) {\n approved = await opts.onSessionProposal(meta);\n }\n\n if (!approved) {\n await signClient!.reject({ id, reason: getSdkError(\"USER_REJECTED\") });\n console.log(chalk.red(\"[WC] Session rejected\"));\n return;\n }\n\n const account = opts.handlerOptions.vault.getActiveKeypair();\n\n const { topic, acknowledged } = await signClient!.approve({\n id,\n namespaces: {\n solana: {\n accounts: [`${CHAIN_ID}:${account.publicKey}`],\n methods: [\n \"solana_signTransaction\",\n \"solana_signAndSendTransaction\",\n \"solana_signAllTransactions\",\n \"solana_signMessage\",\n ],\n events: [],\n },\n },\n });\n\n await acknowledged();\n\n saveSession({\n topic,\n dappName: meta.name,\n dappUrl: meta.url,\n dappIcon: meta.icons?.[0],\n connectedAccount: account.publicKey,\n connectedAt: new Date().toISOString(),\n lastActivity: new Date().toISOString(),\n permissions: [\n \"solana_signTransaction\",\n \"solana_signAndSendTransaction\",\n \"solana_signAllTransactions\",\n \"solana_signMessage\",\n ],\n chainId: CHAIN_ID,\n active: true,\n });\n\n console.log(chalk.green(`[WC] Connected to ${meta.name}`));\n console.log(chalk.dim(` Address: ${account.publicKey}`));\n });\n\n // ── Inbound sign request ──────────────────────────────────────────────────\n signClient.on(\"session_request\", async ({ id, topic, params }: any) => {\n const session = signClient!.session.get(topic);\n const dapp = {\n name: session.peer.metadata.name,\n url: session.peer.metadata.url,\n };\n\n console.log(\n chalk.yellow(\n `\\n[WC] Request: ${params.request.method} from ${dapp.name}`,\n ),\n );\n\n const request: WalletRequest = {\n id,\n method: params.request.method as any,\n params: params.request.params,\n dapp,\n topic,\n };\n\n const response = await handleRequest(request, opts.handlerOptions);\n\n // WalletConnect requires either { result } or { error } — never both optional\n const jsonRpcResponse = response.error\n ? {\n id,\n jsonrpc: \"2.0\" as const,\n error: { code: response.error.code, message: response.error.message },\n }\n : { id, jsonrpc: \"2.0\" as const, result: response.result ?? null };\n\n await signClient!.respond({ topic, response: jsonRpcResponse });\n\n if (response.error) {\n console.log(chalk.red(`[WC] Rejected: ${response.error.message}`));\n } else {\n console.log(chalk.green(`[WC] Request fulfilled`));\n }\n });\n\n // ── dApp disconnects ──────────────────────────────────────────────────────\n signClient.on(\"session_delete\", ({ topic }: any) => {\n markInactive(topic);\n console.log(\n chalk.dim(`[WC] dApp disconnected (topic: ${topic.slice(0, 8)}...)`),\n );\n });\n\n return signClient;\n}\n\n// User pastes wc: URI from the dApp.\n// Waits for session_proposal to fire before returning so the\n// caller knows the dApp has received the wallet's address.\nexport async function pairWithDapp(uri: string): Promise<void> {\n if (!signClient) throw new Error(\"WalletConnect not initialised\");\n\n console.log(chalk.dim(\"[WC] Connecting to dApp...\"));\n\n await new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n signClient!.off(\"session_proposal\", onProposal);\n reject(new Error(\"WalletConnect pairing timed out after 30s\"));\n }, 30_000);\n\n // Listen for the session_proposal — fired when dApp receives our pairing\n // The main session_proposal handler in initWalletConnect does approve()\n // and saveSession(). We just wait here to print the result.\n const onProposal = ({ params }: any) => {\n clearTimeout(timeout);\n signClient!.off(\"session_proposal\", onProposal);\n const meta = params.proposer.metadata;\n console.log(\n chalk.cyan(\n `[WC] Request from: ${chalk.bold(meta.name)} (${meta.url})`,\n params,\n ),\n );\n resolve();\n };\n\n signClient!.on(\"session_proposal\", onProposal);\n\n signClient!.core.pairing.pair({ uri }).catch((err: Error) => {\n clearTimeout(timeout);\n signClient!.off(\"session_proposal\", onProposal);\n reject(err);\n });\n });\n}\n\n// Disconnect from a dApp by topic\nexport async function disconnectDapp(topic: string): Promise<void> {\n if (!signClient) throw new Error(\"WalletConnect not initialised\");\n await signClient.disconnect({\n topic,\n reason: getSdkError(\"USER_DISCONNECTED\"),\n });\n removeSession(topic);\n console.log(\n chalk.dim(`[WC] Disconnected from topic ${topic.slice(0, 8)}...`),\n );\n}\n\nexport function getSignClient() {\n return signClient;\n}\n","/**\n *\n * The central request handler — every signing request from every source\n * (WalletConnect, WebSocket, direct import) flows through here.\n *\n * Pipeline for every request:\n * 1. Parse intent (what method, what transaction)\n * 2. Simulate the transaction on Solana\n * 3. Sign (and optionally send)\n * 4. Return result to caller\n *\n * No request bypasses this pipeline.\n *\n * Dependencies: ../solana/simulate, ../solana/tx, ../vault\n */\n\nimport { simulateTransaction } from \"../solana/simulate\";\nimport {\n signTransaction,\n signAllTransactions,\n signAndSendTransaction,\n signOffchainMessage,\n} from \"../solana/tx\";\nimport { WalletVault } from \"../vault\";\nimport bs58 from \"bs58\";\n\nexport interface DappMetadata {\n name: string;\n url: string;\n icon?: string;\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type WalletMethod =\n | \"solana_signTransaction\"\n | \"solana_signAndSendTransaction\"\n | \"solana_signAllTransactions\"\n | \"solana_signMessage\"\n | \"solana_connect\"\n | \"solana_disconnect\";\n\nexport interface WalletRequest {\n id: string | number;\n method: WalletMethod;\n params: {\n transaction?: string; // base64 encoded\n transactions?: string[]; // for signAll\n message?: string; // for signMessage\n options?: Record<string, any>;\n };\n topic: string;\n dapp: DappMetadata;\n agentId?: string; // identifies which agent sent this request\n}\n\nexport interface WalletResponse {\n id: string | number;\n result?: any;\n error?: {\n code: number;\n message: string;\n };\n}\n\n// ── Error Codes (matching WalletConnect standard) ─────────────────────────────\n\nexport const ERROR_CODES = {\n USER_REJECTED: 4001,\n UNAUTHORIZED: 4100,\n UNSUPPORTED_METHOD: 4200,\n DISCONNECTED: 4900,\n CHAIN_DISCONNECTED: 4901,\n};\n\n// ── Handler ───────────────────────────────────────────────────────────────────\n\nexport class WalletRequestHandler {\n private vault: WalletVault;\n\n constructor(vault: WalletVault) {\n this.vault = vault;\n }\n\n /**\n * Handle any incoming wallet request.\n * This is the single entry point — all bridges call this.\n */\n async handle(request: WalletRequest): Promise<WalletResponse> {\n try {\n switch (request.method) {\n case \"solana_connect\":\n return this.handleConnect(request);\n\n case \"solana_disconnect\":\n return this.handleDisconnect(request);\n\n case \"solana_signTransaction\":\n return this.handleSignTransaction(request);\n\n case \"solana_signAndSendTransaction\":\n return this.handleSignAndSend(request);\n\n case \"solana_signAllTransactions\":\n return this.handleSignAll(request);\n\n case \"solana_signMessage\":\n return this.handleSignMessage(request);\n\n default:\n return this.errorResponse(\n request.id,\n ERROR_CODES.UNSUPPORTED_METHOD,\n `Method not supported: ${request.method}`,\n );\n }\n } catch (err) {\n return this.errorResponse(\n request.id,\n 4000,\n err instanceof Error ? err.message : \"Unknown error\",\n );\n }\n }\n\n // ── Connect / Disconnect ───────────────────────────────────────────────────\n\n private async handleConnect(request: WalletRequest): Promise<WalletResponse> {\n const keypair = this.vault.getActiveKeypair();\n return {\n id: request.id,\n result: {\n publicKey: keypair.publicKey,\n },\n };\n }\n\n private async handleDisconnect(\n request: WalletRequest,\n ): Promise<WalletResponse> {\n return { id: request.id, result: { disconnected: true } };\n }\n\n // ── Sign Transaction ───────────────────────────────────────────────────────\n\n private async handleSignTransaction(\n request: WalletRequest,\n ): Promise<WalletResponse> {\n const tx = request.params.transaction;\n if (!tx) return this.errorResponse(request.id, 4000, \"Missing transaction\");\n\n const keypair = this.vault.getActiveKeypair();\n\n // 1. Simulate\n const simulation = await simulateTransaction(tx, keypair.publicKey);\n this.log(request, `simulate → ${simulation.success ? \"ok\" : \"fail\"}`);\n\n if (!simulation.success) {\n return this.errorResponse(\n request.id,\n 4000,\n `Simulation failed: ${simulation.error}`,\n );\n }\n\n // 2. Sign — return signed bytes, dApp broadcasts\n const signed = await signTransaction(tx, keypair);\n this.log(request, `signed → ${signed.signature.slice(0, 8)}...`);\n\n return {\n id: request.id,\n result: { signedTransaction: signed.serialized },\n };\n }\n\n // ── Sign and Send ──────────────────────────────────────────────────────────\n\n private async handleSignAndSend(\n request: WalletRequest,\n ): Promise<WalletResponse> {\n const tx = request.params.transaction;\n if (!tx) return this.errorResponse(request.id, 4000, \"Missing transaction\");\n\n const keypair = this.vault.getActiveKeypair();\n\n // 1. Simulate\n const simulation = await simulateTransaction(tx, keypair.publicKey);\n this.log(request, `simulate → ${simulation.success ? \"ok\" : \"fail\"}`);\n\n if (!simulation.success) {\n return this.errorResponse(\n request.id,\n 4000,\n `Simulation failed: ${simulation.error}`,\n );\n }\n\n // 2. Sign + broadcast — wallet returns tx hash to dApp\n const result = await signAndSendTransaction(tx, keypair);\n this.log(request, `sent → ${result.txHash.slice(0, 8)}...`);\n\n return {\n id: request.id,\n result: {\n signature: result.txHash,\n confirmed: result.confirmed,\n },\n };\n }\n\n // ── Sign All Transactions ──────────────────────────────────────────────────\n\n private async handleSignAll(request: WalletRequest): Promise<WalletResponse> {\n const txs = request.params.transactions;\n if (!txs?.length)\n return this.errorResponse(request.id, 4000, \"Missing transactions\");\n\n const keypair = this.vault.getActiveKeypair();\n\n // Simulate each before signing any\n for (const tx of txs) {\n const simulation = await simulateTransaction(tx, keypair.publicKey);\n if (!simulation.success) {\n return this.errorResponse(\n request.id,\n 4000,\n `Simulation failed for tx in batch: ${simulation.error}`,\n );\n }\n }\n\n // All simulations passed — sign all\n const signed = await signAllTransactions(txs, keypair);\n this.log(request, `signed ${signed.length} transactions`);\n\n return {\n id: request.id,\n result: { signedTransactions: signed.map((s) => s.serialized) },\n };\n }\n\n // ── Sign Message ───────────────────────────────────────────────────────────\n\n private async handleSignMessage(\n request: WalletRequest,\n ): Promise<WalletResponse> {\n const message = request.params.message;\n if (!message)\n return this.errorResponse(request.id, 4000, \"Missing message\");\n\n const keypair = this.vault.getActiveKeypair();\n\n // WalletConnect sends message as base58-encoded bytes.\n // WebSocket / inject.js sends it as base64.\n // Decode to raw Uint8Array before signing.\n let messageBytes: Uint8Array;\n try {\n messageBytes = decodeMessage(message);\n } catch {\n return this.errorResponse(\n request.id,\n 4000,\n \"Could not decode message bytes\",\n );\n }\n\n const signature = signOffchainMessage(messageBytes, keypair);\n this.log(request, \"message signed\");\n\n // Return both signature and publicKey — required by Wallet Standard\n return {\n id: request.id,\n result: {\n signature,\n publicKey: keypair.publicKey,\n },\n };\n }\n\n // ── Helpers ────────────────────────────────────────────────────────────────\n\n private errorResponse(\n id: string | number,\n code: number,\n message: string,\n ): WalletResponse {\n return { id, error: { code, message } };\n }\n\n // TODO: handle logging\n private log(request: WalletRequest, note: string): void {\n // return { request, note };\n // const source = request.agentId ?? request.dapp?.name ?? \"unknown\";\n // addLog(\"handler\", `${request.method} | ${source} | ${note}`, \"info\");\n }\n}\n\n// ── Message Decoding ─────────────────────────────────────────────────────────\n// dApps encode messages differently depending on the transport:\n// WalletConnect → base58\n// WebSocket / inject.js → base64\n// Try base58 first (more common), fall back to base64, then UTF-8.\n\nfunction decodeMessage(message: string): Uint8Array {\n // Try base58 first (WalletConnect standard)\n try {\n const decoded = bs58.decode(message);\n if (decoded.length > 0) return decoded;\n } catch {}\n\n // Try base64 (WebSocket / inject.js)\n try {\n const decoded = Buffer.from(message, \"base64\");\n if (decoded.length > 0) return decoded;\n } catch {}\n\n // Fall back to raw UTF-8 string\n return new TextEncoder().encode(message);\n}\n\n// ── Functional API ────────────────────────────────────────────────────────────\n// Used by websocket.ts and walletconnect.ts so they don't need to\n// instantiate the class themselves.\n\nexport interface HandlerOptions {\n vault: WalletVault;\n}\n\n/**\n * Stateless wrapper around WalletRequestHandler.\n * websocket.ts and walletconnect.ts call this directly.\n */\nexport async function handleRequest(\n request: WalletRequest,\n options: HandlerOptions,\n): Promise<WalletResponse> {\n const handler = new WalletRequestHandler(options.vault);\n return handler.handle(request);\n}\n\nexport * from \"./walletConnect\";\n","import * as fs from \"fs\";\nimport { SESSIONS_FILE, ensureWalletDir } from \"../vault/keystore\";\n\nexport interface DappSession {\n topic: string;\n dappName: string;\n dappUrl: string;\n dappIcon?: string;\n connectedAccount: string;\n connectedAt: string;\n lastActivity: string;\n permissions: string[];\n chainId: string;\n active: boolean;\n}\n\ninterface SessionStore {\n sessions: DappSession[];\n}\n\nfunction read(): SessionStore {\n ensureWalletDir();\n if (!fs.existsSync(SESSIONS_FILE)) return { sessions: [] };\n return JSON.parse(fs.readFileSync(SESSIONS_FILE, \"utf8\"));\n}\n\nfunction write(store: SessionStore): void {\n ensureWalletDir();\n fs.writeFileSync(SESSIONS_FILE, JSON.stringify(store, null, 2));\n}\n\nexport function saveSession(session: DappSession): void {\n const store = read();\n const idx = store.sessions.findIndex((s) => s.topic === session.topic);\n if (idx >= 0) {\n store.sessions[idx] = session;\n } else {\n store.sessions.push(session);\n }\n write(store);\n}\n\nexport function removeSession(topic: string): void {\n const store = read();\n store.sessions = store.sessions.filter((s) => s.topic !== topic);\n write(store);\n}\n\nexport function getSession(topic: string): DappSession | undefined {\n return read().sessions.find((s) => s.topic === topic);\n}\n\nexport function getAllSessions(): DappSession[] {\n return read().sessions.filter((s) => s.active);\n}\n\nexport function updateActivity(topic: string): void {\n const store = read();\n const sess = store.sessions.find((s) => s.topic === topic);\n if (sess) {\n sess.lastActivity = new Date().toISOString();\n write(store);\n }\n}\n\nexport function markInactive(topic: string): void {\n const store = read();\n const sess = store.sessions.find((s) => s.topic === topic);\n if (sess) {\n sess.active = false;\n write(store);\n }\n}\n","/**\n *\n * Ink-based interactive prompts replacing readline/inquirer.\n */\n\nimport React, { useState, useRef } from \"react\";\nimport { render, Box, Text, useInput, useApp } from \"ink\";\n\n// ── Password Prompt ────────────────────────────────────────────────────────────\n\nexport function inkPassword(question: string): Promise<string> {\n return new Promise((resolve) => {\n let result = \"\";\n\n function PasswordPrompt() {\n const { exit } = useApp();\n const valueRef = useRef(\"\");\n const [maskLen, setMaskLen] = useState(0);\n\n useInput((input, key) => {\n if (key.return) {\n result = valueRef.current;\n exit();\n return;\n }\n if (key.backspace || key.delete) {\n if (valueRef.current.length > 0) {\n valueRef.current = valueRef.current.slice(0, -1);\n setMaskLen(valueRef.current.length);\n }\n return;\n }\n if (input && !key.ctrl && !key.meta) {\n valueRef.current += input;\n setMaskLen(valueRef.current.length);\n }\n });\n\n return (\n <Box>\n <Text bold>{question} </Text>\n <Text color=\"gray\">{\"*\".repeat(maskLen)}</Text>\n </Box>\n );\n }\n\n const { waitUntilExit } = render(<PasswordPrompt />);\n waitUntilExit().then(() => resolve(result));\n });\n}\n\n// ── Select Prompt ──────────────────────────────────────────────────────────────\n\nexport function inkSelect<T>(\n message: string,\n choices: { name: string; value: T }[],\n): Promise<T> {\n return new Promise((resolve) => {\n let result: T = choices[0].value;\n\n function SelectPrompt() {\n const { exit } = useApp();\n const cursorRef = useRef(0);\n const [cursor, setCursor] = useState(0);\n\n useInput((_, key) => {\n if (key.upArrow) {\n const n = Math.max(0, cursorRef.current - 1);\n cursorRef.current = n;\n setCursor(n);\n }\n if (key.downArrow) {\n const n = Math.min(choices.length - 1, cursorRef.current + 1);\n cursorRef.current = n;\n setCursor(n);\n }\n if (key.return) {\n result = choices[cursorRef.current].value;\n exit();\n }\n });\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>{message}</Text>\n {choices.map((choice, i) => (\n <Box key={i}>\n <Text color={i === cursor ? \"cyan\" : \"gray\"}>\n {i === cursor ? \"❯ \" : \" \"}\n {choice.name}\n </Text>\n </Box>\n ))}\n </Box>\n );\n }\n\n const { waitUntilExit } = render(<SelectPrompt />);\n waitUntilExit().then(() => resolve(result));\n });\n}\n\n// ── Confirm Prompt ─────────────────────────────────────────────────────────────\n\nexport function inkConfirm(\n message: string,\n defaultYes = false,\n): Promise<boolean> {\n return new Promise((resolve) => {\n let result = defaultYes;\n\n function ConfirmPrompt() {\n const { exit } = useApp();\n\n useInput((input, key) => {\n if (key.return) {\n result = defaultYes;\n exit();\n return;\n }\n const ch = input.toLowerCase();\n if (ch === \"y\") {\n result = true;\n exit();\n } else if (ch === \"n\") {\n result = false;\n exit();\n }\n });\n\n const hint = defaultYes ? \"Y/n\" : \"y/N\";\n return (\n <Box>\n <Text bold>{message} </Text>\n <Text color=\"gray\">[{hint}] </Text>\n </Box>\n );\n }\n\n const { waitUntilExit } = render(<ConfirmPrompt />);\n waitUntilExit().then(() => resolve(result));\n });\n}\n"],"mappings":"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","names":["generateMnemonic","validateMnemonic","mnemonicToSeed","path","mnemonicToSeed","fs","fs","generateMnemonic","mnemonicToSeed","validateMnemonic","LAMPORTS_PER_SOL","LAMPORTS_PER_SOL","Transaction","VersionedTransaction","nacl","bs58","VersionedTransaction","bs58","Transaction","nacl","React","useState","useRef","render","Box","Text","useInput","useApp","chalk","bs58","fs","chalk","generateMnemonic","mnemonicToSeed","PublicKey","Transaction","LAMPORTS_PER_SOL","Keypair","React","Box","Text","useApp","useState","useRef","generateMnemonic","mnemonicToSeed","useInput","render"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface DappSession {
|
|
2
|
+
topic: string;
|
|
3
|
+
dappName: string;
|
|
4
|
+
dappUrl: string;
|
|
5
|
+
dappIcon?: string;
|
|
6
|
+
connectedAccount: string;
|
|
7
|
+
connectedAt: string;
|
|
8
|
+
lastActivity: string;
|
|
9
|
+
permissions: string[];
|
|
10
|
+
chainId: string;
|
|
11
|
+
active: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare function saveSession(session: DappSession): void;
|
|
14
|
+
declare function removeSession(topic: string): void;
|
|
15
|
+
declare function getSession(topic: string): DappSession | undefined;
|
|
16
|
+
declare function getAllSessions(): DappSession[];
|
|
17
|
+
declare function updateActivity(topic: string): void;
|
|
18
|
+
declare function markInactive(topic: string): void;
|
|
19
|
+
|
|
20
|
+
export { type DappSession, getAllSessions, getSession, markInactive, removeSession, saveSession, updateActivity };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/session/index.ts
|
|
4
|
+
import * as fs2 from "fs";
|
|
5
|
+
|
|
6
|
+
// src/vault/keystore.ts
|
|
7
|
+
import fs from "fs";
|
|
8
|
+
import os from "os";
|
|
9
|
+
import path from "path";
|
|
10
|
+
function getWalletDir() {
|
|
11
|
+
return path.join(os.homedir(), ".wallet");
|
|
12
|
+
}
|
|
13
|
+
function getSessionsPath() {
|
|
14
|
+
return path.join(getWalletDir(), "sessions.json");
|
|
15
|
+
}
|
|
16
|
+
var SESSIONS_FILE = getSessionsPath();
|
|
17
|
+
function ensureWalletDir() {
|
|
18
|
+
const dir = getWalletDir();
|
|
19
|
+
if (!fs.existsSync(dir)) {
|
|
20
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/session/index.ts
|
|
25
|
+
function read() {
|
|
26
|
+
ensureWalletDir();
|
|
27
|
+
if (!fs2.existsSync(SESSIONS_FILE)) return { sessions: [] };
|
|
28
|
+
return JSON.parse(fs2.readFileSync(SESSIONS_FILE, "utf8"));
|
|
29
|
+
}
|
|
30
|
+
function write(store) {
|
|
31
|
+
ensureWalletDir();
|
|
32
|
+
fs2.writeFileSync(SESSIONS_FILE, JSON.stringify(store, null, 2));
|
|
33
|
+
}
|
|
34
|
+
function saveSession(session) {
|
|
35
|
+
const store = read();
|
|
36
|
+
const idx = store.sessions.findIndex((s) => s.topic === session.topic);
|
|
37
|
+
if (idx >= 0) {
|
|
38
|
+
store.sessions[idx] = session;
|
|
39
|
+
} else {
|
|
40
|
+
store.sessions.push(session);
|
|
41
|
+
}
|
|
42
|
+
write(store);
|
|
43
|
+
}
|
|
44
|
+
function removeSession(topic) {
|
|
45
|
+
const store = read();
|
|
46
|
+
store.sessions = store.sessions.filter((s) => s.topic !== topic);
|
|
47
|
+
write(store);
|
|
48
|
+
}
|
|
49
|
+
function getSession(topic) {
|
|
50
|
+
return read().sessions.find((s) => s.topic === topic);
|
|
51
|
+
}
|
|
52
|
+
function getAllSessions() {
|
|
53
|
+
return read().sessions.filter((s) => s.active);
|
|
54
|
+
}
|
|
55
|
+
function updateActivity(topic) {
|
|
56
|
+
const store = read();
|
|
57
|
+
const sess = store.sessions.find((s) => s.topic === topic);
|
|
58
|
+
if (sess) {
|
|
59
|
+
sess.lastActivity = (/* @__PURE__ */ new Date()).toISOString();
|
|
60
|
+
write(store);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function markInactive(topic) {
|
|
64
|
+
const store = read();
|
|
65
|
+
const sess = store.sessions.find((s) => s.topic === topic);
|
|
66
|
+
if (sess) {
|
|
67
|
+
sess.active = false;
|
|
68
|
+
write(store);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
getAllSessions,
|
|
73
|
+
getSession,
|
|
74
|
+
markInactive,
|
|
75
|
+
removeSession,
|
|
76
|
+
saveSession,
|
|
77
|
+
updateActivity
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/session/index.ts","../../src/vault/keystore.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport { SESSIONS_FILE, ensureWalletDir } from \"../vault/keystore\";\n\nexport interface DappSession {\n topic: string;\n dappName: string;\n dappUrl: string;\n dappIcon?: string;\n connectedAccount: string;\n connectedAt: string;\n lastActivity: string;\n permissions: string[];\n chainId: string;\n active: boolean;\n}\n\ninterface SessionStore {\n sessions: DappSession[];\n}\n\nfunction read(): SessionStore {\n ensureWalletDir();\n if (!fs.existsSync(SESSIONS_FILE)) return { sessions: [] };\n return JSON.parse(fs.readFileSync(SESSIONS_FILE, \"utf8\"));\n}\n\nfunction write(store: SessionStore): void {\n ensureWalletDir();\n fs.writeFileSync(SESSIONS_FILE, JSON.stringify(store, null, 2));\n}\n\nexport function saveSession(session: DappSession): void {\n const store = read();\n const idx = store.sessions.findIndex((s) => s.topic === session.topic);\n if (idx >= 0) {\n store.sessions[idx] = session;\n } else {\n store.sessions.push(session);\n }\n write(store);\n}\n\nexport function removeSession(topic: string): void {\n const store = read();\n store.sessions = store.sessions.filter((s) => s.topic !== topic);\n write(store);\n}\n\nexport function getSession(topic: string): DappSession | undefined {\n return read().sessions.find((s) => s.topic === topic);\n}\n\nexport function getAllSessions(): DappSession[] {\n return read().sessions.filter((s) => s.active);\n}\n\nexport function updateActivity(topic: string): void {\n const store = read();\n const sess = store.sessions.find((s) => s.topic === topic);\n if (sess) {\n sess.lastActivity = new Date().toISOString();\n write(store);\n }\n}\n\nexport function markInactive(topic: string): void {\n const store = read();\n const sess = store.sessions.find((s) => s.topic === topic);\n if (sess) {\n sess.active = false;\n write(store);\n }\n}\n","/**\n *\n * AES-256-GCM encrypted keystore.\n * The mnemonic (seed phrase) is encrypted at rest in ~/.wallet/vault.enc\n * Private keys NEVER touch disk — they are derived in memory at runtime.\n *\n * Encryption scheme:\n * - Key derivation: PBKDF2 (SHA-512, 210,000 iterations) — OWASP recommended\n * - Cipher: AES-256-GCM (authenticated encryption — detects tampering)\n * - Salt: 32 random bytes (unique per vault)\n * - IV: 16 random bytes (unique per encryption)\n *\n * Dependencies: Node.js built-in `crypto`, `fs`, `os`, `path`\n */\n\nimport crypto from \"crypto\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport interface VaultData {\n mnemonic: string;\n createdAt: string;\n version: number;\n}\n\ninterface EncryptedVault {\n version: number; // format version for future migrations\n salt: string; // hex — used for PBKDF2 key derivation\n iv: string; // hex — AES-GCM initialisation vector\n authTag: string; // hex — GCM authentication tag (detects tampering)\n ciphertext: string; // hex — encrypted vault data\n}\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\nconst VAULT_VERSION = 1;\nconst PBKDF2_ITERATIONS = 210_000; // OWASP 2024 recommendation for PBKDF2-SHA512\nconst PBKDF2_DIGEST = \"sha512\";\nconst KEY_LENGTH = 32; // 256 bits for AES-256\nconst SALT_LENGTH = 32; // 256 bits\nconst IV_LENGTH = 16; // 128 bits for AES-GCM\nconst CIPHER = \"aes-256-gcm\";\n\n// ── Vault Path ────────────────────────────────────────────────────────────────\n\nexport function getWalletDir(): string {\n // return path.join(__dirname, \".wallet\");\n return path.join(os.homedir(), \".wallet\");\n}\n\nexport function getVaultPath(): string {\n return path.join(getWalletDir(), \"vault.enc\");\n}\n\nexport function getConfigPath(): string {\n return path.join(getWalletDir(), \"config.json\");\n}\n\nexport function getSessionsPath(): string {\n return path.join(getWalletDir(), \"sessions.json\");\n}\n\nexport const SESSIONS_FILE = getSessionsPath();\n\nexport function ensureWalletDir(): void {\n const dir = getWalletDir();\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); // owner-only access\n }\n}\n\nexport function vaultExists(): boolean {\n return fs.existsSync(getVaultPath());\n}\n\n// ── Encryption ────────────────────────────────────────────────────────────────\n\n/**\n * Encrypt and save the vault to disk.\n * @param data - vault contents (mnemonic + metadata)\n * @param password - user's wallet password\n */\nexport async function saveVault(\n data: VaultData,\n password: string,\n): Promise<void> {\n ensureWalletDir();\n\n const salt = crypto.randomBytes(SALT_LENGTH);\n const iv = crypto.randomBytes(IV_LENGTH);\n const key = await deriveKey(password, salt);\n\n const plaintext = JSON.stringify(data);\n const cipher = crypto.createCipheriv(CIPHER, key, iv);\n\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n\n const authTag = cipher.getAuthTag();\n\n const vault: EncryptedVault = {\n version: VAULT_VERSION,\n salt: salt.toString(\"hex\"),\n iv: iv.toString(\"hex\"),\n authTag: authTag.toString(\"hex\"),\n ciphertext: encrypted.toString(\"hex\"),\n };\n\n fs.writeFileSync(getVaultPath(), JSON.stringify(vault, null, 2), {\n mode: 0o600, // owner read/write only\n });\n}\n\n/**\n * Load and decrypt the vault from disk.\n * Throws if the password is wrong or the file has been tampered with.\n */\nexport async function loadVault(password: string): Promise<VaultData> {\n if (!vaultExists()) {\n throw new Error(\"No vault found. Run `wallet init` to create one.\");\n }\n\n const raw = fs.readFileSync(getVaultPath(), \"utf8\");\n const vault: EncryptedVault = JSON.parse(raw);\n\n if (vault.version !== VAULT_VERSION) {\n throw new Error(`Unsupported vault version: ${vault.version}`);\n }\n\n const salt = Buffer.from(vault.salt, \"hex\");\n const iv = Buffer.from(vault.iv, \"hex\");\n const authTag = Buffer.from(vault.authTag, \"hex\");\n const ciphertext = Buffer.from(vault.ciphertext, \"hex\");\n\n const key = await deriveKey(password, salt);\n\n try {\n const decipher = crypto.createDecipheriv(CIPHER, key, iv);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([\n decipher.update(ciphertext),\n decipher.final(),\n ]);\n\n return JSON.parse(decrypted.toString(\"utf8\")) as VaultData;\n } catch {\n // GCM auth tag failure means wrong password OR tampered file\n throw new Error(\"Decryption failed: wrong password or vault is corrupted.\");\n }\n}\n\n/**\n * Change the vault password.\n * Decrypts with old password, re-encrypts with new password.\n */\nexport async function changePassword(\n oldPassword: string,\n newPassword: string,\n): Promise<void> {\n const data = await loadVault(oldPassword);\n await saveVault(data, newPassword);\n}\n\n// ── Internal ──────────────────────────────────────────────────────────────────\n\n/**\n * Derive a 256-bit AES key from a password using PBKDF2-SHA512.\n */\nfunction deriveKey(password: string, salt: Buffer): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n crypto.pbkdf2(\n password,\n salt,\n PBKDF2_ITERATIONS,\n KEY_LENGTH,\n PBKDF2_DIGEST,\n (err, key) => {\n if (err) reject(err);\n else resolve(key);\n },\n );\n });\n}\n"],"mappings":";;;AAAA,YAAYA,SAAQ;;;ACgBpB,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AA8BV,SAAS,eAAuB;AAErC,SAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,SAAS;AAC1C;AAUO,SAAS,kBAA0B;AACxC,SAAO,KAAK,KAAK,aAAa,GAAG,eAAe;AAClD;AAEO,IAAM,gBAAgB,gBAAgB;AAEtC,SAAS,kBAAwB;AACtC,QAAM,MAAM,aAAa;AACzB,MAAI,CAAC,GAAG,WAAW,GAAG,GAAG;AACvB,OAAG,UAAU,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAAA,EACpD;AACF;;;ADpDA,SAAS,OAAqB;AAC5B,kBAAgB;AAChB,MAAI,CAAI,eAAW,aAAa,EAAG,QAAO,EAAE,UAAU,CAAC,EAAE;AACzD,SAAO,KAAK,MAAS,iBAAa,eAAe,MAAM,CAAC;AAC1D;AAEA,SAAS,MAAM,OAA2B;AACxC,kBAAgB;AAChB,EAAG,kBAAc,eAAe,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAChE;AAEO,SAAS,YAAY,SAA4B;AACtD,QAAM,QAAQ,KAAK;AACnB,QAAM,MAAM,MAAM,SAAS,UAAU,CAAC,MAAM,EAAE,UAAU,QAAQ,KAAK;AACrE,MAAI,OAAO,GAAG;AACZ,UAAM,SAAS,GAAG,IAAI;AAAA,EACxB,OAAO;AACL,UAAM,SAAS,KAAK,OAAO;AAAA,EAC7B;AACA,QAAM,KAAK;AACb;AAEO,SAAS,cAAc,OAAqB;AACjD,QAAM,QAAQ,KAAK;AACnB,QAAM,WAAW,MAAM,SAAS,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK;AAC/D,QAAM,KAAK;AACb;AAEO,SAAS,WAAW,OAAwC;AACjE,SAAO,KAAK,EAAE,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK;AACtD;AAEO,SAAS,iBAAgC;AAC9C,SAAO,KAAK,EAAE,SAAS,OAAO,CAAC,MAAM,EAAE,MAAM;AAC/C;AAEO,SAAS,eAAe,OAAqB;AAClD,QAAM,QAAQ,KAAK;AACnB,QAAM,OAAO,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK;AACzD,MAAI,MAAM;AACR,SAAK,gBAAe,oBAAI,KAAK,GAAE,YAAY;AAC3C,UAAM,KAAK;AAAA,EACb;AACF;AAEO,SAAS,aAAa,OAAqB;AAChD,QAAM,QAAQ,KAAK;AACnB,QAAM,OAAO,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,KAAK;AACzD,MAAI,MAAM;AACR,SAAK,SAAS;AACd,UAAM,KAAK;AAAA,EACb;AACF;","names":["fs"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { confirmTransaction, getBalance, getConnection, getLatestBlockhash, healthCheck, requestAirdrop, resetConnection } from './rpc.js';
|
|
2
|
+
export { AccountChange, KNOWN_PROGRAMS, SimulationResult, TokenChange, simulateTransaction } from './simulate.js';
|
|
3
|
+
export { SendResult, SignedTransaction, sendSignedTransaction, signAllTransactions, signAndSendTransaction, signOffchainMessage, signTransaction } from './tx.js';
|
|
4
|
+
import '@solana/web3.js';
|
|
5
|
+
import '../vault/accounts.js';
|