@jellyos/agent 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tui/App.js +53 -2
- package/dist/tui/REPL.js +1 -1
- package/dist/tui/StatusBar.js +17 -1
- package/package.json +1 -1
package/dist/tui/App.js
CHANGED
|
@@ -96,6 +96,10 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
|
|
|
96
96
|
const [ticker, setTicker] = useState("");
|
|
97
97
|
const [costBadge, setCostBadge] = useState("");
|
|
98
98
|
const [newsBadge, setNewsBadge] = useState("");
|
|
99
|
+
// ── Sidebar live data state ─────────────────────────────────────────────
|
|
100
|
+
const [sidebarTickers, setSidebarTickers] = useState([]);
|
|
101
|
+
const [sidebarNews, setSidebarNews] = useState([]);
|
|
102
|
+
const [rotationSlots, setRotationSlots] = useState([null, null, null, null, null]);
|
|
99
103
|
// ── Model selector overlay state ──────────────────────────────────────
|
|
100
104
|
const [showModelSelector, setShowModelSelector] = useState(false);
|
|
101
105
|
const [modelSelectorInitialQuery, setModelSelectorInitialQuery] = useState("");
|
|
@@ -210,7 +214,28 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
|
|
|
210
214
|
if (costTracker)
|
|
211
215
|
setCostBadge(costTracker.statusLine());
|
|
212
216
|
setNewsBadge(newsFeed.statusBadge());
|
|
213
|
-
|
|
217
|
+
// Update sidebar live data
|
|
218
|
+
const allTicks = priceFeed.getAll();
|
|
219
|
+
setSidebarTickers(allTicks.slice(0, 8).map(t => ({ symbol: t.symbol, price: t.price, changePct: t.change24h })));
|
|
220
|
+
const latestNews = newsFeed.getLatest();
|
|
221
|
+
if (latestNews?.items) {
|
|
222
|
+
setSidebarNews(latestNews.items.slice(0, 6).map(item => ({ title: item.title ?? item.source ?? "News", sentiment: item.sentiment ?? 0, source: item.source ?? "" })));
|
|
223
|
+
}
|
|
224
|
+
// Read rotation slots from context.json
|
|
225
|
+
try {
|
|
226
|
+
const { existsSync: exists, readFileSync: read } = require("node:fs");
|
|
227
|
+
const { join } = require("node:path");
|
|
228
|
+
const { homedir } = require("node:os");
|
|
229
|
+
const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
|
|
230
|
+
const ctxPath = join(JELLY_HOME, "context.json");
|
|
231
|
+
if (exists(ctxPath)) {
|
|
232
|
+
const store = JSON.parse(read(ctxPath, "utf-8"));
|
|
233
|
+
if (store.rotationSlots)
|
|
234
|
+
setRotationSlots(store.rotationSlots);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch { /* non-fatal */ }
|
|
238
|
+
}, 3_000);
|
|
214
239
|
const saveInterval = setInterval(() => { costTracker?.saveLifetime(); }, 60_000);
|
|
215
240
|
const session = new SessionManager();
|
|
216
241
|
session.setSystemPrompt(registry.getSystemPrompt() || systemPrompt || "You are JellyOS, an autonomous AI trading agent.");
|
|
@@ -284,6 +309,13 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
|
|
|
284
309
|
if (costTracker)
|
|
285
310
|
setCostBadge(costTracker.statusLine());
|
|
286
311
|
setNewsBadge(newsFeed.statusBadge());
|
|
312
|
+
// Initial sidebar data fetch (before interval fires)
|
|
313
|
+
const initialTicks = priceFeed.getAll();
|
|
314
|
+
setSidebarTickers(initialTicks.slice(0, 8).map(t => ({ symbol: t.symbol, price: t.price, changePct: t.change24h })));
|
|
315
|
+
const initialNews = newsFeed.getLatest();
|
|
316
|
+
if (initialNews?.items) {
|
|
317
|
+
setSidebarNews(initialNews.items.slice(0, 6).map(item => ({ title: item.title ?? item.source ?? "News", sentiment: item.sentiment ?? 0, source: item.source ?? "" })));
|
|
318
|
+
}
|
|
287
319
|
return () => {
|
|
288
320
|
if (sessionCtxRef.current)
|
|
289
321
|
registry.fireHook("session_end", sessionCtxRef.current).catch(() => { });
|
|
@@ -492,6 +524,11 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
|
|
|
492
524
|
const ctxPath = join(JELLY_HOME, "context.json");
|
|
493
525
|
const store = existsSync(ctxPath) ? JSON.parse(readFileSync(ctxPath, "utf-8")) : {};
|
|
494
526
|
store.model = modelId;
|
|
527
|
+
// Also save as rotation slot 1 (primary)
|
|
528
|
+
const tier = modelReg?.getTier?.(modelId) ?? "worker";
|
|
529
|
+
const slots = store.rotationSlots ?? [null, null, null, null, null];
|
|
530
|
+
slots[0] = { id: modelId, tier };
|
|
531
|
+
store.rotationSlots = slots;
|
|
495
532
|
writeFileSync(ctxPath, JSON.stringify(store, null, 2), "utf-8");
|
|
496
533
|
}
|
|
497
534
|
catch { /* non-fatal */ }
|
|
@@ -517,12 +554,26 @@ export function App({ registry, systemPrompt, effectLevel: initialEffect = "norm
|
|
|
517
554
|
}, [modelReg]);
|
|
518
555
|
const ctx = getContextBar(sessionRef.current);
|
|
519
556
|
const statusLine = [ticker, costBadge, newsBadge, ...Object.values(statusBadges)].filter(Boolean).join(" ") || null;
|
|
557
|
+
// ── Sidebar helper functions ───────────────────────────────────────────────
|
|
558
|
+
const changeColor = (pct) => pct > 0 ? JELLY_COLORS.success : pct < 0 ? JELLY_COLORS.error : JELLY_COLORS.muted;
|
|
559
|
+
const changeArrow = (pct) => pct > 0 ? "▲" : pct < 0 ? "▼" : "─";
|
|
560
|
+
const SIDEBAR_W = 42;
|
|
520
561
|
// ── Overlay: model selector ────────────────────────────────────────────
|
|
521
562
|
if (showModelSelector) {
|
|
522
563
|
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(StatusBar, { model: modelName, chain: chain, vaultLocked: vaultLocked, effectLevel: effectLevel, toolRunning: toolRunning, connected: true, statusLine: statusLine }), _jsx(ModelSelector, { models: modelList, currentModelId: process.env.DEFAULT_MODEL ?? "", onSelect: handleModelSelect, onCancel: handleModelCancel, initialQuery: modelSelectorInitialQuery })] }));
|
|
523
564
|
}
|
|
524
565
|
// ── Multi-pane layout ────────────────────────────────────────────────────
|
|
525
|
-
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(StatusBar, { model: modelName, chain: chain, vaultLocked: vaultLocked, effectLevel: effectLevel, toolRunning: toolRunning, connected: true, statusLine: statusLine }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [_jsxs(Box, { flexDirection: "column", width:
|
|
566
|
+
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(StatusBar, { model: modelName, chain: chain, vaultLocked: vaultLocked, effectLevel: effectLevel, toolRunning: toolRunning, connected: true, statusLine: statusLine }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, overflow: "hidden", children: [_jsxs(Box, { flexDirection: "column", width: SIDEBAR_W, flexShrink: 0, children: [_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: JELLY_COLORS.dim, paddingX: 1, children: [_jsxs(Text, { bold: true, children: ["\uD83D\uDCE1 Ticker", rotationSlots.filter(s => s && s.id).length > 0 && (_jsxs(Text, { color: "#6b7280", children: [" \u21BB", rotationSlots.filter(s => s && s.id).length] }))] }), sidebarTickers.length > 0 ? sidebarTickers.map((t, i) => {
|
|
567
|
+
const arrow = changeArrow(t.changePct);
|
|
568
|
+
const col = changeColor(t.changePct);
|
|
569
|
+
const pctStr = (t.changePct > 0 ? "+" : "") + t.changePct.toFixed(1) + "%";
|
|
570
|
+
return _jsxs(Text, { color: col, children: [t.symbol.padEnd(8), "$", String(t.price).padStart(9), " ", arrow, pctStr] }, i);
|
|
571
|
+
}) : _jsx(Text, { color: JELLY_COLORS.muted, children: "Loading prices\u2026" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: JELLY_COLORS.dim, paddingX: 1, marginTop: 1, children: [_jsx(Text, { bold: true, children: "Context" }), _jsxs(Text, { color: ctx.color, children: [ctx.bar, " ", ctx.pct, "%"] }), ctx.turboReady ? null : _jsx(Text, { color: JELLY_COLORS.warn, children: "\u26A0 no turbo" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: JELLY_COLORS.dim, paddingX: 1, marginTop: 1, children: [_jsx(Text, { bold: true, children: "Effect" }), _jsx(Text, { color: effectLevel === "eco" ? "#22c55e" : effectLevel === "turbo" ? "#f59e0b" : effectLevel === "max" ? "#ef4444" : JELLY_COLORS.accent, children: effectLevel.toUpperCase() })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: JELLY_COLORS.dim, paddingX: 1, marginTop: 1, children: [_jsx(Text, { bold: true, children: "News" }), sidebarNews.length > 0 ? sidebarNews.map((n, i) => {
|
|
572
|
+
const sentColor = n.sentiment > 0.3 ? JELLY_COLORS.success : n.sentiment < -0.3 ? JELLY_COLORS.error : JELLY_COLORS.muted;
|
|
573
|
+
const sentPct = Math.round((n.sentiment + 1) * 50);
|
|
574
|
+
const title = n.title.length > 28 ? n.title.slice(0, 26) + "…" : n.title;
|
|
575
|
+
return (_jsxs(Box, { flexDirection: "row", justifyContent: "space-between", children: [_jsx(Text, { color: JELLY_COLORS.muted, children: title }), _jsxs(Text, { color: sentColor, children: [sentPct, "%"] })] }, i));
|
|
576
|
+
}) : _jsx(Text, { color: JELLY_COLORS.muted, children: "Loading news\u2026" })] }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: JELLY_COLORS.dim, paddingX: 1, marginTop: 1, children: [_jsx(Text, { bold: true, children: "Feeds" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[coingecko] SOLANA\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[coingecko] ETHEREUM\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[etherscan] BTC Price\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[etherscan] ETF Gas\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[binance] XRPUSDT 24h\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[binance] AVAXUSDT 24h\u2026" }), _jsx(Text, { color: JELLY_COLORS.muted, children: "[binance] SOLUSDT 24h\u2026" })] })] }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: _jsx(REPL, { messages: messages, streamingText: streaming, toolRunning: toolRunning, onSubmit: handleSubmit, disabled: disabled, onAbort: () => {
|
|
526
577
|
runnerRef.current?.abort();
|
|
527
578
|
setDisabled(false);
|
|
528
579
|
setToolRunning(null);
|
package/dist/tui/REPL.js
CHANGED
|
@@ -46,6 +46,6 @@ export function REPL({ messages, streamingText, toolRunning, onSubmit, onAbort,
|
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
const visible = messages.slice(-MAX_VISIBLE);
|
|
49
|
-
return (_jsxs(Box, { flexDirection: "column", width: termWidth, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [visible.map(m => _jsx(MessageLine, { msg: m }, m.id)), streamingText && (_jsxs(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: [_jsx(Text, { color: JELLY_COLORS.muted, children: " " }), _jsx(Text, { color: JELLY_COLORS.header, bold: true, children: "\uD83E\uDEBC " }), _jsx(Text, { wrap: "wrap", children: streamingText })] })), toolRunning && (_jsx(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: _jsxs(Text, { color: JELLY_COLORS.warn, children: ["\u2699 running ", toolRunning, "\u2026"] }) }))] }), _jsxs(Box, { borderStyle: "round", borderColor: disabled ? JELLY_COLORS.dim : JELLY_COLORS.accent, paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: JELLY_COLORS.accent, children: "\u203A " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleSubmit, placeholder: disabled ? "thinking…" : "message or /command" })] })
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "column", width: termWidth, children: [_jsxs(Box, { flexDirection: "column", flexGrow: 1, children: [visible.map(m => _jsx(MessageLine, { msg: m }, m.id)), streamingText && (_jsxs(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: [_jsx(Text, { color: JELLY_COLORS.muted, children: " " }), _jsx(Text, { color: JELLY_COLORS.header, bold: true, children: "\uD83E\uDEBC " }), _jsx(Text, { wrap: "wrap", children: streamingText })] })), toolRunning && (_jsx(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: _jsxs(Text, { color: JELLY_COLORS.warn, children: ["\u2699 running ", toolRunning, "\u2026"] }) }))] }), _jsxs(Box, { borderStyle: "round", borderColor: disabled ? JELLY_COLORS.dim : JELLY_COLORS.accent, paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: JELLY_COLORS.accent, children: "\u203A " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleSubmit, placeholder: disabled ? "thinking…" : "message or /command" })] })] }));
|
|
50
50
|
}
|
|
51
51
|
//# sourceMappingURL=REPL.js.map
|
package/dist/tui/StatusBar.js
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { JELLY_COLORS } from "./theme.js";
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { homedir } from "node:os";
|
|
4
7
|
export function StatusBar({ model, chain, vaultLocked, effectLevel, toolRunning, connected, statusLine, }) {
|
|
5
8
|
const vaultIcon = vaultLocked ? "🔒" : "🔓";
|
|
6
9
|
const chainShort = chain.slice(0, 8);
|
|
7
10
|
const modelShort = model.split("/").pop()?.slice(0, 18) ?? model.slice(0, 18);
|
|
8
11
|
const effectIcon = { eco: "🌿", normal: "⚡", turbo: "🚀", max: "🌊" }[effectLevel] ?? "⚡";
|
|
9
|
-
|
|
12
|
+
// Read rotation slot count for display
|
|
13
|
+
let rotationCount = 0;
|
|
14
|
+
try {
|
|
15
|
+
const JELLY_HOME = process.env.JELLYOS_HOME ?? join(homedir(), ".jelly");
|
|
16
|
+
const ctxPath = join(JELLY_HOME, "context.json");
|
|
17
|
+
if (existsSync(ctxPath)) {
|
|
18
|
+
const store = JSON.parse(readFileSync(ctxPath, "utf-8"));
|
|
19
|
+
const slots = store.rotationSlots ?? [];
|
|
20
|
+
rotationCount = slots.filter((s) => s && s.id).length;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch { /* non-fatal */ }
|
|
24
|
+
const rotationBadge = rotationCount > 0 ? `↻${rotationCount}` : null;
|
|
25
|
+
return (_jsxs(Box, { borderStyle: "single", borderColor: JELLY_COLORS.dim, paddingX: 1, flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: JELLY_COLORS.accent, bold: true, children: "\uD83E\uDEBC JellyOS" }), _jsx(Text, { color: JELLY_COLORS.muted, children: modelShort }), rotationBadge ? _jsx(Text, { color: "#6b7280", children: rotationBadge }) : null] }), _jsx(Box, { children: toolRunning
|
|
10
26
|
? _jsxs(Text, { color: JELLY_COLORS.warn, children: ["\u2699 ", toolRunning] })
|
|
11
27
|
: statusLine
|
|
12
28
|
? _jsx(Text, { color: JELLY_COLORS.muted, children: statusLine.slice(0, 80) })
|