diff --git a/README.md b/README.md index 2cd120f..f255b1d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,15 @@ # Eremos +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) +![TypeScript](https://img.shields.io/badge/language-TypeScript-3178C6?logo=typescript&logoColor=white) +![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen) +[![Follow on X](https://img.shields.io/badge/follow-@EremosCore-000000?logo=x)](https://x.com/EremosCore) + ![Eremos](docs/banner2.png) **Autonomous swarm agents for early on-chain signal detection** -Eremos is a lightweight framework for deploying modular agents that monitor blockchain activity - tracking wallet clusters, mint patterns, and contract anomalies. +Eremos is a lightweight framework for deploying modular agents that monitor blockchain activity — tracking wallet clusters, mint patterns, and contract anomalies. Designed for devs who want low-noise, early signals embedded into their workflows. --- @@ -23,6 +28,22 @@ Modular and extendable by design.* --- +## Table of Contents + +- [Features](#features) +- [Quick Links](#quick-links) +- [Example Signal](#example-signal) +- [Signal Confidence](#signal-confidence) +- [Tech Stack](#tech-stack) +- [Getting Started](#getting-started) +- [Key Folders](#key-folders) +- [Common Commands](#common-commands) +- [Contributing](#contributing) +- [License](#license) +- [Links](#links) + +--- + ## Features - **Modular Agents** - Scoped logic for detecting wallet activity, contract spawns, and anomalies @@ -35,6 +56,20 @@ Modular and extendable by design.* - *+ More to come.* +--- + +## Quick Links + +- **Docs**: [`/docs`](./docs) +- **Architecture**: [`/docs/architecture.md`](./docs/architecture.md) +- **Agents**: [`/docs/agents.md`](./docs/agents.md) +- **Signals**: [`/docs/signals.md`](./docs/signals.md) +- **Metrics**: [`/docs/metrics.md`](./docs/metrics.md) +- **Events**: [`/docs/events.md`](./docs/events.md) +- **Deployment**: [`/docs/deployment.md`](./docs/deployment.md) +- **Contributing**: [`/docs/contributing.md`](./docs/contributing.md) +- **Whitepaper (v1.0)**: [`/docs/whitepaper.pdf`](./docs/whitepaper.pdf) + --- ## Example Signal @@ -75,10 +110,9 @@ Confidence is computed via agent-side scoring and logged alongside the signal. ## Tech Stack -- **Frontend:** Next.js, Tailwind CSS -- **Backend:** Node.js (TypeScript-based agent runner) - **Language:** TypeScript (typed logic across agents, utils, and infra) -- **Chain Layer:** RPC watchers, mempool filters, native triggers +- **Runtime:** Node.js (TypeScript-based agent runner) +- **Chain Layer:** Solana RPC watchers, mempool filters, native triggers --- @@ -90,10 +124,9 @@ cd Eremos npm install ``` -Set up your environment: +Run a local development agent: ```bash -cp .env.example .env.local npm run dev ``` @@ -109,6 +142,24 @@ npm run dev --- +## Common Commands + +```bash +# List available agents +npm run agents:list + +# Run the example dev agent +npm run agent:dev + +# Generate a new agent scaffold +npm run agent:generate MyAgent + +# Validate an agent implementation +npm run agent:validate +``` + +--- + ## Contributing We’re open to contributors. diff --git a/package.json b/package.json index 75703f0..180b9fa 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,11 @@ "description": "Modular agent framework for on-chain activity monitoring.", "main": "index.js", "scripts": { - "dev": "echo 'Running dev mode...'" + "dev": "tsx scripts/dev-agent.ts", + "agents:list": "tsx scripts/agent-list.ts", + "agent:dev": "tsx scripts/dev-agent.ts", + "agent:generate": "tsx scripts/generate-agent.ts", + "agent:validate": "tsx scripts/validate-agent.ts || echo 'validate script not yet implemented'" }, "keywords": [ "agent", @@ -14,5 +18,9 @@ "framework" ], "license": "MIT", - "author": "EremosCore" + "author": "EremosCore", + "devDependencies": { + "tsx": "^4.19.0", + "typescript": "^5.4.0" + } } diff --git a/scripts/agent-list.ts b/scripts/agent-list.ts index afe0d8e..1d98837 100644 --- a/scripts/agent-list.ts +++ b/scripts/agent-list.ts @@ -2,9 +2,23 @@ import * as fs from "fs"; import * as path from "path"; const agentsPath = path.join(__dirname, "../agents"); -const agentFiles = fs.readdirSync(agentsPath); +const agentFiles = fs + .readdirSync(agentsPath) + .filter((f) => f.endsWith(".ts") || f.endsWith(".js")); -agentFiles.forEach(file => { - const agent = require(path.join(agentsPath, file)); - console.log(`${agent.name || file.replace(".ts", "")} (${agent.id}) - ${agent.description}`); -}); +for (const file of agentFiles) { + const full = path.join(agentsPath, file); + try { + // Support both ESM transpiled and TS via tsx + // eslint-disable-next-line @typescript-eslint/no-var-requires + const mod = require(full); + const exportKeys = Object.keys(mod); + const exported = exportKeys.length === 1 ? mod[exportKeys[0]] : mod.ExampleAgent || mod.default || mod; + const name = exported?.name ?? path.basename(file, path.extname(file)); + const id = exported?.id ?? "unknown"; + const desc = exported?.description ?? "(no description)"; + console.log(`${name} (${id}) - ${desc}`); + } catch (err) { + console.error(`Failed to load agent from ${file}:`, (err as Error).message); + } +} diff --git a/scripts/generate-agent.ts b/scripts/generate-agent.ts index c84e792..10158bc 100644 --- a/scripts/generate-agent.ts +++ b/scripts/generate-agent.ts @@ -1,12 +1,36 @@ import fs from 'fs'; +import path from 'path'; const name = process.argv[2]; if (!name) throw new Error("Please specify agent name."); -const content = `export const ${name} = { +const targetPath = path.join(process.cwd(), 'agents', `${name.toLowerCase()}.ts`); +if (fs.existsSync(targetPath)) { + throw new Error(`Agent file already exists: ${targetPath}`); +} + +const content = `import { Agent } from "../types/agent"; +import { generateSignalHash } from "../utils/signal"; +import { logSignal } from "../utils/logger"; + +export const ${name}: Agent = { id: "${name.toLowerCase()}", name: "${name}", - ... -};`; + role: "template", + glyph: "?", + watchType: "wallet_activity", + triggerThreshold: 3, + lastSignal: null, + originTimestamp: new Date().toISOString(), + description: "${name} agent", + observe: (event) => { + if (!event) return; + const hash = generateSignalHash(event); + logSignal({ agent: "${name}", type: "observe", glyph: "?", hash, timestamp: new Date().toISOString() }); + }, + getMemory: () => [], +}; +`; -fs.writeFileSync(`agents/${name.toLowerCase()}.ts`, content); +fs.writeFileSync(targetPath, content, 'utf8'); +console.log(`Created ${targetPath}`); diff --git a/scripts/validate-agent.ts b/scripts/validate-agent.ts index 20a2e1c..f5aafa9 100644 --- a/scripts/validate-agent.ts +++ b/scripts/validate-agent.ts @@ -1,3 +1,59 @@ +import * as fs from "fs"; +import * as path from "path"; + +type ValidationIssue = { file: string; message: string }; + +const agentsDir = path.join(__dirname, "../agents"); +const files = fs + .readdirSync(agentsDir) + .filter((f) => f.endsWith(".ts") || f.endsWith(".js")); + +const issues: ValidationIssue[] = []; + +for (const file of files) { + const full = path.join(agentsDir, file); + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const mod = require(full); + const exportKeys = Object.keys(mod); + const agent = exportKeys.length === 1 ? mod[exportKeys[0]] : mod.default || mod.ExampleAgent || mod; + + const required = [ + "id", + "name", + "role", + "glyph", + "watchType", + "triggerThreshold", + "originTimestamp", + "description", + "observe", + ]; + for (const key of required) { + if (!(key in agent)) { + issues.push({ file, message: `Missing required field: ${key}` }); + } + } + + if (typeof agent.observe !== "function") { + issues.push({ file, message: `observe must be a function` }); + } + } catch (e) { + issues.push({ file, message: `Failed to load: ${(e as Error).message}` }); + } +} + +if (issues.length === 0) { + console.log("All agents look valid."); + process.exit(0); +} else { + console.error("Validation issues found:\n"); + for (const issue of issues) { + console.error(`- ${issue.file}: ${issue.message}`); + } + process.exit(1); +} + import { Agent } from "../types/agent"; import fs from "fs"; diff --git a/tsconfig.json b/tsconfig.json index 0651f2f..3ba13a5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,5 +7,5 @@ "forceConsistentCasingInFileNames": true, "skipLibCheck": true }, - "include": ["./agents", "./types", "./utils"] + "include": ["./agents", "./types", "./utils", "./scripts"] }