@jellyos/agent 0.1.3 → 0.1.5

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.
Files changed (90) hide show
  1. package/README.md +9 -9
  2. package/README.npm.md +212 -0
  3. package/bin/jellyos-mcp +26 -0
  4. package/dist/api/ExtensionAPI.d.ts +6 -0
  5. package/dist/api/Registry.js +3 -1
  6. package/dist/cli.js +117 -42
  7. package/dist/index.d.ts +24 -1
  8. package/dist/index.js +19 -2
  9. package/dist/mcp/entry.d.ts +2 -0
  10. package/dist/mcp/entry.js +71 -0
  11. package/dist/mcp/server.d.ts +31 -0
  12. package/dist/mcp/server.js +128 -0
  13. package/dist/models/CostTracker.d.ts +66 -0
  14. package/dist/models/CostTracker.js +148 -0
  15. package/dist/models/ModelRegistry.d.ts +157 -0
  16. package/dist/models/ModelRegistry.js +496 -0
  17. package/dist/models/index.d.ts +5 -0
  18. package/dist/models/index.js +3 -0
  19. package/dist/runner/AgentRunner.d.ts +23 -2
  20. package/dist/runner/AgentRunner.js +264 -24
  21. package/dist/runner/ModelClient.d.ts +26 -6
  22. package/dist/runner/ModelClient.js +147 -28
  23. package/dist/runner/SwarmRouter.d.ts +10 -7
  24. package/dist/runner/SwarmRouter.js +85 -28
  25. package/dist/runner/ToolDispatcher.d.ts +10 -0
  26. package/dist/runner/ToolDispatcher.js +106 -2
  27. package/dist/scheduler/AgentScheduler.d.ts +118 -0
  28. package/dist/scheduler/AgentScheduler.js +253 -0
  29. package/dist/session/ContextStore.d.ts +96 -0
  30. package/dist/session/ContextStore.js +207 -0
  31. package/dist/session/GoalManager.d.ts +101 -0
  32. package/dist/session/GoalManager.js +167 -0
  33. package/dist/session/MemoryStore.d.ts +48 -0
  34. package/dist/session/MemoryStore.js +166 -0
  35. package/dist/session/SessionManager.d.ts +45 -4
  36. package/dist/session/SessionManager.js +151 -8
  37. package/dist/telemetry/Tracer.d.ts +48 -0
  38. package/dist/telemetry/Tracer.js +102 -0
  39. package/dist/tests/ContextStore.test.d.ts +2 -0
  40. package/dist/tests/ContextStore.test.js +74 -0
  41. package/dist/tests/ModelRegistry.test.d.ts +2 -0
  42. package/dist/tests/ModelRegistry.test.js +69 -0
  43. package/dist/tests/SessionManager.test.d.ts +2 -0
  44. package/dist/tests/SessionManager.test.js +108 -0
  45. package/dist/tests/TechnicalAnalysis.test.d.ts +2 -0
  46. package/dist/tests/TechnicalAnalysis.test.js +109 -0
  47. package/dist/tools/MarketSentiment.d.ts +166 -0
  48. package/dist/tools/MarketSentiment.js +209 -0
  49. package/dist/tools/NewsSentiment.d.ts +67 -0
  50. package/dist/tools/NewsSentiment.js +226 -0
  51. package/dist/tools/PriceFeed.d.ts +105 -0
  52. package/dist/tools/PriceFeed.js +282 -0
  53. package/dist/tools/TechnicalAnalysis.d.ts +110 -0
  54. package/dist/tools/TechnicalAnalysis.js +357 -0
  55. package/dist/tools/index.d.ts +7 -0
  56. package/dist/tools/index.js +4 -0
  57. package/dist/tui/App.d.ts +7 -5
  58. package/dist/tui/App.js +350 -65
  59. package/dist/tui/REPL.d.ts +2 -1
  60. package/dist/tui/REPL.js +11 -6
  61. package/dist/tui/StatusBar.js +1 -1
  62. package/package.json +9 -4
  63. package/dist/api/ExtensionAPI.d.ts.map +0 -1
  64. package/dist/api/ExtensionAPI.js.map +0 -1
  65. package/dist/api/Registry.d.ts.map +0 -1
  66. package/dist/api/Registry.js.map +0 -1
  67. package/dist/cli.d.ts.map +0 -1
  68. package/dist/cli.js.map +0 -1
  69. package/dist/index.d.ts.map +0 -1
  70. package/dist/index.js.map +0 -1
  71. package/dist/loader.d.ts.map +0 -1
  72. package/dist/loader.js.map +0 -1
  73. package/dist/runner/AgentRunner.d.ts.map +0 -1
  74. package/dist/runner/AgentRunner.js.map +0 -1
  75. package/dist/runner/ModelClient.d.ts.map +0 -1
  76. package/dist/runner/ModelClient.js.map +0 -1
  77. package/dist/runner/SwarmRouter.d.ts.map +0 -1
  78. package/dist/runner/SwarmRouter.js.map +0 -1
  79. package/dist/runner/ToolDispatcher.d.ts.map +0 -1
  80. package/dist/runner/ToolDispatcher.js.map +0 -1
  81. package/dist/session/SessionManager.d.ts.map +0 -1
  82. package/dist/session/SessionManager.js.map +0 -1
  83. package/dist/tui/App.d.ts.map +0 -1
  84. package/dist/tui/App.js.map +0 -1
  85. package/dist/tui/REPL.d.ts.map +0 -1
  86. package/dist/tui/REPL.js.map +0 -1
  87. package/dist/tui/StatusBar.d.ts.map +0 -1
  88. package/dist/tui/StatusBar.js.map +0 -1
  89. package/dist/tui/theme.d.ts.map +0 -1
  90. package/dist/tui/theme.js.map +0 -1
package/README.md CHANGED
@@ -39,7 +39,7 @@ Your machine
39
39
  │ ├── VaultManager ← AES-256-GCM encrypted profit vault
40
40
  │ └── DashboardServer ← optional local WebSocket dashboard
41
41
 
42
- ├── ~/.jellyos/
42
+ ├── ~/.jelly/
43
43
  │ ├── .env ← your API keys
44
44
  │ ├── wallets/ ← local keypairs (never synced)
45
45
  │ ├── vault/ ← encrypted vault file
@@ -68,8 +68,8 @@ npm install -g @jellyos/agent
68
68
 
69
69
  ```bash
70
70
  # 1. Create config directory and set your API key
71
- mkdir -p ~/.jellyos
72
- echo "OPENROUTER_API_KEY=sk-or-..." > ~/.jellyos/.env
71
+ mkdir -p ~/.jelly
72
+ echo "OPENROUTER_API_KEY=sk-or-..." > ~/.jelly/.env
73
73
 
74
74
  # 2. Launch
75
75
  jellyos
@@ -91,7 +91,7 @@ cd JellyOS
91
91
  # Install dependencies
92
92
  npm install
93
93
 
94
- # Run one-command setup (generates wallets, vault ceremony, writes ~/.jellyos/.env)
94
+ # Run one-command setup (generates wallets, vault ceremony, writes ~/.jelly/.env)
95
95
  bash setup.sh # macOS / Linux
96
96
  # or
97
97
  powershell -ExecutionPolicy Bypass -File setup.ps1 # Windows
@@ -104,11 +104,11 @@ jellyos
104
104
 
105
105
  ## Configuration
106
106
 
107
- All config lives in `~/.jellyos/.env`. The setup wizard creates this for you, or create it manually:
107
+ All config lives in `~/.jelly/.env`. The setup wizard creates this for you, or create it manually:
108
108
 
109
109
  ```bash
110
- cp .env.example ~/.jellyos/.env
111
- nano ~/.jellyos/.env
110
+ cp .env.example ~/.jelly/.env
111
+ nano ~/.jelly/.env
112
112
  ```
113
113
 
114
114
  ### AI Model Provider (pick one)
@@ -362,11 +362,11 @@ jellyos setup # run the setup wizard
362
362
 
363
363
  ## Security
364
364
 
365
- - **Keys stay local** — API keys are read from `~/.jellyos/.env` at startup and never logged or transmitted beyond outbound API calls
365
+ - **Keys stay local** — API keys are read from `~/.jelly/.env` at startup and never logged or transmitted beyond outbound API calls
366
366
  - **Private keys never leave the process** — signing happens in memory; only the resulting signature is returned
367
367
  - **Vault encryption** — AES-256-GCM with a key derived from your passphrase using scrypt (memory-hard KDF) + random per-vault salt; the key itself is never persisted
368
368
  - **Auto-lock** — vault locks automatically on `/panic` and on process exit
369
- - **Wallet storage** — keypairs are written to `~/.jellyos/wallets/` which is in `.gitignore` and never included in any sync or backup by the agent
369
+ - **Wallet storage** — keypairs are written to `~/.jelly/wallets/` which is in `.gitignore` and never included in any sync or backup by the agent
370
370
 
371
371
  ---
372
372
 
package/README.npm.md ADDED
@@ -0,0 +1,212 @@
1
+ # @jellyos/agent
2
+
3
+ <div align="center">
4
+
5
+ <pre>
6
+ ██╗███████╗██╗ ██╗ ██╗ ██╗ ██████╗ ███████╗
7
+ ██║██╔════╝██║ ██║ ╚██╗ ██╔╝ ██╔═══██╗██╔════╝
8
+ ██║█████╗ ██║ ██║ ╚████╔╝ ██║ ██║███████╗
9
+ ██ ██║██╔══╝ ██║ ██║ ╚██╔╝ ██║ ██║╚════██║
10
+ ╚█████╔╝███████╗███████╗██║ ██║ ╚██████╔╝███████║
11
+ ╚════╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
12
+ </pre>
13
+
14
+ **Autonomous AI trading agent. Runs 100% locally. No server. No inbound ports.**
15
+
16
+ [![npm](https://img.shields.io/npm/v/@jellyos/agent?color=14b8a6&style=flat-square)](https://www.npmjs.com/package/@jellyos/agent)
17
+ [![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen?style=flat-square)](https://nodejs.org)
18
+ [![License: MIT](https://img.shields.io/badge/license-MIT-yellow?style=flat-square)](LICENSE)
19
+
20
+ </div>
21
+
22
+ ---
23
+
24
+ ## What's in this package
25
+
26
+ This NPM package contains the **core JellyOS agent engine**:
27
+
28
+ | Component | Description |
29
+ |-----------|-------------|
30
+ | `AgentRunner` | Multi-model agentic loop with tool dispatch, swarm routing, reflection |
31
+ | `ModelClient` | Streaming OpenAI-compatible client with fallback rotation + thinking mode |
32
+ | `ModelRegistry` | Dynamic model discovery, tier classification, cost tracking (356 models) |
33
+ | `SwarmRouter` | LLM-based task decomposition + parallel sub-agent execution |
34
+ | `SessionManager` | Conversation history with 3-tier smart compaction + turbo headroom tracking |
35
+ | `MemoryStore` | SQLite long-term memory (cross-session, persistent) |
36
+ | `GoalManager` | Persistent cross-session goals injected into every turn |
37
+ | `ContextStore` | Ephemeral task context folders (auto-deleted on completion) |
38
+ | `AgentScheduler` | Cron + price-trigger autonomous task scheduling |
39
+ | `MCPServer` | Model Context Protocol server (Claude Desktop / Cursor compatible) |
40
+ | **18 built-in tools** | Prices, candles+TA, news, Fear&Greed, funding rates, BTC mempool, DeFi TVL, Solana TPS, model management, goals, tasks, scheduling |
41
+ | Ink TUI | Terminal UI with live ticker, context pressure monitor, approval gates |
42
+
43
+ For wallets, vault, on-chain signing, and the full 28-tool trading suite → [JellyOS full project](https://github.com/jelly-chain/JellyOS)
44
+
45
+ ---
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ npm install -g @jellyos/agent
51
+ ```
52
+
53
+ ## Quick Start
54
+
55
+ ```bash
56
+ mkdir -p ~/.jelly
57
+ echo "OPENROUTER_API_KEY=sk-or-..." > ~/.jelly/.env
58
+ jellyos
59
+ ```
60
+
61
+ ## Headless Mode
62
+
63
+ ```bash
64
+ # Single turn, print to stdout, exit
65
+ jellyos --headless "what is the current ETH price and RSI on the 1h chart?"
66
+
67
+ # Use in scripts
68
+ RESULT=$(jellyos --headless "summarize BTC market conditions")
69
+ echo "$RESULT"
70
+ ```
71
+
72
+ ## MCP Server (Claude Desktop / Cursor)
73
+
74
+ ```bash
75
+ # Start MCP server — exposes all 18 tools to any MCP client
76
+ jellyos-mcp
77
+ ```
78
+
79
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "jellyos": {
84
+ "command": "jellyos-mcp"
85
+ }
86
+ }
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Configuration (`~/.jelly/.env`)
93
+
94
+ ```env
95
+ # AI Provider (pick one)
96
+ OPENROUTER_API_KEY=sk-or-... # recommended — 356 models
97
+ ANTHROPIC_API_KEY=sk-ant-... # direct Anthropic
98
+ OPENAI_API_KEY=sk-... # direct OpenAI
99
+ OPENAI_BASE_URL=http://localhost:11434/v1 # Ollama / local
100
+
101
+ # Optional model pool (up to 5, rotated on rate-limit)
102
+ JELLY_MODEL_1=anthropic/claude-opus-4.7
103
+ JELLY_MODEL_2=openai/gpt-5.5
104
+ JELLY_MODEL_3=google/gemini-3.5-flash
105
+ ```
106
+
107
+ ---
108
+
109
+ ## Built-in Tools
110
+
111
+ | Tool | Description | Source |
112
+ |------|-------------|--------|
113
+ | `get_prices` | Live prices + 24h change | Binance + CoinGecko |
114
+ | `get_candles` | OHLCV data + RSI/MACD/Bollinger analysis | Binance |
115
+ | `get_top_movers` | Largest 24h movers | Binance |
116
+ | `get_market_overview` | Aggregated market summary | Multi-source |
117
+ | `get_news` | Headlines + sentiment scoring | CoinDesk/CoinTelegraph/TheBlock |
118
+ | `get_fear_greed` | Fear & Greed Index (7-day history) | alternative.me |
119
+ | `get_funding_rates` | Perp funding rates (long/short bias) | Binance |
120
+ | `get_btc_mempool` | BTC pending txs + fee rates | mempool.space |
121
+ | `get_defi_tvl` | DeFi TVL by chain | DeFiLlama |
122
+ | `get_solana_stats` | Solana TPS + network health | Solana RPC |
123
+ | `analyze_ta` | RSI, MACD, Bollinger, EMA, ATR on price arrays | Local |
124
+ | `list_models` | Search 356 available AI models | OpenRouter |
125
+ | `pick_model` | Find cheapest model for requirements | OpenRouter |
126
+ | `set_goal` / `list_goals` / `complete_goal` | Persistent cross-session goals | Local |
127
+ | `schedule_task` / `list_schedule` | Cron + price-trigger scheduling | Local |
128
+ | `read_task_context` / `list_tasks` | Ephemeral task context folders | Local |
129
+ | `cost_report` | Session + lifetime token usage | Local |
130
+
131
+ All data tools are free — no API keys required.
132
+
133
+ ---
134
+
135
+ ## Effect Levels
136
+
137
+ ```
138
+ /effect eco # minimal tool calls, cheapest models
139
+ /effect normal # balanced (default)
140
+ /effect turbo # 2 parallel sub-agents for complex tasks
141
+ /effect max # 5 agents + thinking models for deep research
142
+ ```
143
+
144
+ ---
145
+
146
+ ## Extension API
147
+
148
+ ```typescript
149
+ import { Type } from "@jellyos/agent";
150
+ import type { ExtensionAPI } from "@jellyos/agent";
151
+
152
+ export default function (agent: ExtensionAPI) {
153
+ agent.setSystemPrompt("You are a DeFi yield optimizer.");
154
+
155
+ agent.registerTool({
156
+ name: "get_apy",
157
+ label: "Get APY",
158
+ description: "Fetch current APY for a DeFi protocol",
159
+ requiresApproval: false, // set true for money-moving tools
160
+ parameters: Type.Object({
161
+ protocol: Type.String({ description: "Protocol name e.g. aave" }),
162
+ }),
163
+ async execute(_id, { protocol }) {
164
+ const res = await fetch(`https://api.llama.fi/protocol/${protocol}`);
165
+ const data = await res.json() as Record<string, unknown>;
166
+ return {
167
+ content: [{ type: "text", text: `${protocol}: ${JSON.stringify(data)}` }],
168
+ details: {},
169
+ };
170
+ },
171
+ });
172
+
173
+ agent.on("session_start", async (ctx) => {
174
+ ctx.ui.setStatus("yields", "ready");
175
+ });
176
+ }
177
+ ```
178
+
179
+ ```bash
180
+ jellyos --extension ./my-extension.ts
181
+ ```
182
+
183
+ ---
184
+
185
+ ## REPL Commands
186
+
187
+ ```
188
+ /help List commands
189
+ /effect [level] eco | normal | turbo | max
190
+ /prices [symbols] Quick price check
191
+ /news Latest headlines + sentiment
192
+ /goals List active goals
193
+ /goal add <text> Add a persistent goal
194
+ /goal done <id> Mark goal complete
195
+ /schedule List scheduled tasks
196
+ /tasks List active context folders
197
+ /traces Show last 5 agent traces with timing
198
+ /memory <query> Search long-term memory
199
+ /models [query] Search available AI models
200
+ /cost Session + lifetime cost report
201
+ /approve | /deny Respond to tool approval gates
202
+ /palette Full command + tool list
203
+ /clear Clear conversation history
204
+ Escape Abort in-flight model stream
205
+ Ctrl-C Exit
206
+ ```
207
+
208
+ ---
209
+
210
+ ## License
211
+
212
+ MIT
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * jellyos-mcp — JellyOS MCP server entry point.
4
+ * Exposes all JellyOS tools via the Model Context Protocol (stdio transport).
5
+ * Compatible with Claude Desktop, Cursor, Continue, and any MCP client.
6
+ */
7
+ import { createRequire } from "module";
8
+ import { fileURLToPath } from "url";
9
+ import { dirname, join } from "path";
10
+ import { existsSync } from "fs";
11
+
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const require = createRequire(import.meta.url);
14
+
15
+ const distEntry = join(__dirname, "..", "dist", "mcp", "entry.js");
16
+ const srcEntry = join(__dirname, "..", "src", "mcp", "entry.ts");
17
+
18
+ if (existsSync(distEntry)) {
19
+ await import(distEntry);
20
+ } else if (existsSync(srcEntry)) {
21
+ const { register } = await import("tsx/esm");
22
+ await import(srcEntry);
23
+ } else {
24
+ process.stderr.write("JellyOS MCP: run 'npm run build' first\n");
25
+ process.exit(1);
26
+ }
@@ -24,6 +24,12 @@ export interface ToolDef<P extends TSchema = TSchema> {
24
24
  label: string;
25
25
  description: string;
26
26
  parameters: P;
27
+ /**
28
+ * #10: If true, the agent pauses before executing this tool and asks the
29
+ * user for confirmation. Use for any tool that moves money or signs txs.
30
+ * The REPL renders an [APPROVE] prompt — user types y/n within 60 seconds.
31
+ */
32
+ requiresApproval?: boolean;
27
33
  execute(id: string, params: Static<P>): Promise<ToolContent>;
28
34
  }
29
35
  export interface TuiHeader {
@@ -83,7 +83,9 @@ export class Registry {
83
83
  await h(undefined, ctx); // (_event, ctx) => {...} — Pi convention
84
84
  }
85
85
  }
86
- catch { /* hooks must not crash the session */ }
86
+ catch (e) {
87
+ console.error(`[Registry] hook "${event}" threw:`, e);
88
+ }
87
89
  }
88
90
  }
89
91
  // ── OpenAI tool schema ───────────────────────────────────────────────────
package/dist/cli.js CHANGED
@@ -12,6 +12,11 @@ import { Registry } from "./api/Registry.js";
12
12
  import { loadExtension } from "./loader.js";
13
13
  import { App } from "./tui/App.js";
14
14
  import { T } from "./tui/theme.js";
15
+ import { modelRegistry } from "./models/ModelRegistry.js";
16
+ import { CostTracker } from "./models/CostTracker.js";
17
+ import { AgentRunner } from "./runner/AgentRunner.js";
18
+ import { SessionManager } from "./session/SessionManager.js";
19
+ import { makeTheme } from "./tui/theme.js";
15
20
  // ── Load env vars from ~/.jelly/.env ─────────────────────────────────────────
16
21
  const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
17
22
  const envPath = join(JELLY_HOME, ".env");
@@ -33,7 +38,7 @@ if (subcmd === "config") {
33
38
  const m = line.match(/^([A-Z_]+)=(.*)$/);
34
39
  if (!m)
35
40
  continue;
36
- const masked = m[2].length > 8 ? m[2].slice(0, 4) + "****" + m[2].slice(-4) : "****";
41
+ const masked = m[2].length > 12 ? m[2].slice(0, 6) + "********" : "********";
37
42
  console.log(` ${m[1].padEnd(28)} ${masked}`);
38
43
  }
39
44
  }
@@ -81,10 +86,72 @@ function loadContext() {
81
86
  return { effectLevel: "normal", chain: "ethereum" };
82
87
  }
83
88
  }
84
- // ── Boot ──────────────────────────────────────────────────────────────────────
85
- (async () => {
86
- console.clear();
87
- console.log(T.accent(`
89
+ // ── Headless mode (#26) ─────────────────────────────────────────────────────
90
+ const headlessIdx = args.indexOf("--headless");
91
+ const headlessMsg = headlessIdx >= 0 ? args[headlessIdx + 1] : null;
92
+ if (headlessMsg) {
93
+ (async () => {
94
+ if (existsSync(envPath))
95
+ loadDotenv({ path: envPath, override: false });
96
+ const registry = new Registry();
97
+ if (extensionPath) {
98
+ try {
99
+ await loadExtension(extensionPath, registry);
100
+ }
101
+ catch (e) {
102
+ const msg = e instanceof Error ? e.message : String(e);
103
+ process.stderr.write(`Extension load failed: ${msg}\n`);
104
+ process.exit(1);
105
+ }
106
+ }
107
+ await modelRegistry.initialise();
108
+ const session = new SessionManager();
109
+ const prompt = systemPrompt || registry.getSystemPrompt() || "You are JellyOS, an autonomous AI trading agent.";
110
+ session.setSystemPrompt(prompt);
111
+ const theme = makeTheme();
112
+ const nullUi = {
113
+ notify: () => { },
114
+ setStatus: () => { },
115
+ setTheme: () => { },
116
+ setHeader: () => { },
117
+ theme,
118
+ };
119
+ const sessionCtx = {
120
+ ui: nullUi,
121
+ hasUI: false,
122
+ config: { OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY },
123
+ };
124
+ // Fire session_start hooks
125
+ await registry.fireHook("session_start", sessionCtx);
126
+ session.setSystemPrompt(registry.getSystemPrompt() || prompt);
127
+ let exitCode = 0;
128
+ const runner = new AgentRunner(registry, session, (event) => {
129
+ if (event.type === "text_delta")
130
+ process.stdout.write(event.text);
131
+ if (event.type === "turn_done")
132
+ process.stdout.write("\n");
133
+ if (event.type === "error") {
134
+ process.stderr.write(`\nError: ${event.message}\n`);
135
+ exitCode = 1;
136
+ }
137
+ }, sessionCtx, "normal", modelRegistry);
138
+ try {
139
+ await runner.run(headlessMsg);
140
+ }
141
+ catch (e) {
142
+ const msg = e instanceof Error ? e.message : String(e);
143
+ process.stderr.write(`Runner error: ${msg}\n`);
144
+ exitCode = 1;
145
+ }
146
+ await registry.fireHook("session_end", sessionCtx);
147
+ process.exit(exitCode);
148
+ })();
149
+ }
150
+ else {
151
+ // ── Boot (interactive TUI) ────────────────────────────────────────────────────
152
+ (async () => {
153
+ console.clear();
154
+ console.log(T.accent(`
88
155
  ██╗███████╗██╗ ██╗ ██╗ ██╗ ██████╗ ███████╗
89
156
  ██║██╔════╝██║ ██║ ╚██╗ ██╔╝ ██╔═══██╗██╔════╝
90
157
  ██║█████╗ ██║ ██║ ╚████╔╝ ██║ ██║███████╗
@@ -92,43 +159,51 @@ function loadContext() {
92
159
  ╚█████╔╝███████╗███████╗██║ ██║ ╚██████╔╝███████║
93
160
  ╚════╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══════╝
94
161
  `));
95
- console.log(T.muted(" Standalone AI trading agent — all local, zero exposure\n"));
96
- const registry = new Registry();
97
- const { effectLevel, chain } = loadContext();
98
- // These callbacks are forwarded into the extension API so ui.setStatus
99
- // and ui.notify work even during the session_start hook (before Ink mounts).
100
- let _notifyFn = null;
101
- let _setStatusFn = null;
102
- if (extensionPath) {
103
- try {
104
- console.log(T.muted(` Loading: ${extensionPath}`));
105
- await loadExtension(extensionPath, registry, {
106
- onNotify: (msg) => { _notifyFn?.(msg); },
107
- onStatusUpdate: (k, v) => { _setStatusFn?.(k, v); },
108
- });
109
- console.log(T.success(` ✓ ${registry.listTools().length} tools · ${registry.listCommands().length} commands`));
162
+ console.log(T.muted(" Standalone AI trading agent — all local, zero exposure\n"));
163
+ const registry = new Registry();
164
+ const { effectLevel, chain } = loadContext();
165
+ // These callbacks are forwarded into the extension API so ui.setStatus
166
+ // and ui.notify work even during the session_start hook (before Ink mounts).
167
+ let _notifyFn = null;
168
+ let _setStatusFn = null;
169
+ if (extensionPath) {
170
+ try {
171
+ console.log(T.muted(` Loading: ${extensionPath}`));
172
+ await loadExtension(extensionPath, registry, {
173
+ onNotify: (msg) => { _notifyFn?.(msg); },
174
+ onStatusUpdate: (k, v) => { _setStatusFn?.(k, v); },
175
+ });
176
+ console.log(T.success(` ✓ ${registry.listTools().length} tools · ${registry.listCommands().length} commands`));
177
+ }
178
+ catch (e) {
179
+ console.error(T.error(` ✗ Extension load failed: ${e.message}`));
180
+ process.exit(1);
181
+ }
110
182
  }
111
- catch (e) {
112
- console.error(T.error(` Extension load failed: ${e.message}`));
113
- process.exit(1);
183
+ else {
184
+ console.log(T.warn(" No extension found base agent only."));
185
+ console.log(T.muted(" Run from jellyos project root or pass --extension path\n"));
114
186
  }
115
- }
116
- else {
117
- console.log(T.warn(" No extension found — base agent only."));
118
- console.log(T.muted(" Run from jellyos project root or pass --extension path\n"));
119
- }
120
- if (!process.env.OPENROUTER_API_KEY && !process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) {
121
- console.log(T.warn(" No API key found. Set OPENROUTER_API_KEY in ~/.jelly/.env\n"));
122
- }
123
- await new Promise(r => setTimeout(r, 500));
124
- console.clear();
125
- render(React.createElement(App, {
126
- registry,
127
- systemPrompt,
128
- effectLevel,
129
- chain,
130
- onNotifyReady: (fn) => { _notifyFn = fn; },
131
- onStatusReady: (fn) => { _setStatusFn = fn; },
132
- }), { exitOnCtrlC: false });
133
- })();
187
+ if (!process.env.OPENROUTER_API_KEY && !process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) {
188
+ console.log(T.warn(" No API key found. Set OPENROUTER_API_KEY in ~/.jelly/.env\n"));
189
+ }
190
+ // ── Initialise model registry & cost tracker ─────────────────────────────
191
+ const costTracker = new CostTracker(modelRegistry);
192
+ console.log(T.muted(" Discovering available models via OpenRouter…"));
193
+ await modelRegistry.initialise();
194
+ console.log(T.success(` ✓ ${modelRegistry.modelCount} models available \n`));
195
+ await new Promise(r => setTimeout(r, 500));
196
+ console.clear();
197
+ render(React.createElement(App, {
198
+ registry,
199
+ systemPrompt,
200
+ effectLevel,
201
+ chain,
202
+ modelReg: modelRegistry,
203
+ costTracker,
204
+ onNotifyReady: (fn) => { _notifyFn = fn; },
205
+ onStatusReady: (fn) => { _setStatusFn = fn; },
206
+ }), { exitOnCtrlC: false });
207
+ })();
208
+ } // end headless else
134
209
  //# sourceMappingURL=cli.js.map
package/dist/index.d.ts CHANGED
@@ -12,7 +12,30 @@ export { Registry } from "./api/Registry.js";
12
12
  export { AgentRunner } from "./runner/AgentRunner.js";
13
13
  export { ModelClient, resolveModelConfig } from "./runner/ModelClient.js";
14
14
  export { ToolDispatcher } from "./runner/ToolDispatcher.js";
15
- export { SessionManager } from "./session/SessionManager.js";
16
15
  export { loadExtension } from "./loader.js";
17
16
  export { makeTheme, T, JELLY_COLORS } from "./tui/theme.js";
17
+ export { ModelRegistry, modelRegistry, classifyModel } from "./models/ModelRegistry.js";
18
+ export { CostTracker } from "./models/CostTracker.js";
19
+ export type { OpenRouterModel, TieredModel, TieredPool, ModelTier } from "./models/ModelRegistry.js";
20
+ export type { UsageEntry, SessionUsage, LifetimeUsage } from "./models/CostTracker.js";
21
+ export { fullAnalysis, rsi, macd, ema, sma, bollingerBands, atr, getCandlesTool, getCandlesParams } from "./tools/TechnicalAnalysis.js";
22
+ export { PriceFeed, priceFeed, getPricesTool, topMoversTool, marketOverviewTool } from "./tools/PriceFeed.js";
23
+ export { NewsFeed, newsFeed, getNewsTool, scoreSentiment } from "./tools/NewsSentiment.js";
24
+ export { getFearGreedTool, fundingRatesParams, getFundingRatesTool, getBtcMempoolTool, getDefiTvlTool, getSolanaStatsTool, } from "./tools/MarketSentiment.js";
25
+ export type { OHLCV, AnalysisResult } from "./tools/TechnicalAnalysis.js";
26
+ export type { PriceTick } from "./tools/PriceFeed.js";
27
+ export type { NewsItem, SentimentReport } from "./tools/NewsSentiment.js";
28
+ export { SessionManager } from "./session/SessionManager.js";
29
+ export { MemoryStore, memoryStore } from "./session/MemoryStore.js";
30
+ export { GoalManager, goalManager } from "./session/GoalManager.js";
31
+ export { ContextStore, contextStore } from "./session/ContextStore.js";
32
+ export type { MemoryEntry, RecentSession } from "./session/MemoryStore.js";
33
+ export type { Goal } from "./session/GoalManager.js";
34
+ export type { TaskContext } from "./session/ContextStore.js";
35
+ export type { ContextPressure } from "./session/SessionManager.js";
36
+ export { MCPServer } from "./mcp/server.js";
37
+ export { AgentScheduler, agentScheduler } from "./scheduler/AgentScheduler.js";
38
+ export type { ScheduledTask, PriceTrigger } from "./scheduler/AgentScheduler.js";
39
+ export { Tracer } from "./telemetry/Tracer.js";
40
+ export type { Span, Trace } from "./telemetry/Tracer.js";
18
41
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -15,10 +15,27 @@ export { Registry } from "./api/Registry.js";
15
15
  export { AgentRunner } from "./runner/AgentRunner.js";
16
16
  export { ModelClient, resolveModelConfig } from "./runner/ModelClient.js";
17
17
  export { ToolDispatcher } from "./runner/ToolDispatcher.js";
18
- // Session
19
- export { SessionManager } from "./session/SessionManager.js";
20
18
  // Loader (for embedding the agent in other tools)
21
19
  export { loadExtension } from "./loader.js";
22
20
  // Theme
23
21
  export { makeTheme, T, JELLY_COLORS } from "./tui/theme.js";
22
+ // Model intelligence
23
+ export { ModelRegistry, modelRegistry, classifyModel } from "./models/ModelRegistry.js";
24
+ export { CostTracker } from "./models/CostTracker.js";
25
+ // Tools
26
+ export { fullAnalysis, rsi, macd, ema, sma, bollingerBands, atr, getCandlesTool, getCandlesParams } from "./tools/TechnicalAnalysis.js";
27
+ export { PriceFeed, priceFeed, getPricesTool, topMoversTool, marketOverviewTool } from "./tools/PriceFeed.js";
28
+ export { NewsFeed, newsFeed, getNewsTool, scoreSentiment } from "./tools/NewsSentiment.js";
29
+ export { getFearGreedTool, fundingRatesParams, getFundingRatesTool, getBtcMempoolTool, getDefiTvlTool, getSolanaStatsTool, } from "./tools/MarketSentiment.js";
30
+ // Session / Memory / Goals / Context
31
+ export { SessionManager } from "./session/SessionManager.js";
32
+ export { MemoryStore, memoryStore } from "./session/MemoryStore.js";
33
+ export { GoalManager, goalManager } from "./session/GoalManager.js";
34
+ export { ContextStore, contextStore } from "./session/ContextStore.js";
35
+ // MCP server
36
+ export { MCPServer } from "./mcp/server.js";
37
+ // Scheduler
38
+ export { AgentScheduler, agentScheduler } from "./scheduler/AgentScheduler.js";
39
+ // Telemetry
40
+ export { Tracer } from "./telemetry/Tracer.js";
24
41
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1,71 @@
1
+ /**
2
+ * MCP server entry — bootstraps the Registry with built-in tools
3
+ * and starts the MCP stdio server.
4
+ */
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+ import { existsSync } from "node:fs";
8
+ import { config as loadDotenv } from "dotenv";
9
+ import { Registry } from "../api/Registry.js";
10
+ import { loadExtension } from "../loader.js";
11
+ import { MCPServer } from "./server.js";
12
+ import { modelRegistry } from "../models/ModelRegistry.js";
13
+ import { getPricesTool, topMoversTool, marketOverviewTool, getPricesParams, topMoversParams, marketOverviewParams, priceFeed, } from "../tools/PriceFeed.js";
14
+ import { getNewsTool, getNewsParams, newsFeed } from "../tools/NewsSentiment.js";
15
+ import { getCandlesParams, getCandlesTool, analyzeTAParams, fullAnalysis } from "../tools/TechnicalAnalysis.js";
16
+ import { getFearGreedTool, fearGreedParams, getFundingRatesTool, fundingRatesParams, getBtcMempoolTool, btcMempoolParams, getDefiTvlTool, defiTvlParams, getSolanaStatsTool, solanaStatsParams, } from "../tools/MarketSentiment.js";
17
+ const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
18
+ const envPath = join(JELLY_HOME, ".env");
19
+ if (existsSync(envPath))
20
+ loadDotenv({ path: envPath, override: false });
21
+ const registry = new Registry();
22
+ // Load optional extension from --extension arg
23
+ const extIdx = process.argv.indexOf("--extension");
24
+ const extPath = extIdx >= 0 ? process.argv[extIdx + 1] : null;
25
+ if (extPath && existsSync(extPath)) {
26
+ try {
27
+ await loadExtension(extPath, registry);
28
+ }
29
+ catch (e) {
30
+ process.stderr.write(`[MCP] Extension load failed: ${e}\n`);
31
+ }
32
+ }
33
+ // Register all built-in tools
34
+ await modelRegistry.initialise();
35
+ const mk = modelRegistry;
36
+ registry.addTool({ name: "list_models", label: "List Models", description: "Search available AI models.", parameters: mk["listModelsParams"], execute: (id, p) => mk["listModelsTool"](id, p) });
37
+ registry.addTool({ name: "get_prices", label: "Get Prices", description: "Get live crypto prices.", parameters: getPricesParams, execute: (id, p) => getPricesTool(id, p) });
38
+ registry.addTool({ name: "get_top_movers", label: "Top Movers", description: "Top 24h price movers.", parameters: topMoversParams, execute: (id, p) => topMoversTool(id, p) });
39
+ registry.addTool({ name: "market_overview", label: "Market Overview", description: "Aggregated market data.", parameters: marketOverviewParams, execute: () => marketOverviewTool() });
40
+ registry.addTool({ name: "get_news", label: "Get News", description: "Crypto news + sentiment.", parameters: getNewsParams, execute: (id, p) => getNewsTool(id, p) });
41
+ registry.addTool({ name: "get_candles", label: "Get Candles", description: "OHLCV + TA analysis from Binance.", parameters: getCandlesParams, execute: (id, p) => getCandlesTool(id, p) });
42
+ registry.addTool({ name: "get_fear_greed", label: "Fear & Greed", description: "Crypto fear & greed index.", parameters: fearGreedParams, execute: (id, p) => getFearGreedTool(id, p) });
43
+ registry.addTool({ name: "get_funding_rates", label: "Funding Rates", description: "Perp funding rates.", parameters: fundingRatesParams, execute: (id, p) => getFundingRatesTool(id, p) });
44
+ registry.addTool({ name: "get_btc_mempool", label: "BTC Mempool", description: "BTC mempool + fees.", parameters: btcMempoolParams, execute: () => getBtcMempoolTool() });
45
+ registry.addTool({ name: "get_defi_tvl", label: "DeFi TVL", description: "DeFiLlama TVL.", parameters: defiTvlParams, execute: (id, p) => getDefiTvlTool(id, p) });
46
+ registry.addTool({ name: "get_solana_stats", label: "Solana Stats", description: "Solana TPS + health.", parameters: solanaStatsParams, execute: () => getSolanaStatsTool() });
47
+ registry.addTool({
48
+ name: "analyze_ta", label: "Technical Analysis", description: "RSI, MACD, Bollinger on price arrays.",
49
+ parameters: analyzeTAParams,
50
+ execute: async (_id, p) => {
51
+ const params = p;
52
+ const closes = params.prices;
53
+ const candles = closes.map((c, i) => ({
54
+ timestamp: i, open: c, high: (params.highs?.[i] ?? c), low: (params.lows?.[i] ?? c), close: c, volume: (params.volumes?.[i] ?? 0),
55
+ }));
56
+ const results = fullAnalysis(candles);
57
+ const text = results.map(r => {
58
+ const s = r.signal === "bullish" ? "🟢" : r.signal === "bearish" ? "🔴" : "⚪";
59
+ return `${s} ${r.indicator}: ${typeof r.value === "number" ? r.value.toFixed(2) : String(r.value)}`;
60
+ }).join("\n");
61
+ return { content: [{ type: "text", text: `Technical Analysis:\n${text}` }], details: {} };
62
+ },
63
+ });
64
+ // Start price + news feeds
65
+ priceFeed.track("btc", "eth", "sol", "bnb", "matic", "arb", "op", "avax");
66
+ priceFeed.start();
67
+ newsFeed.start();
68
+ // Start MCP server
69
+ const server = new MCPServer(registry);
70
+ await server.run();
71
+ //# sourceMappingURL=entry.js.map