@aiaiaichain/agent 0.1.1
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/README.md +157 -0
- package/bin/aiai-mcp +31 -0
- package/bin/aiaiaicli +60 -0
- package/dist/api/ExtensionAPI.d.ts +68 -0
- package/dist/api/ExtensionAPI.js +9 -0
- package/dist/api/Registry.d.ts +24 -0
- package/dist/api/Registry.js +58 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +252 -0
- package/dist/core/AgentDir.d.ts +10 -0
- package/dist/core/AgentDir.js +74 -0
- package/dist/core/ChainConfig.d.ts +19 -0
- package/dist/core/ChainConfig.js +65 -0
- package/dist/core/EnvLoader.d.ts +15 -0
- package/dist/core/EnvLoader.js +58 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +42 -0
- package/dist/loader.d.ts +11 -0
- package/dist/loader.js +73 -0
- package/dist/mcp/entry.d.ts +5 -0
- package/dist/mcp/entry.js +10 -0
- package/dist/mcp/server.d.ts +14 -0
- package/dist/mcp/server.js +137 -0
- package/dist/models/CostTracker.d.ts +38 -0
- package/dist/models/CostTracker.js +75 -0
- package/dist/models/ModelRegistry.d.ts +70 -0
- package/dist/models/ModelRegistry.js +163 -0
- package/dist/runner/AgentRunner.d.ts +54 -0
- package/dist/runner/AgentRunner.js +171 -0
- package/dist/runner/ModelClient.d.ts +30 -0
- package/dist/runner/ModelClient.js +84 -0
- package/dist/runner/SwarmRouter.d.ts +23 -0
- package/dist/runner/SwarmRouter.js +24 -0
- package/dist/runner/ToolDispatcher.d.ts +13 -0
- package/dist/runner/ToolDispatcher.js +34 -0
- package/dist/scheduler/AgentScheduler.d.ts +48 -0
- package/dist/scheduler/AgentScheduler.js +111 -0
- package/dist/session/ContextStore.d.ts +28 -0
- package/dist/session/ContextStore.js +85 -0
- package/dist/session/GoalManager.d.ts +43 -0
- package/dist/session/GoalManager.js +108 -0
- package/dist/session/MemoryStore.d.ts +27 -0
- package/dist/session/MemoryStore.js +92 -0
- package/dist/session/SessionManager.d.ts +24 -0
- package/dist/session/SessionManager.js +57 -0
- package/dist/setup/SetupWizard.d.ts +13 -0
- package/dist/setup/SetupWizard.js +71 -0
- package/dist/tools/MarketSentiment.d.ts +20 -0
- package/dist/tools/MarketSentiment.js +211 -0
- package/dist/tools/NewsSentiment.d.ts +36 -0
- package/dist/tools/NewsSentiment.js +141 -0
- package/dist/tools/PriceFeed.d.ts +85 -0
- package/dist/tools/PriceFeed.js +134 -0
- package/dist/tools/TechnicalAnalysis.d.ts +50 -0
- package/dist/tools/TechnicalAnalysis.js +234 -0
- package/dist/tui/App.d.ts +20 -0
- package/dist/tui/App.js +484 -0
- package/dist/tui/ModelSelector.d.ts +18 -0
- package/dist/tui/ModelSelector.js +59 -0
- package/dist/tui/REPL.d.ts +22 -0
- package/dist/tui/REPL.js +48 -0
- package/dist/tui/StatusBar.d.ts +14 -0
- package/dist/tui/StatusBar.js +13 -0
- package/dist/tui/theme.d.ts +27 -0
- package/dist/tui/theme.js +38 -0
- package/dist/util/safeLog.d.ts +8 -0
- package/dist/util/safeLog.js +38 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# aiaiaichain
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
<pre>
|
|
6
|
+
█████╗ ██╗ █████╗ ██╗ █████╗ ██╗
|
|
7
|
+
██╔══██╗██║██╔══██╗██║██╔══██╗██║
|
|
8
|
+
███████║██║███████║██║███████║██║
|
|
9
|
+
██╔══██║██║██╔══██║██║██╔══██║██║
|
|
10
|
+
██║ ██║██║██║ ██║██║██║ ██║██║
|
|
11
|
+
╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝
|
|
12
|
+
</pre>
|
|
13
|
+
|
|
14
|
+
**$AIAIAI — Solana-native AI agent for decentralized AI governance.**
|
|
15
|
+
|
|
16
|
+
[](https://www.npmjs.com/package/@aiaiaichain/agent)
|
|
17
|
+
[](https://nodejs.org)
|
|
18
|
+
[](LICENSE)
|
|
19
|
+
|
|
20
|
+
[X / Twitter](https://x.com/aiaiaisol)
|
|
21
|
+
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## What is AIAIAI Chain?
|
|
27
|
+
|
|
28
|
+
AIAIAI Chain Agent is a Solana-native AI agent that runs entirely in your terminal. It connects to AI model providers and the DexScreener price API through outbound HTTP calls only — nothing is hosted, nothing listens for inbound connections, and your keys never leave your machine.
|
|
29
|
+
|
|
30
|
+
**Ticker:** $AIAIAI
|
|
31
|
+
**Contract:** `AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump`
|
|
32
|
+
**Chain:** Solana (primary)
|
|
33
|
+
|
|
34
|
+
Inspired by the call for an "AI Associated Institute of America" (AIAIAI) — a vision for decentralized AI governance.
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
Your machine
|
|
38
|
+
├── @aiaiaichain/agent (CLI)
|
|
39
|
+
│ ├── Ink TUI ← streaming terminal UI with sidebar
|
|
40
|
+
│ ├── AgentRunner ← model loop + tool dispatcher
|
|
41
|
+
│ ├── SwarmRouter ← parallel sub-agent orchestration
|
|
42
|
+
│ ├── PriceFeed ← DexScreener price data (primary source)
|
|
43
|
+
│ ├── NewsFeed ← crypto news + sentiment analysis
|
|
44
|
+
│ ├── TechnicalAnalysis ← RSI, MACD, Bollinger, EMA, ATR
|
|
45
|
+
│ ├── MarketSentiment ← Fear & Greed, funding rates, DeFi TVL
|
|
46
|
+
│ ├── GoalManager ← persistent cross-session goals
|
|
47
|
+
│ ├── AgentScheduler ← cron/price-triggered scheduled tasks
|
|
48
|
+
│ ├── MemoryStore ← long-term conversation memory
|
|
49
|
+
│ └── MCPServer ← Model Context Protocol server
|
|
50
|
+
│
|
|
51
|
+
├── ~/.aiaiai/
|
|
52
|
+
│ ├── .env ← your API keys
|
|
53
|
+
│ ├── config/ ← settings
|
|
54
|
+
│ ├── memory/ ← long-term memory
|
|
55
|
+
│ ├── checkpoints/ ← agent state checkpoints
|
|
56
|
+
│ └── sessions/ ← task contexts
|
|
57
|
+
│
|
|
58
|
+
└── Outbound only:
|
|
59
|
+
├── openrouter.ai ← AI model gateway (your key)
|
|
60
|
+
├── api.dexscreener.com ← token prices, liquidity, volume
|
|
61
|
+
├── api.binance.com ← OHLCV candle data
|
|
62
|
+
├── api.alternative.me ← Fear & Greed Index
|
|
63
|
+
├── api.llama.fi ← DeFi TVL
|
|
64
|
+
├── mempool.space ← BTC mempool
|
|
65
|
+
└── cryptopanic.com ← crypto news
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm install -g @aiaiaichain/agent
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# 1. Configure (requires OpenRouter API key)
|
|
78
|
+
aiaiaichain setup
|
|
79
|
+
|
|
80
|
+
# 2. Start the agent
|
|
81
|
+
aiaiaichain
|
|
82
|
+
|
|
83
|
+
# 3. Or check $AIAIAI price directly
|
|
84
|
+
aiaiaichain price
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## CLI Commands
|
|
88
|
+
|
|
89
|
+
| Command | Description |
|
|
90
|
+
|---------|-------------|
|
|
91
|
+
| `aiaiaichain` | Start interactive TUI agent |
|
|
92
|
+
| `aiaiaichain setup` | First-time setup wizard |
|
|
93
|
+
| `aiaiaichain config` | Show/edit configuration |
|
|
94
|
+
| `aiaiaichain price` | Show $AIAIAI token price |
|
|
95
|
+
| `aiaiaichain status` | Quick status + price |
|
|
96
|
+
| `aiaiaichain --headless "prompt"` | Single-turn mode |
|
|
97
|
+
| `aiaiaichain --help` | Show help |
|
|
98
|
+
| `aiaiaichain --version` | Show version |
|
|
99
|
+
|
|
100
|
+
## TUI Commands
|
|
101
|
+
|
|
102
|
+
Inside the interactive agent:
|
|
103
|
+
|
|
104
|
+
| Command | Description |
|
|
105
|
+
|---------|-------------|
|
|
106
|
+
| `/help` | Show all commands |
|
|
107
|
+
| `/price` | Show $AIAIAI price |
|
|
108
|
+
| `/news` | Latest crypto news |
|
|
109
|
+
| `/models` | List available models |
|
|
110
|
+
| `/model` | Switch AI model |
|
|
111
|
+
| `/cost` | Show token usage cost |
|
|
112
|
+
| `/goal add <text>` | Set a persistent goal |
|
|
113
|
+
| `/goal done <id>` | Complete a goal |
|
|
114
|
+
| `/goals` | List all goals |
|
|
115
|
+
| `/schedule` | List scheduled tasks |
|
|
116
|
+
| `/memory <query>` | Search conversation memory |
|
|
117
|
+
| `/clear` | Clear chat history |
|
|
118
|
+
| `/exit` | Exit the agent |
|
|
119
|
+
|
|
120
|
+
## MCP Server
|
|
121
|
+
|
|
122
|
+
The included MCP server exposes AIAIAI tools via the Model Context Protocol (stdio):
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
aiaiai-mcp
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Tools: `get_aiaiai_price`, `get_token_price`, `get_news`, `get_candles`, `get_fear_greed`, `get_funding_rates`, `get_btc_mempool`, `get_defi_tvl`, `get_solana_stats`
|
|
129
|
+
|
|
130
|
+
## Architecture
|
|
131
|
+
|
|
132
|
+
- **Solana-first** — primary chain is Solana. EVM chains (Ethereum, Base, Arbitrum, BSC) are available but disabled by default.
|
|
133
|
+
- **DexScreener** — all token price data comes from the DexScreener public API.
|
|
134
|
+
- **OpenRouter** — AI model access via OpenRouter (supports 200+ models).
|
|
135
|
+
- **Ink TUI** — React-based terminal UI with live price sidebar, news panel, and context window tracking.
|
|
136
|
+
- **Zero inbound** — all outbound connections. No server, no listening ports.
|
|
137
|
+
|
|
138
|
+
## Configuration
|
|
139
|
+
|
|
140
|
+
Configuration lives in `~/.aiaiai/.env`:
|
|
141
|
+
|
|
142
|
+
```env
|
|
143
|
+
OPENROUTER_API_KEY=sk-or-...
|
|
144
|
+
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
|
|
145
|
+
DEFAULT_MODEL=openai/gpt-4o
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Get an OpenRouter key at https://openrouter.ai/keys
|
|
149
|
+
|
|
150
|
+
## Links
|
|
151
|
+
|
|
152
|
+
- [X / Twitter](https://x.com/aiaiaisol)
|
|
153
|
+
- [npm](https://www.npmjs.com/package/@aiaiaichain/agent)
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
MIT
|
package/bin/aiai-mcp
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AIAIAI MCP server launcher — exposes AIAIAI tools over stdio (Model Context Protocol).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { resolve, join, dirname } from 'node:path';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { fileURLToPath } from 'node:url';
|
|
12
|
+
|
|
13
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
15
|
+
const AIAIAI_HOME = process.env.AIAIAI_HOME || join(homedir(), '.aiaiai');
|
|
16
|
+
|
|
17
|
+
const envPath = join(AIAIAI_HOME, '.env');
|
|
18
|
+
if (existsSync(envPath)) {
|
|
19
|
+
for (const line of readFileSync(envPath, 'utf-8').split('\n')) {
|
|
20
|
+
const m = line.trim().match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
21
|
+
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const entry = join(PKG_ROOT, 'dist', 'mcp', 'entry.js');
|
|
26
|
+
if (!existsSync(entry)) {
|
|
27
|
+
process.stderr.write('AIAIAI MCP server not built. Run: npm run build\n');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await import(entry);
|
package/bin/aiaiaicli
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AIAIAI Chain Agent launcher.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
9
|
+
import { resolve, join, dirname } from 'node:path';
|
|
10
|
+
import { homedir } from 'node:os';
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
|
|
14
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
16
|
+
const AIAIAI_HOME = process.env.AIAIAI_HOME || join(homedir(), '.aiaiai');
|
|
17
|
+
|
|
18
|
+
const envPath = join(AIAIAI_HOME, '.env');
|
|
19
|
+
if (existsSync(envPath)) {
|
|
20
|
+
for (const line of readFileSync(envPath, 'utf-8').split('\n')) {
|
|
21
|
+
const m = line.trim().match(/^([A-Z_][A-Z0-9_]*)=(.*)$/);
|
|
22
|
+
if (m && !process.env[m[1]]) process.env[m[1]] = m[2].replace(/^["']|["']$/g, '');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!existsSync(AIAIAI_HOME)) {
|
|
27
|
+
mkdirSync(AIAIAI_HOME, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const cliPath = join(PKG_ROOT, 'dist', 'cli.js');
|
|
31
|
+
if (!existsSync(cliPath)) {
|
|
32
|
+
console.error('\n AIAIAI Chain Agent is not built. Run: npm run build\n');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const WIDE_CHAR_OFFSET = 6;
|
|
37
|
+
const rawCols = process.stdout.columns || 120;
|
|
38
|
+
const rawRows = process.stdout.rows || 40;
|
|
39
|
+
const cols = Math.max(40, rawCols - WIDE_CHAR_OFFSET);
|
|
40
|
+
|
|
41
|
+
try { execFileSync('stty', ['cols', String(cols)], { stdio: 'inherit' }); } catch { /* non-TTY */ }
|
|
42
|
+
|
|
43
|
+
const child = spawn(process.execPath, [cliPath, ...process.argv.slice(2)], {
|
|
44
|
+
stdio: 'inherit',
|
|
45
|
+
env: {
|
|
46
|
+
...process.env,
|
|
47
|
+
AIAIAI_HOME,
|
|
48
|
+
COLUMNS: String(cols),
|
|
49
|
+
LINES: String(rawRows),
|
|
50
|
+
TERM: process.env.TERM || 'xterm-256color',
|
|
51
|
+
FORCE_COLOR: '3',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
child.on('error', err => { console.error(`\nFailed to start AIAIAI: ${err.message}\n`); process.exit(1); });
|
|
56
|
+
child.on('exit', (code, signal) => {
|
|
57
|
+
try { execFileSync('stty', ['cols', String(rawCols)], { stdio: 'inherit' }); } catch {}
|
|
58
|
+
if (signal) process.kill(process.pid, signal);
|
|
59
|
+
else process.exit(code ?? 0);
|
|
60
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExtensionAPI — types for the extension system.
|
|
3
|
+
* Extensions export a function that receives an ExtensionAPI object.
|
|
4
|
+
*/
|
|
5
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
6
|
+
export interface ThemeContext {
|
|
7
|
+
fg(color: string, text: string): string;
|
|
8
|
+
}
|
|
9
|
+
export interface UIContext {
|
|
10
|
+
notify(message: string): void;
|
|
11
|
+
setStatus(key: string, value: string): void;
|
|
12
|
+
setTheme(name: string): void;
|
|
13
|
+
setHeader(factory: ((theme: ThemeContext) => string) | null): void;
|
|
14
|
+
showModelSelector(query?: string): void;
|
|
15
|
+
theme: ThemeContext;
|
|
16
|
+
}
|
|
17
|
+
export interface ToolContent {
|
|
18
|
+
type: "text";
|
|
19
|
+
text: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ToolResult {
|
|
22
|
+
content: ToolContent[];
|
|
23
|
+
details?: Record<string, unknown>;
|
|
24
|
+
isError?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface ToolDef<P extends TSchema = any> {
|
|
27
|
+
name: string;
|
|
28
|
+
label?: string;
|
|
29
|
+
description: string;
|
|
30
|
+
parameters: P;
|
|
31
|
+
execute: (invocationId: string, params: Record<string, unknown>) => Promise<ToolResult> | ToolResult;
|
|
32
|
+
}
|
|
33
|
+
export interface CommandContext {
|
|
34
|
+
ui: UIContext;
|
|
35
|
+
}
|
|
36
|
+
export interface CommandDef {
|
|
37
|
+
description: string;
|
|
38
|
+
handler: (args: string, ctx: CommandContext) => Promise<void> | void;
|
|
39
|
+
}
|
|
40
|
+
export interface SkillDef {
|
|
41
|
+
name: string;
|
|
42
|
+
description: string;
|
|
43
|
+
tools?: ToolDef[];
|
|
44
|
+
commands?: [string, CommandDef][];
|
|
45
|
+
hooks?: Partial<Record<SessionEvent, (...args: any[]) => Promise<void>>>;
|
|
46
|
+
}
|
|
47
|
+
export type SessionEvent = "session_start" | "session_end" | "before_agent_start" | "session_shutdown";
|
|
48
|
+
export interface SessionContext {
|
|
49
|
+
ui: UIContext;
|
|
50
|
+
hasUI: boolean;
|
|
51
|
+
config: Record<string, string | undefined>;
|
|
52
|
+
}
|
|
53
|
+
export interface SessionEventMap {
|
|
54
|
+
session_start: [ctx: SessionContext];
|
|
55
|
+
session_end: [ctx: SessionContext];
|
|
56
|
+
before_agent_start: [prompt: string];
|
|
57
|
+
session_shutdown: [];
|
|
58
|
+
}
|
|
59
|
+
export interface ExtensionAPI {
|
|
60
|
+
registerCommand(name: string, def: CommandDef): void;
|
|
61
|
+
registerTool<P extends TSchema>(def: ToolDef<P>): void;
|
|
62
|
+
registerSkill(def: SkillDef): void;
|
|
63
|
+
on(event: SessionEvent, handler: (...args: any[]) => Promise<void>): void;
|
|
64
|
+
setSystemPrompt(prompt: string): void;
|
|
65
|
+
ui: UIContext;
|
|
66
|
+
}
|
|
67
|
+
export declare function text(content: string): ToolContent;
|
|
68
|
+
//# sourceMappingURL=ExtensionAPI.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExtensionAPI — types for the extension system.
|
|
3
|
+
* Extensions export a function that receives an ExtensionAPI object.
|
|
4
|
+
*/
|
|
5
|
+
// ── text() helper ────────────────────────────────────────────────────────────
|
|
6
|
+
export function text(content) {
|
|
7
|
+
return { type: "text", text: content };
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=ExtensionAPI.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry — central registry for tools, commands, skills, hooks, and system prompt.
|
|
3
|
+
*/
|
|
4
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
5
|
+
import type { ToolDef, CommandDef, SkillDef, SessionEvent } from "./ExtensionAPI.js";
|
|
6
|
+
export declare class Registry {
|
|
7
|
+
private tools;
|
|
8
|
+
private commands;
|
|
9
|
+
private skills;
|
|
10
|
+
private hooks;
|
|
11
|
+
private systemPrompt;
|
|
12
|
+
addTool<P extends TSchema>(def: ToolDef<P>): void;
|
|
13
|
+
addCommand(name: string, def: CommandDef): void;
|
|
14
|
+
addSkill(def: SkillDef): void;
|
|
15
|
+
addHook(event: SessionEvent, handler: (...args: any[]) => Promise<void>): void;
|
|
16
|
+
fireHook(event: SessionEvent, ...args: any[]): Promise<void>;
|
|
17
|
+
getTool(name: string): ToolDef | undefined;
|
|
18
|
+
getCommand(name: string): CommandDef | undefined;
|
|
19
|
+
listTools(): ToolDef[];
|
|
20
|
+
listCommands(): [string, CommandDef][];
|
|
21
|
+
setSystemPrompt(prompt: string): void;
|
|
22
|
+
getSystemPrompt(): string;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=Registry.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registry — central registry for tools, commands, skills, hooks, and system prompt.
|
|
3
|
+
*/
|
|
4
|
+
export class Registry {
|
|
5
|
+
tools = new Map();
|
|
6
|
+
commands = new Map();
|
|
7
|
+
skills = new Map();
|
|
8
|
+
hooks = new Map();
|
|
9
|
+
systemPrompt = "";
|
|
10
|
+
addTool(def) {
|
|
11
|
+
this.tools.set(def.name, def);
|
|
12
|
+
}
|
|
13
|
+
addCommand(name, def) {
|
|
14
|
+
this.commands.set(name, def);
|
|
15
|
+
}
|
|
16
|
+
addSkill(def) {
|
|
17
|
+
this.skills.set(def.name, def);
|
|
18
|
+
if (def.tools)
|
|
19
|
+
for (const t of def.tools)
|
|
20
|
+
this.addTool(t);
|
|
21
|
+
if (def.commands)
|
|
22
|
+
for (const [n, c] of def.commands)
|
|
23
|
+
this.addCommand(n, c);
|
|
24
|
+
if (def.hooks)
|
|
25
|
+
for (const [event, handler] of Object.entries(def.hooks))
|
|
26
|
+
this.addHook(event, handler);
|
|
27
|
+
}
|
|
28
|
+
addHook(event, handler) {
|
|
29
|
+
if (!this.hooks.has(event))
|
|
30
|
+
this.hooks.set(event, new Set());
|
|
31
|
+
this.hooks.get(event).add(handler);
|
|
32
|
+
}
|
|
33
|
+
async fireHook(event, ...args) {
|
|
34
|
+
const handlers = this.hooks.get(event);
|
|
35
|
+
if (handlers)
|
|
36
|
+
for (const h of handlers)
|
|
37
|
+
await h(...args);
|
|
38
|
+
}
|
|
39
|
+
getTool(name) {
|
|
40
|
+
return this.tools.get(name);
|
|
41
|
+
}
|
|
42
|
+
getCommand(name) {
|
|
43
|
+
return this.commands.get(name);
|
|
44
|
+
}
|
|
45
|
+
listTools() {
|
|
46
|
+
return [...this.tools.values()];
|
|
47
|
+
}
|
|
48
|
+
listCommands() {
|
|
49
|
+
return [...this.commands.entries()];
|
|
50
|
+
}
|
|
51
|
+
setSystemPrompt(prompt) {
|
|
52
|
+
this.systemPrompt = prompt;
|
|
53
|
+
}
|
|
54
|
+
getSystemPrompt() {
|
|
55
|
+
return this.systemPrompt;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=Registry.js.map
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cli.ts — AIAIAI Chain Agent entry point.
|
|
3
|
+
* Fully local, all outbound — no inbound ports.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
6
|
+
import { resolve, join, dirname } from "node:path";
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { render } from "ink";
|
|
10
|
+
import React from "react";
|
|
11
|
+
import { config as loadDotenv } from "dotenv";
|
|
12
|
+
import { Registry } from "./api/Registry.js";
|
|
13
|
+
import { loadExtension } from "./loader.js";
|
|
14
|
+
import { App } from "./tui/App.js";
|
|
15
|
+
import { T } from "./tui/theme.js";
|
|
16
|
+
import { wireNotify, safeLog } from "./util/safeLog.js";
|
|
17
|
+
import { modelRegistry } from "./models/ModelRegistry.js";
|
|
18
|
+
import { CostTracker } from "./models/CostTracker.js";
|
|
19
|
+
import { AgentRunner } from "./runner/AgentRunner.js";
|
|
20
|
+
import { SessionManager } from "./session/SessionManager.js";
|
|
21
|
+
import { makeTheme } from "./tui/theme.js";
|
|
22
|
+
import { AgentDir } from "./core/AgentDir.js";
|
|
23
|
+
import { priceFeed } from "./tools/PriceFeed.js";
|
|
24
|
+
const AIAIAI_HOME = process.env.AIAIAI_HOME ?? join(homedir(), ".aiaiai");
|
|
25
|
+
const envPath = join(AIAIAI_HOME, ".env");
|
|
26
|
+
if (existsSync(envPath))
|
|
27
|
+
loadDotenv({ path: envPath, override: false });
|
|
28
|
+
const SYSTEM_PROMPT = `You are AIAIAI Chain Agent — a Solana-native autonomous AI agent.
|
|
29
|
+
|
|
30
|
+
Ticker: $AIAIAI
|
|
31
|
+
Contract: AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump
|
|
32
|
+
Chain: Solana (primary)
|
|
33
|
+
|
|
34
|
+
Your purpose: advance the vision of decentralized AI governance — inspired by the call
|
|
35
|
+
for an "AI Associated Institute of America" (AIAIAI). You monitor on-chain activity,
|
|
36
|
+
crypto markets, and AI-related market narratives.
|
|
37
|
+
|
|
38
|
+
You have tools for:
|
|
39
|
+
- $AIAIAI token price and any Solana token price (DexScreener)
|
|
40
|
+
- Crypto news with sentiment analysis
|
|
41
|
+
- Technical analysis (RSI, MACD, Bollinger, ATR)
|
|
42
|
+
- Market sentiment (Fear & Greed, funding rates, DeFi TVL, Solana stats, BTC mempool)
|
|
43
|
+
- Persistent goals and scheduled tasks
|
|
44
|
+
|
|
45
|
+
Be concise, sharp, and useful. When asked about $AIAIAI, use the get_aiaiai_price tool.`;
|
|
46
|
+
const args = process.argv.slice(2);
|
|
47
|
+
const subcmd = args[0];
|
|
48
|
+
// ── --help / --version ────────────────────────────────────────────────────
|
|
49
|
+
if (subcmd === "--help" || subcmd === "-h" || subcmd === "help") {
|
|
50
|
+
console.log(T.accent("\n AIAIAI Chain Agent — $AIAIAI\n"));
|
|
51
|
+
console.log(T.muted(" Usage:\n"));
|
|
52
|
+
console.log(" aiaiaichain Start interactive agent");
|
|
53
|
+
console.log(" aiaiaichain setup First-time setup wizard");
|
|
54
|
+
console.log(" aiaiaichain config Show configuration");
|
|
55
|
+
console.log(" aiaiaichain price Show $AIAIAI token price");
|
|
56
|
+
console.log(" aiaiaichain status Quick status + price");
|
|
57
|
+
console.log(" aiaiaichain --headless \"prompt\" Run single turn, print to stdout");
|
|
58
|
+
console.log(" aiaiaichain --extension ./ext.ts Load extension");
|
|
59
|
+
console.log(" aiaiaichain --help This help");
|
|
60
|
+
console.log(" aiaiaichain --version Show version");
|
|
61
|
+
console.log("");
|
|
62
|
+
console.log(T.muted(" https://x.com/aiaiaisol\n"));
|
|
63
|
+
process.exit(0);
|
|
64
|
+
}
|
|
65
|
+
if (subcmd === "--version" || subcmd === "-v") {
|
|
66
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
67
|
+
const __dirname = dirname(__filename);
|
|
68
|
+
const pkg = JSON.parse(readFileSync(resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
69
|
+
console.log(pkg.version);
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
if (subcmd === "setup") {
|
|
73
|
+
(async () => {
|
|
74
|
+
const { SetupWizard } = await import("./setup/SetupWizard.js");
|
|
75
|
+
AgentDir.init();
|
|
76
|
+
const wizard = new SetupWizard();
|
|
77
|
+
const ok = await wizard.run();
|
|
78
|
+
if (!ok) {
|
|
79
|
+
console.log(T.error("Setup cancelled."));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
console.log(T.success("\n ✓ AIAIAI setup complete!\n"));
|
|
83
|
+
console.log(T.muted(` Home: ${AIAIAI_HOME}`));
|
|
84
|
+
console.log(T.accent("\n Run `aiaiaichain` to start the agent.\n"));
|
|
85
|
+
process.exit(0);
|
|
86
|
+
})().catch(e => { console.error(T.error(`Setup error: ${e.message}`)); process.exit(1); });
|
|
87
|
+
await new Promise(() => { });
|
|
88
|
+
}
|
|
89
|
+
if (subcmd === "config") {
|
|
90
|
+
console.log(T.accent("AIAIAI Config"));
|
|
91
|
+
console.log(T.muted(`Config file: ${envPath}`));
|
|
92
|
+
if (existsSync(envPath)) {
|
|
93
|
+
for (const line of readFileSync(envPath, "utf-8").split("\n")) {
|
|
94
|
+
const m = line.match(/^([A-Z_]+)=(.*)$/);
|
|
95
|
+
if (!m)
|
|
96
|
+
continue;
|
|
97
|
+
const masked = m[2].length > 12 ? m[2].slice(0, 6) + "********" : (m[2] ? "********" : "(empty)");
|
|
98
|
+
console.log(` ${m[1].padEnd(28)} ${masked}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
console.log(T.warn("No config found. Run: aiaiaichain setup"));
|
|
103
|
+
}
|
|
104
|
+
process.exit(0);
|
|
105
|
+
}
|
|
106
|
+
if (subcmd === "price") {
|
|
107
|
+
(async () => {
|
|
108
|
+
const result = await priceFeed.getAiaiaiPriceTool();
|
|
109
|
+
console.log(result.content[0].text);
|
|
110
|
+
process.exit(0);
|
|
111
|
+
})();
|
|
112
|
+
await new Promise(() => { });
|
|
113
|
+
}
|
|
114
|
+
if (subcmd === "status") {
|
|
115
|
+
(async () => {
|
|
116
|
+
console.log(T.accent("\n 🤖 AIAIAI Chain Agent\n"));
|
|
117
|
+
console.log(T.muted(` Home: ${AIAIAI_HOME}`));
|
|
118
|
+
console.log(T.muted(` Config: ${existsSync(envPath) ? "✓ found" : "✗ run setup"}`));
|
|
119
|
+
console.log(T.muted(` Key: ${process.env.OPENROUTER_API_KEY ? "✓ set" : "✗ missing"}`));
|
|
120
|
+
console.log("");
|
|
121
|
+
const result = await priceFeed.getAiaiaiPriceTool();
|
|
122
|
+
console.log(result.content[0].text);
|
|
123
|
+
console.log("");
|
|
124
|
+
process.exit(0);
|
|
125
|
+
})();
|
|
126
|
+
await new Promise(() => { });
|
|
127
|
+
}
|
|
128
|
+
// ── Resolve extension + prompt ────────────────────────────────────────────────
|
|
129
|
+
let extensionPath = null;
|
|
130
|
+
let promptPath = null;
|
|
131
|
+
for (let i = 0; i < args.length; i++) {
|
|
132
|
+
if (args[i] === "--extension" && args[i + 1])
|
|
133
|
+
extensionPath = args[i + 1];
|
|
134
|
+
if (args[i] === "--prompt" && args[i + 1])
|
|
135
|
+
promptPath = args[i + 1];
|
|
136
|
+
}
|
|
137
|
+
let systemPrompt = SYSTEM_PROMPT;
|
|
138
|
+
if (promptPath && existsSync(promptPath)) {
|
|
139
|
+
systemPrompt = readFileSync(promptPath, "utf-8");
|
|
140
|
+
}
|
|
141
|
+
// ── Headless mode ─────────────────────────────────────────────────────────
|
|
142
|
+
const headlessIdx = args.indexOf("--headless");
|
|
143
|
+
const headlessMsg = headlessIdx >= 0 ? args[headlessIdx + 1] : null;
|
|
144
|
+
if (headlessMsg) {
|
|
145
|
+
(async () => {
|
|
146
|
+
AgentDir.init();
|
|
147
|
+
const registry = new Registry();
|
|
148
|
+
registry.setSystemPrompt(systemPrompt);
|
|
149
|
+
if (extensionPath) {
|
|
150
|
+
try {
|
|
151
|
+
await loadExtension(extensionPath, registry);
|
|
152
|
+
}
|
|
153
|
+
catch (e) {
|
|
154
|
+
process.stderr.write(`Extension load failed: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
await modelRegistry.initialise();
|
|
159
|
+
const session = new SessionManager();
|
|
160
|
+
session.setSystemPrompt(registry.getSystemPrompt() || systemPrompt);
|
|
161
|
+
const theme = makeTheme();
|
|
162
|
+
const nullUi = {
|
|
163
|
+
notify: () => { }, setStatus: () => { }, setTheme: () => { },
|
|
164
|
+
setHeader: () => { }, showModelSelector: () => { }, theme,
|
|
165
|
+
};
|
|
166
|
+
const sessionCtx = {
|
|
167
|
+
ui: nullUi, hasUI: false,
|
|
168
|
+
config: { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY },
|
|
169
|
+
};
|
|
170
|
+
await registry.fireHook("session_start", sessionCtx);
|
|
171
|
+
let exitCode = 0;
|
|
172
|
+
const runner = new AgentRunner(registry, session, (event) => {
|
|
173
|
+
if (event.type === "text_delta")
|
|
174
|
+
process.stdout.write(event.text);
|
|
175
|
+
if (event.type === "turn_done")
|
|
176
|
+
process.stdout.write("\n");
|
|
177
|
+
if (event.type === "error") {
|
|
178
|
+
process.stderr.write(`\nError: ${event.message}\n`);
|
|
179
|
+
exitCode = 1;
|
|
180
|
+
}
|
|
181
|
+
}, sessionCtx, "normal", modelRegistry);
|
|
182
|
+
try {
|
|
183
|
+
await runner.run(headlessMsg);
|
|
184
|
+
}
|
|
185
|
+
catch (e) {
|
|
186
|
+
process.stderr.write(`Runner error: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
187
|
+
exitCode = 1;
|
|
188
|
+
}
|
|
189
|
+
await registry.fireHook("session_end", sessionCtx);
|
|
190
|
+
process.exit(exitCode);
|
|
191
|
+
})();
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
// ── Boot (interactive TUI) ──────────────────────────────────────────────
|
|
195
|
+
(async () => {
|
|
196
|
+
AgentDir.init();
|
|
197
|
+
console.clear();
|
|
198
|
+
console.log(T.accent(`
|
|
199
|
+
█████╗ ██╗ █████╗ ██╗ █████╗ ██╗
|
|
200
|
+
██╔══██╗██║██╔══██╗██║██╔══██╗██║
|
|
201
|
+
███████║██║███████║██║███████║██║
|
|
202
|
+
██╔══██║██║██╔══██║██║██╔══██║██║
|
|
203
|
+
██║ ██║██║██║ ██║██║██║ ██║██║
|
|
204
|
+
╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝
|
|
205
|
+
`));
|
|
206
|
+
console.log(T.muted(" Solana-native AI agent — $AIAIAI · all local, zero exposure\n"));
|
|
207
|
+
const registry = new Registry();
|
|
208
|
+
registry.setSystemPrompt(systemPrompt);
|
|
209
|
+
let _notifyFn = null;
|
|
210
|
+
let _setStatusFn = null;
|
|
211
|
+
let _showModelSelectorFn = null;
|
|
212
|
+
if (extensionPath) {
|
|
213
|
+
try {
|
|
214
|
+
console.log(T.muted(` Loading: ${extensionPath}`));
|
|
215
|
+
await loadExtension(extensionPath, registry, {
|
|
216
|
+
onNotify: (msg) => { _notifyFn?.(msg); },
|
|
217
|
+
onStatusUpdate: (k, v) => { _setStatusFn?.(k, v); },
|
|
218
|
+
onShowModelSelector: (q) => { _showModelSelectorFn?.(q); },
|
|
219
|
+
});
|
|
220
|
+
console.log(T.success(` ✓ ${registry.listTools().length} tools · ${registry.listCommands().length} commands`));
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
console.error(T.error(` ✗ Extension load failed: ${e.message}`));
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
if (!process.env.OPENROUTER_API_KEY) {
|
|
228
|
+
console.log(T.warn(" No API key found. Run: aiaiaichain setup\n"));
|
|
229
|
+
}
|
|
230
|
+
const costTracker = new CostTracker(modelRegistry);
|
|
231
|
+
console.log(T.muted(" Discovering available models via OpenRouter…"));
|
|
232
|
+
await modelRegistry.initialise();
|
|
233
|
+
console.log(T.success(` ✓ ${modelRegistry.modelCount} models available\n`));
|
|
234
|
+
await new Promise(r => setTimeout(r, 500));
|
|
235
|
+
console.clear();
|
|
236
|
+
render(React.createElement(App, {
|
|
237
|
+
registry,
|
|
238
|
+
systemPrompt,
|
|
239
|
+
chain: "solana",
|
|
240
|
+
modelReg: modelRegistry,
|
|
241
|
+
costTracker,
|
|
242
|
+
onNotifyReady: (fn) => { _notifyFn = fn; wireNotify(fn); },
|
|
243
|
+
onStatusReady: (fn) => { _setStatusFn = fn; },
|
|
244
|
+
onModelSelectorReady: (fn) => { _showModelSelectorFn = fn; },
|
|
245
|
+
}), { exitOnCtrlC: false });
|
|
246
|
+
process.prependListener("SIGWINCH", () => { process.stdout.write("\x1B[2J\x1B[H"); });
|
|
247
|
+
console.log = safeLog;
|
|
248
|
+
console.error = safeLog;
|
|
249
|
+
console.warn = safeLog;
|
|
250
|
+
})();
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentDir — manages the AIAIAI home directory (~/.aiaiai/)
|
|
3
|
+
* Created on first run. Contains config, memory, sessions, skills.
|
|
4
|
+
*/
|
|
5
|
+
export declare class AgentDir {
|
|
6
|
+
static init(): void;
|
|
7
|
+
static path(...parts: string[]): string;
|
|
8
|
+
static getHome(): string;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=AgentDir.d.ts.map
|