From aed85dff726cb612415a98aa1cac9f59d82e294f Mon Sep 17 00:00:00 2001 From: ngoc Date: Mon, 26 Jan 2026 04:15:56 +0700 Subject: [PATCH] npm cli app --- .npmignore | 52 +++++++++++ INSTALL.md | 173 ++++++++++++++++++++++++++++++++++++ cli/commands/dev.ts | 207 +++++++++++++++++++++++++++++++++++++++++++ cli/commands/stop.ts | 43 +++++++++ cli/index.ts | 54 +++++------ cli/scripts/dev.sh | 138 ----------------------------- cli/scripts/stop.sh | 30 ------- cli/server/deploy.ts | 4 +- cli/server/oracle.ts | 4 +- package.json | 42 +++++++-- tsconfig.build.json | 16 ++++ tsconfig.json | 36 +++----- 12 files changed, 564 insertions(+), 235 deletions(-) create mode 100644 .npmignore create mode 100644 INSTALL.md create mode 100644 cli/commands/dev.ts create mode 100644 cli/commands/stop.ts delete mode 100755 cli/scripts/dev.sh delete mode 100755 cli/scripts/stop.sh create mode 100644 tsconfig.build.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..60f65b1 --- /dev/null +++ b/.npmignore @@ -0,0 +1,52 @@ +# Source files (only compiled JS will be included) +*.ts +!*.d.ts + +# Tests +tests/ +**/*.test.ts +**/*.test.js + +# Build config +tsconfig.json +tsconfig.build.json +bun.lockb + +# Development +.env +.env.* +!.env.example + +# Logs +*.log +anvil.log +.anvil.pid + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# OS +.DS_Store +Thumbs.db + +# Git +.git/ +.gitignore + +# CI/CD +.github/ + +# Documentation (keep README.md) +docs/ + +# Deployments +deployments/ + +# Node modules (will be installed by user) +node_modules/ + +# Parent directory references +../ diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..e8f4067 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,173 @@ +# Installing NLA CLI Globally + +## Prerequisites + +- Node.js >= 18.0.0 +- npm or yarn or pnpm +- A blockchain node (local Anvil or remote RPC URL) +- At least one LLM provider API key (OpenAI, Anthropic, or OpenRouter) + +## Installation + +### Global Installation (Recommended) + +Install the NLA CLI globally to use it from anywhere: + +```bash +npm install -g nla +``` + +Or with yarn: +```bash +yarn global add nla +``` + +Or with pnpm: +```bash +pnpm add -g nla +``` + +### Verify Installation + +```bash +nla --help +``` + +## Configuration + +Create a `.env` file in your project directory: + +```bash +# Copy the example environment file +cp node_modules/nla/.env.example .env + +# Edit with your configuration +nano .env +``` + +Required environment variables: +```bash +# At least one LLM provider API key +OPENAI_API_KEY=sk-... +# OR +ANTHROPIC_API_KEY=sk-ant-... +# OR +OPENROUTER_API_KEY=sk-or-... + +# Oracle configuration +ORACLE_PRIVATE_KEY=0x... +RPC_URL=http://localhost:8545 + +# Optional: For enhanced search +PERPLEXITY_API_KEY=pplx-... +``` + +## Quick Start + +### 1. Start Development Environment + +```bash +nla dev +``` + +This will: +- Start Anvil (local blockchain) +- Deploy all contracts +- Start the oracle + +### 2. Create an Escrow + +```bash +nla escrow:create \ + --demand "The sky is blue" \ + --amount 10 \ + --token 0xa513E6E4b8f2a923D98304ec87F64353C4D5C853 \ + --oracle 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +``` + +### 3. Fulfill an Escrow + +```bash +nla escrow:fulfill \ + --escrow-uid 0x... \ + --fulfillment "The sky appears blue today" \ + --oracle 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 +``` + +### 4. Collect Payment + +```bash +nla escrow:collect \ + --escrow-uid 0x... \ + --fulfillment-uid 0x... +``` + +## Uninstallation + +```bash +npm uninstall -g nla +``` + +## Development + +If you want to contribute or modify the CLI: + +```bash +# Clone the repository +git clone https://github.com/arkhai-io/natural-language-agreements.git +cd natural-language-agreements + +# Install dependencies +npm install + +# Build +npm run build + +# Link locally +npm link +``` + +## Troubleshooting + +### Command not found after installation + +Make sure your npm global bin directory is in your PATH: + +```bash +# Check npm global bin path +npm bin -g + +# Add to PATH (add to ~/.bashrc or ~/.zshrc) +export PATH="$(npm bin -g):$PATH" +``` + +### Permission errors on Linux/Mac + +If you get permission errors, either: + +1. Use a Node version manager (recommended): +```bash +# Install nvm +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash + +# Install and use Node +nvm install 18 +nvm use 18 + +# Now install without sudo +npm install -g nla +``` + +2. Or configure npm to use a different directory: +```bash +mkdir ~/.npm-global +npm config set prefix '~/.npm-global' +echo 'export PATH=~/.npm-global/bin:$PATH' >> ~/.bashrc +source ~/.bashrc +``` + +## Support + +For issues and questions: +- GitHub: https://github.com/arkhai-io/natural-language-agreements/issues +- Documentation: https://github.com/arkhai-io/natural-language-agreements diff --git a/cli/commands/dev.ts b/cli/commands/dev.ts new file mode 100644 index 0000000..19f3355 --- /dev/null +++ b/cli/commands/dev.ts @@ -0,0 +1,207 @@ +import { spawn, spawnSync } from "child_process"; +import { existsSync, readFileSync, writeFileSync, createWriteStream, unlinkSync } from "fs"; +import { join } from "path"; + +// Colors for console output +const colors = { + green: '\x1b[32m', + blue: '\x1b[34m', + red: '\x1b[31m', + yellow: '\x1b[33m', + reset: '\x1b[0m' +}; + +// Load .env file if it exists +function loadEnvFile() { + const envPath = '.env'; + if (existsSync(envPath)) { + console.log(`${colors.blue}📄 Loading .env file...${colors.reset}`); + const envContent = readFileSync(envPath, 'utf-8'); + const lines = envContent.split('\n'); + + for (const line of lines) { + // Skip comments and empty lines + if (line.trim().startsWith('#') || !line.trim()) continue; + + // Parse key=value + const match = line.match(/^([^=]+)=(.*)$/); + if (match) { + const key = match[1].trim(); + const value = match[2].trim(); + // Only set if not already in environment + if (!process.env[key]) { + process.env[key] = value; + } + } + } + console.log(`${colors.green}✅ Environment variables loaded${colors.reset}`); + } +} + +// Helper to check if a command exists +function commandExists(command: string): boolean { + try { + const result = spawnSync(process.platform === 'win32' ? 'where' : 'which', [command], { + stdio: 'pipe' + }); + return result.status === 0; + } catch { + return false; + } +} + +// Helper to check if a port is in use +function isPortInUse(port: number): boolean { + try { + const result = spawnSync('lsof', ['-Pi', `:${port}`, '-sTCP:LISTEN', '-t'], { + stdio: 'pipe' + }); + return result.status === 0; + } catch { + return false; + } +} + +// Dev command - Start complete development environment +export async function runDevCommand(cliDir: string) { + console.log(`${colors.blue}════════════════════════════════════════════════════════${colors.reset}`); + console.log(`${colors.blue} Natural Language Agreement Oracle - Quick Setup${colors.reset}`); + console.log(`${colors.blue}════════════════════════════════════════════════════════${colors.reset}\n`); + + // Load .env file first + loadEnvFile(); + console.log(''); + + // Check prerequisites + console.log(`${colors.blue}📋 Checking prerequisites...${colors.reset}\n`); + + // Check Bun + if (!commandExists('bun')) { + console.error(`${colors.red}❌ Bun is not installed${colors.reset}`); + console.log('Please install it: https://bun.sh'); + process.exit(1); + } + console.log(`${colors.green}✅ Bun installed${colors.reset}`); + + // Check Foundry + if (!commandExists('forge')) { + console.error(`${colors.red}❌ Foundry (forge) is not installed${colors.reset}`); + console.log('Please install it: https://book.getfoundry.sh/getting-started/installation'); + process.exit(1); + } + console.log(`${colors.green}✅ Foundry installed${colors.reset}`); + + // Check Anvil + if (!commandExists('anvil')) { + console.error(`${colors.red}❌ Anvil is not installed${colors.reset}`); + console.log('Please install Foundry: https://book.getfoundry.sh/getting-started/installation'); + process.exit(1); + } + console.log(`${colors.green}✅ Anvil installed${colors.reset}`); + + // Check LLM API keys + const hasOpenAI = !!process.env.OPENAI_API_KEY; + const hasAnthropic = !!process.env.ANTHROPIC_API_KEY; + const hasOpenRouter = !!process.env.OPENROUTER_API_KEY; + const hasPerplexity = !!process.env.PERPLEXITY_API_KEY; + + if (!hasOpenAI && !hasAnthropic && !hasOpenRouter && !hasPerplexity) { + console.error(`${colors.red}❌ No LLM provider API key set${colors.reset}`); + console.log('Please add at least one API key to your environment:'); + console.log(' export OPENAI_API_KEY=sk-...'); + console.log(' export ANTHROPIC_API_KEY=sk-ant-...'); + console.log(' export OPENROUTER_API_KEY=sk-or-...'); + process.exit(1); + } + + if (hasOpenAI) console.log(`${colors.green}✅ OpenAI API key configured${colors.reset}`); + if (hasAnthropic) console.log(`${colors.green}✅ Anthropic API key configured${colors.reset}`); + if (hasOpenRouter) console.log(`${colors.green}✅ OpenRouter API key configured${colors.reset}`); + if (hasPerplexity) console.log(`${colors.green}✅ Perplexity API key configured${colors.reset}`); + console.log(''); + + // Check if Anvil is already running + if (isPortInUse(8545)) { + console.log(`${colors.yellow}⚠️ Anvil is already running on port 8545${colors.reset}`); + console.log(`${colors.blue}Using existing Anvil instance${colors.reset}\n`); + } else { + // Start Anvil + console.log(`${colors.blue}🔨 Starting Anvil...${colors.reset}`); + const anvilProcess = spawn('anvil', [], { + stdio: ['ignore', 'pipe', 'pipe'], + detached: true + }); + + // Save PID + writeFileSync('.anvil.pid', anvilProcess.pid!.toString()); + + // Redirect output to log file + const logStream = createWriteStream('anvil.log', { flags: 'a' }); + anvilProcess.stdout?.pipe(logStream); + anvilProcess.stderr?.pipe(logStream); + + anvilProcess.unref(); + + console.log(`${colors.green}✅ Anvil started (PID: ${anvilProcess.pid})${colors.reset}`); + console.log(' Logs: tail -f anvil.log'); + + // Wait for Anvil to be ready + await new Promise(resolve => setTimeout(resolve, 3000)); + } + + // Deploy contracts + console.log(`\n${colors.blue}📝 Deploying contracts...${colors.reset}\n`); + const deployScript = join(cliDir, 'server', 'deploy.js'); + const deployResult = spawnSync('bun', ['run', deployScript, '--network', 'localhost', '--rpc-url', 'http://localhost:8545'], { + stdio: 'inherit', + cwd: process.cwd() + }); + + if (deployResult.status !== 0) { + console.error(`${colors.red}❌ Deployment failed${colors.reset}`); + process.exit(1); + } + + // Start oracle + console.log(`\n${colors.blue}🚀 Starting oracle...${colors.reset}\n`); + const oracleScript = join(cliDir, 'server', 'oracle.js'); + const deploymentFile = join(cliDir, 'deployments', 'localhost.json'); + + const oracleProcess = spawn('bun', ['run', oracleScript, '--deployment', deploymentFile], { + stdio: 'inherit', + cwd: process.cwd() + }); + + // Handle cleanup on exit + const cleanup = () => { + console.log(`\n${colors.yellow}🛑 Shutting down...${colors.reset}`); + + // Kill oracle + oracleProcess.kill(); + + // Kill Anvil + try { + const pidFile = '.anvil.pid'; + if (existsSync(pidFile)) { + const pid = readFileSync(pidFile, 'utf-8').trim(); + try { + process.kill(parseInt(pid)); + console.log(`${colors.green}✅ Anvil stopped${colors.reset}`); + } catch (e) { + // Process might already be dead + } + unlinkSync(pidFile); + } + } catch (e) { + // Ignore errors + } + + process.exit(0); + }; + + process.on('SIGINT', cleanup); + process.on('SIGTERM', cleanup); + + // Keep process alive + await new Promise(() => {}); +} diff --git a/cli/commands/stop.ts b/cli/commands/stop.ts new file mode 100644 index 0000000..4c4328b --- /dev/null +++ b/cli/commands/stop.ts @@ -0,0 +1,43 @@ +import { spawnSync } from "child_process"; +import { existsSync, readFileSync, unlinkSync } from "fs"; + +// Colors for console output +const colors = { + green: '\x1b[32m', + yellow: '\x1b[33m', + red: '\x1b[31m', + reset: '\x1b[0m' +}; + +// Stop command - Stop all services +export async function runStopCommand() { + console.log(`${colors.yellow}🛑 Stopping services...${colors.reset}\n`); + + // Stop Anvil + try { + const pidFile = '.anvil.pid'; + if (existsSync(pidFile)) { + const pid = readFileSync(pidFile, 'utf-8').trim(); + try { + process.kill(parseInt(pid)); + console.log(`${colors.green}✅ Anvil stopped${colors.reset}`); + } catch (e) { + console.log(`${colors.yellow}⚠️ Anvil process not found (may have already stopped)${colors.reset}`); + } + unlinkSync(pidFile); + } else { + console.log(`${colors.yellow}⚠️ No Anvil PID file found${colors.reset}`); + } + } catch (e) { + console.error(`${colors.red}❌ Error stopping Anvil:${colors.reset}`, e); + } + + // Try to kill any remaining processes on port 8545 + try { + spawnSync('pkill', ['-f', 'anvil']); + } catch (e) { + // Ignore + } + + console.log(`\n${colors.green}✅ Services stopped${colors.reset}`); +} diff --git a/cli/index.ts b/cli/index.ts index e50beff..56662c2 100755 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,11 +1,20 @@ -#!/usr/bin/env bun +#!/usr/bin/env node import { parseArgs } from "util"; import { spawnSync } from "child_process"; import { existsSync, readFileSync } from "fs"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; import { createPublicClient, http, parseAbiParameters, decodeAbiParameters } from "viem"; import { foundry } from "viem/chains"; import { contracts } from "alkahest-ts"; + +import { runDevCommand } from "./commands/dev.js"; +import { runStopCommand } from "./commands/stop.js"; + +// Get the directory name for ESM modules (compatible with both Node and Bun) +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); // Helper function to display usage function displayHelp() { console.log(` @@ -83,7 +92,7 @@ Examples: // Parse command line arguments function parseCliArgs() { - const args = Bun.argv.slice(2); + const args = process.argv.slice(2); if (args.length === 0) { displayHelp(); @@ -120,27 +129,9 @@ function parseCliArgs() { return { command, ...values }; } -// Shell command handler -async function runShellCommand(scriptName: string, args: string[] = []) { - const { spawnSync } = await import("child_process"); - const scriptDir = import.meta.dir; - const scriptPath = `${scriptDir}/scripts/${scriptName}`; - - // Run the shell script - const result = spawnSync(scriptPath, args, { - stdio: "inherit", - cwd: process.cwd(), - shell: true, - }); - - process.exit(result.status || 0); -} - // Server command handler (for deploy.ts, oracle.ts) async function runServerCommand(scriptName: string, args: string[] = []) { - const { spawnSync } = await import("child_process"); - const scriptDir = import.meta.dir; - const scriptPath = `${scriptDir}/server/${scriptName}`; + const scriptPath = join(__dirname, "server", scriptName); // Run the TypeScript file directly const result = spawnSync("bun", ["run", scriptPath, ...args], { @@ -157,25 +148,25 @@ async function main() { const args = parseCliArgs(); const command = args.command; - // Handle shell script commands (dev and stop need shell for process management) + // Handle dev and stop commands if (command === "dev") { - await runShellCommand("dev.sh"); + await runDevCommand(__dirname); return; } if (command === "stop") { - await runShellCommand("stop.sh"); + await runStopCommand(); return; } // Handle TypeScript commands that can run directly if (command === "deploy") { - await runServerCommand("deploy.ts", Bun.argv.slice(3)); + await runServerCommand("deploy.js", process.argv.slice(3)); return; } if (command === "start-oracle") { - await runServerCommand("oracle.ts", Bun.argv.slice(3)); + await runServerCommand("oracle.js", process.argv.slice(3)); return; } @@ -184,13 +175,13 @@ async function main() { switch (command) { case "escrow:create": - scriptPath = "./client/create-escrow.ts"; + scriptPath = "./client/create-escrow.js"; break; case "escrow:fulfill": - scriptPath = "./client/fulfill-escrow.ts"; + scriptPath = "./client/fulfill-escrow.js"; break; case "escrow:collect": - scriptPath = "./client/collect-escrow.ts"; + scriptPath = "./client/collect-escrow.js"; break; case "escrow:status": await runStatusCommand(args); @@ -203,11 +194,10 @@ async function main() { // Run the command as a subprocess with the args (excluding the command name) const { spawnSync } = await import("child_process"); - const scriptDir = import.meta.dir; - const fullScriptPath = `${scriptDir}/${scriptPath}`; + const fullScriptPath = join(__dirname, scriptPath); // Build args array without the command name - const commandArgs = Bun.argv.slice(3); // Skip bun, script, and command + const commandArgs = process.argv.slice(3); // Skip node, script, and command const result = spawnSync("bun", ["run", fullScriptPath, ...commandArgs], { stdio: "inherit", diff --git a/cli/scripts/dev.sh b/cli/scripts/dev.sh deleted file mode 100755 index cfa0cea..0000000 --- a/cli/scripts/dev.sh +++ /dev/null @@ -1,138 +0,0 @@ -#!/bin/bash - -# Complete setup and deployment for local development -# This script will: -# 1. Check prerequisites -# 2. Start Anvil -# 3. Deploy contracts -# 4. Start the oracle - -set -e - -# Colors for output -GREEN='\033[0;32m' -BLUE='\033[0;34m' -RED='\033[0;31m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${BLUE}════════════════════════════════════════════════════════${NC}" -echo -e "${BLUE} Natural Language Agreement Oracle - Quick Setup${NC}" -echo -e "${BLUE}════════════════════════════════════════════════════════${NC}\n" - -# Check prerequisites -echo -e "${BLUE}📋 Checking prerequisites...${NC}\n" - -# Load .env file if it exists -if [ -f ".env" ]; then - echo -e "${BLUE}📄 Loading .env file...${NC}" - export $(cat .env | grep -v '^#' | xargs) - echo -e "${GREEN}✅ Environment variables loaded${NC}" -fi - -# Check Bun -if ! command -v bun &> /dev/null; then - echo -e "${RED}❌ Bun is not installed${NC}" - echo "Please install it: https://bun.sh" - exit 1 -fi -echo -e "${GREEN}✅ Bun installed${NC}" - -# Check Foundry -if ! command -v forge &> /dev/null; then - echo -e "${RED}❌ Foundry (forge) is not installed${NC}" - echo "Please install it: https://book.getfoundry.sh/getting-started/installation" - exit 1 -fi -echo -e "${GREEN}✅ Foundry installed${NC}" - -# Check Anvil -if ! command -v anvil &> /dev/null; then - echo -e "${RED}❌ Anvil is not installed${NC}" - echo "Please install Foundry: https://book.getfoundry.sh/getting-started/installation" - exit 1 -fi -echo -e "${GREEN}✅ Anvil installed${NC}" - -# Check alkahest -if [ ! -d "../alkahest" ]; then - echo -e "${RED}❌ alkahest repository not found${NC}" - echo "Please clone it in the parent directory:" - echo " cd .. && git clone https://github.com/arkhai-io/alkahest.git" - exit 1 -fi -echo -e "${GREEN}✅ alkahest repository found${NC}" - -# Check LLM API keys -if [ -z "$OPENAI_API_KEY" ] && [ -z "$ANTHROPIC_API_KEY" ] && [ -z "$OPENROUTER_API_KEY" ]; then - echo -e "${RED}❌ No LLM provider API key set${NC}" - echo "Please add at least one API key to your .env file:" - echo " OPENAI_API_KEY=sk-..." - echo " ANTHROPIC_API_KEY=sk-ant-..." - echo " OPENROUTER_API_KEY=sk-or-..." - exit 1 -fi - -if [ -n "$OPENAI_API_KEY" ]; then - echo -e "${GREEN}✅ OpenAI API key configured${NC}" -fi -if [ -n "$ANTHROPIC_API_KEY" ]; then - echo -e "${GREEN}✅ Anthropic API key configured${NC}" -fi -if [ -n "$OPENROUTER_API_KEY" ]; then - echo -e "${GREEN}✅ OpenRouter API key configured${NC}" -fi -if [ -n "$PERPLEXITY_API_KEY" ]; then - echo -e "${GREEN}✅ Perplexity API key configured${NC}" -fi -echo "" - -# Install dependencies -echo -e "${BLUE}📦 Installing dependencies...${NC}\n" -bun install - -# Check if Anvil is already running -if lsof -Pi :8545 -sTCP:LISTEN -t >/dev/null ; then - echo -e "${YELLOW}⚠️ Anvil is already running on port 8545${NC}" - read -p "Do you want to kill it and start fresh? (y/n) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ ]]; then - pkill -f anvil || true - sleep 2 - else - echo -e "${BLUE}Using existing Anvil instance${NC}\n" - fi -fi - -# Start Anvil in background if not running -if ! lsof -Pi :8545 -sTCP:LISTEN -t >/dev/null ; then - echo -e "${BLUE}🔨 Starting Anvil...${NC}" - anvil > anvil.log 2>&1 & - ANVIL_PID=$! - echo $ANVIL_PID > .anvil.pid - echo -e "${GREEN}✅ Anvil started (PID: $ANVIL_PID)${NC}" - echo " Logs: tail -f anvil.log" - sleep 3 -fi - -# Deploy contracts -echo -e "\n${BLUE}📝 Deploying contracts...${NC}\n" -bun run cli/server/deploy.ts --network localhost --rpc-url http://localhost:8545 - -# Start oracle -echo -e "\n${BLUE}🚀 Starting oracle...${NC}\n" -bun run cli/server/oracle.ts --deployment ./cli/deployments/localhost.json - -# Cleanup function -cleanup() { - echo -e "\n${YELLOW}🛑 Shutting down...${NC}" - if [ -f .anvil.pid ]; then - ANVIL_PID=$(cat .anvil.pid) - kill $ANVIL_PID 2>/dev/null || true - rm .anvil.pid - echo -e "${GREEN}✅ Anvil stopped${NC}" - fi - exit 0 -} - -trap cleanup SIGINT SIGTERM diff --git a/cli/scripts/stop.sh b/cli/scripts/stop.sh deleted file mode 100755 index 7536c5d..0000000 --- a/cli/scripts/stop.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Stop all running oracle and Anvil processes - -# Colors for output -GREEN='\033[0;32m' -BLUE='\033[0;34m' -RED='\033[0;31m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -echo -e "${BLUE}🛑 Stopping Natural Language Agreement services...${NC}\n" - -# Stop Anvil -if [ -f .anvil.pid ]; then - ANVIL_PID=$(cat .anvil.pid) - if kill -0 $ANVIL_PID 2>/dev/null; then - kill $ANVIL_PID - echo -e "${GREEN}✅ Stopped Anvil (PID: $ANVIL_PID)${NC}" - fi - rm .anvil.pid -else - # Try to kill any running anvil - pkill -f anvil && echo -e "${GREEN}✅ Stopped Anvil${NC}" || echo -e "${YELLOW}⚠️ No Anvil process found${NC}" -fi - -# Stop oracle -pkill -f "bun run oracle" && echo -e "${GREEN}✅ Stopped oracle${NC}" || echo -e "${YELLOW}⚠️ No oracle process found${NC}" - -echo -e "\n${GREEN}✨ Cleanup complete${NC}" diff --git a/cli/server/deploy.ts b/cli/server/deploy.ts index 092adb5..49b997c 100644 --- a/cli/server/deploy.ts +++ b/cli/server/deploy.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env bun +#!/usr/bin/env node /** * Deployment script for Alkahest Natural Language Agreement Oracle * @@ -54,7 +54,7 @@ Examples: // Parse command line arguments function parseCliArgs() { const { values } = parseArgs({ - args: Bun.argv.slice(2), + args: process.argv.slice(2), options: { "network": { type: "string" }, "rpc-url": { type: "string" }, diff --git a/cli/server/oracle.ts b/cli/server/oracle.ts index 57926b0..bfe415a 100644 --- a/cli/server/oracle.ts +++ b/cli/server/oracle.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env bun +#!/usr/bin/env node import { parseArgs } from "util"; import { parseAbiParameters, createWalletClient, http, publicActions } from "viem"; import { privateKeyToAccount } from "viem/accounts"; @@ -57,7 +57,7 @@ Examples: // Parse command line arguments function parseCliArgs() { const { values } = parseArgs({ - args: Bun.argv.slice(2), + args: process.argv.slice(2), options: { "rpc-url": { type: "string" }, "private-key": { type: "string" }, diff --git a/package.json b/package.json index 4134f9a..1c8d244 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,45 @@ { - "name": "natural-language-agreement-extension", - "module": "index.ts", + "name": "nla", + "version": "1.0.0", + "description": "Natural Language Agreement Oracle - CLI for creating and managing blockchain agreements using natural language", "type": "module", - "private": true, - "devDependencies": { - "@types/bun": "latest" + "private": false, + "author": "Arkhai", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/arkhai-io/natural-language-agreements.git" }, + "keywords": [ + "blockchain", + "ethereum", + "smart-contracts", + "natural-language", + "oracle", + "ai", + "llm", + "escrow" + ], "bin": { - "nla": "cli/index.ts" + "nla": "./dist/cli/index.js" + }, + "files": [ + "dist/**/*", + "README.md", + ".env.example" + ], + "engines": { + "node": ">=18.0.0" + }, + "preferGlobal": true, + "devDependencies": { + "@types/bun": "latest", + "@types/node": "^20.0.0", + "typescript": "^5.9.3" }, "scripts": { + "build": "tsc --project tsconfig.build.json", + "prepublishOnly": "npm run build", "dev": "bun run index.ts", "start": "bun run index.ts", "test": "bun test ./tests --exclude alkahest-ts/** ", diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..00fba9a --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./", + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + + "esModuleInterop": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true + }, + "include": ["cli/**/*"], + "exclude": ["node_modules", "tests", "dist"] +} diff --git a/tsconfig.json b/tsconfig.json index cc0c50e..49c508d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,30 +1,16 @@ { "compilerOptions": { - // Environment setup & latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "Preserve", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, + "outDir": "dist", + "rootDir": ".", + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "Bundler", - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - // Best practices + "esModuleInterop": true, "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false, - - } + "skipLibCheck": true + }, + "include": [ + "cli/**/*" + ] }