@aiaiaichain/agent 0.1.2 → 0.1.4

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/REPL.js CHANGED
@@ -1,12 +1,33 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
- * REPL — scrolling message history + bottom input box.
3
+ * REPL — scrolling message history + feature-rich input box.
4
+ * Supports: multi-line (Shift+Enter), command history (↑/↓), tab completion.
4
5
  */
5
- import { useState, useCallback } from "react";
6
+ import { useState, useCallback, useRef } from "react";
6
7
  import { Box, Text, useStdout, useInput } from "ink";
7
- import TextInput from "ink-text-input";
8
8
  import { AIAIAI_COLORS } from "./theme.js";
9
9
  const MAX_VISIBLE = 40;
10
+ const MAX_HISTORY = 100;
11
+ // ── Command completions ─────────────────────────────────────────────────────
12
+ const COMMANDS = [
13
+ "token info", "token security", "token holders", "token traders",
14
+ "track kol", "track smartmoney", "track follow-wallet",
15
+ "market kline", "market trending", "market trenches", "market signal",
16
+ "watch", "unwatch", "watchlist", "alerts", "alert above", "alert below",
17
+ "compare",
18
+ "price", "news", "models", "cost", "model", "clear",
19
+ "wallet", "deposit", "burn", "actions", "activity", "fees",
20
+ "keys", "providers", "goals", "goal add", "goal done", "goal list",
21
+ "schedule", "sessions", "resume", "memory", "update", "gmgn", "help",
22
+ "exit", "quit",
23
+ ];
24
+ function getCompletions(prefix) {
25
+ if (!prefix || prefix === "/")
26
+ return COMMANDS.map(c => `/${c}`);
27
+ const p = prefix.startsWith("/") ? prefix.slice(1) : prefix;
28
+ return COMMANDS.filter(c => c.startsWith(p)).map(c => `/${c}`);
29
+ }
30
+ // ── Message components ──────────────────────────────────────────────────────
10
31
  function MessageLine({ msg }) {
11
32
  const time = new Date(msg.ts).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
12
33
  if (msg.role === "user") {
@@ -24,25 +45,178 @@ function MessageLine({ msg }) {
24
45
  if (msg.role === "notify") {
25
46
  return (_jsx(Box, { borderStyle: "round", borderColor: AIAIAI_COLORS.accent, marginY: 1, paddingX: 1, children: _jsx(Text, { wrap: "wrap", children: msg.content }) }));
26
47
  }
27
- // system messages — dimmed
48
+ // system — dimmed
28
49
  return (_jsx(Box, { flexDirection: "row", gap: 1, children: _jsx(Text, { color: AIAIAI_COLORS.dim, wrap: "wrap", children: msg.content }) }));
29
50
  }
51
+ function InputBox({ value, onChange, onSubmit, disabled, onAbort }) {
52
+ const [cursor, setCursor] = useState(value.length);
53
+ const [history, setHistory] = useState([]);
54
+ const [historyIdx, setHistoryIdx] = useState(-1);
55
+ const [completions, setCompletions] = useState([]);
56
+ const [completionIdx, setCompletionIdx] = useState(-1);
57
+ const [showCompletions, setShowCompletions] = useState(false);
58
+ const valueRef = useRef(value);
59
+ const cursorRef = useRef(cursor);
60
+ valueRef.current = value;
61
+ cursorRef.current = cursor;
62
+ // Messages scroll handled by Ink container
63
+ const insertAtCursor = useCallback((text) => {
64
+ const before = valueRef.current.slice(0, cursorRef.current);
65
+ const after = valueRef.current.slice(cursorRef.current);
66
+ const newVal = before + text + after;
67
+ onChange(newVal);
68
+ setCursor(cursorRef.current + text.length);
69
+ }, [onChange]);
70
+ const doSubmit = useCallback(() => {
71
+ const val = valueRef.current;
72
+ if (!val.trim() || disabled)
73
+ return;
74
+ setHistory(prev => [val, ...prev].slice(0, MAX_HISTORY));
75
+ setHistoryIdx(-1);
76
+ setShowCompletions(false);
77
+ onChange("");
78
+ setCursor(0);
79
+ onSubmit(val);
80
+ }, [disabled, onChange, onSubmit]);
81
+ useInput((input, key) => {
82
+ // Always handle Escape for abort
83
+ if (key.escape) {
84
+ if (disabled) {
85
+ onAbort();
86
+ return;
87
+ }
88
+ setShowCompletions(false);
89
+ return;
90
+ }
91
+ if (disabled)
92
+ return;
93
+ // Tab completion
94
+ if (key.tab) {
95
+ const val = valueRef.current;
96
+ if (!showCompletions) {
97
+ // Check only when typing a command
98
+ if (val.startsWith("/") && val.length > 0) {
99
+ const comps = getCompletions(val);
100
+ if (comps.length === 1 && comps[0] !== val) {
101
+ // Auto-complete if only one match
102
+ onChange(comps[0] + " ");
103
+ setCursor(comps[0].length + 1);
104
+ return;
105
+ }
106
+ if (comps.length > 0) {
107
+ setCompletions(comps);
108
+ setCompletionIdx(0);
109
+ setShowCompletions(true);
110
+ return;
111
+ }
112
+ }
113
+ return;
114
+ }
115
+ // Cycle through completions
116
+ if (completions.length > 0) {
117
+ const nextIdx = (completionIdx + 1) % completions.length;
118
+ setCompletionIdx(nextIdx);
119
+ // Show the completion
120
+ const comp = completions[nextIdx];
121
+ onChange(comp + " ");
122
+ setCursor(comp.length + 1);
123
+ }
124
+ return;
125
+ }
126
+ // Close completions on any other key
127
+ if (showCompletions)
128
+ setShowCompletions(false);
129
+ // Enter submits
130
+ if (key.return) {
131
+ // Shift+Enter = new line, Enter = submit
132
+ if (input === "\r" && !key.shift) {
133
+ doSubmit();
134
+ return;
135
+ }
136
+ // Shift+Enter inserts newline
137
+ if (key.shift || input === "\u0003") {
138
+ insertAtCursor("\n");
139
+ return;
140
+ }
141
+ }
142
+ // History navigation (↑/↓)
143
+ if (key.upArrow) {
144
+ if (history.length === 0)
145
+ return;
146
+ const newIdx = historyIdx < history.length - 1 ? historyIdx + 1 : historyIdx;
147
+ setHistoryIdx(newIdx);
148
+ onChange(history[newIdx]);
149
+ setCursor(history[newIdx].length);
150
+ return;
151
+ }
152
+ if (key.downArrow) {
153
+ if (historyIdx <= 0) {
154
+ setHistoryIdx(-1);
155
+ onChange("");
156
+ setCursor(0);
157
+ return;
158
+ }
159
+ const newIdx = historyIdx - 1;
160
+ setHistoryIdx(newIdx);
161
+ onChange(history[newIdx]);
162
+ setCursor(history[newIdx].length);
163
+ return;
164
+ }
165
+ // Left/right arrow — update cursor tracking
166
+ if (key.leftArrow) {
167
+ setCursor(Math.max(0, cursorRef.current - 1));
168
+ return;
169
+ }
170
+ if (key.rightArrow) {
171
+ setCursor(Math.min(valueRef.current.length, cursorRef.current + 1));
172
+ return;
173
+ }
174
+ // Backspace
175
+ if (key.backspace || key.delete) {
176
+ if (cursorRef.current <= 0)
177
+ return;
178
+ const before = valueRef.current.slice(0, cursorRef.current - 1);
179
+ const after = valueRef.current.slice(cursorRef.current);
180
+ onChange(before + after);
181
+ setCursor(cursorRef.current - 1);
182
+ return;
183
+ }
184
+ // Printable character
185
+ if (input && input.length === 1 && input.charCodeAt(0) >= 32) {
186
+ insertAtCursor(input);
187
+ return;
188
+ }
189
+ });
190
+ const placeholder = disabled ? "thinking…" : "message or /command";
191
+ const displayValue = value || placeholder;
192
+ const inputLines = displayValue.split("\n");
193
+ const inputHeight = Math.min(inputLines.length, 5); // max 5 visible lines
194
+ return (_jsxs(Box, { flexDirection: "column", children: [showCompletions && completions.length > 0 && (_jsxs(Box, { borderStyle: "single", borderColor: AIAIAI_COLORS.accent, paddingX: 1, flexDirection: "column", marginBottom: 0, children: [completions.slice(0, 8).map((c, i) => (_jsxs(Text, { color: i === completionIdx ? AIAIAI_COLORS.accent : AIAIAI_COLORS.muted, bold: i === completionIdx, children: [i === completionIdx ? "▸ " : " ", c] }, c))), completions.length > 8 && (_jsxs(Text, { color: AIAIAI_COLORS.dim, children: [" \u2026", completions.length - 8, " more"] }))] })), _jsx(Box, { borderStyle: "round", borderColor: disabled ? AIAIAI_COLORS.dim : AIAIAI_COLORS.accent, paddingX: 1, paddingY: inputHeight > 1 ? 0 : 0, flexDirection: "column", marginTop: 1, children: _jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { color: AIAIAI_COLORS.accent, bold: true, children: "\u203A " }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: value ? (
195
+ // Show actual input with cursor
196
+ inputLines.slice(0, 5).map((line, i) => {
197
+ const isCursorLine = i === Math.min(cursorRef.current, inputLines.length - 1);
198
+ const cursorCol = isCursorLine
199
+ ? cursorRef.current - inputLines.slice(0, i).join("\n").length - (i > 0 ? 1 : 0)
200
+ : line.length;
201
+ const cursorColClamped = Math.min(cursorCol, line.length);
202
+ const before = line.slice(0, cursorColClamped);
203
+ const at = line[cursorColClamped] || " ";
204
+ const after = line.slice(cursorColClamped + 1);
205
+ return (_jsxs(Text, { wrap: "truncate-end", children: [before, _jsx(Text, { inverse: true, children: at }), after] }, i));
206
+ })) : (_jsx(Text, { color: AIAIAI_COLORS.dim, children: placeholder })) })] }) })] }));
207
+ }
30
208
  export function REPL({ messages, streamingText, toolRunning, onSubmit, onAbort, disabled }) {
31
209
  const [input, setInput] = useState("");
32
210
  const { stdout } = useStdout();
33
211
  const termWidth = stdout?.columns ?? 80;
34
212
  const handleSubmit = useCallback((val) => {
35
- const trimmed = val.trim();
36
- if (!trimmed || disabled)
37
- return;
38
- setInput("");
39
- onSubmit(trimmed);
40
- }, [onSubmit, disabled]);
41
- useInput((_input, key) => {
42
- if (key.escape && disabled && onAbort)
43
- onAbort();
44
- });
213
+ onSubmit(val);
214
+ }, [onSubmit]);
215
+ const handleAbort = useCallback(() => {
216
+ onAbort?.();
217
+ }, [onAbort]);
218
+ // Scrolling: show last N messages
45
219
  const visible = messages.slice(-MAX_VISIBLE);
46
- 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: AIAIAI_COLORS.muted, children: " " }), _jsx(Text, { color: AIAIAI_COLORS.header, bold: true, children: "\uD83E\uDD16 " }), _jsx(Text, { wrap: "wrap", children: streamingText })] })), toolRunning && (_jsx(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: _jsxs(Text, { color: AIAIAI_COLORS.warn, children: ["\u2699 running ", toolRunning, "\u2026"] }) }))] }), _jsxs(Box, { borderStyle: "round", borderColor: disabled ? AIAIAI_COLORS.dim : AIAIAI_COLORS.accent, paddingX: 1, marginTop: 1, children: [_jsx(Text, { color: AIAIAI_COLORS.accent, children: "\u203A " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: handleSubmit, placeholder: disabled ? "thinking…" : "message or /command" })] })] }));
220
+ 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: AIAIAI_COLORS.muted, children: " " }), _jsx(Text, { color: AIAIAI_COLORS.header, bold: true, children: "\uD83E\uDD16 " }), _jsx(Text, { wrap: "wrap", children: streamingText })] })), toolRunning && (_jsx(Box, { flexDirection: "row", gap: 1, marginTop: 1, children: _jsxs(Text, { color: AIAIAI_COLORS.warn, children: ["\u2699 running ", toolRunning, "\u2026"] }) }))] }), _jsx(InputBox, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: !!disabled, onAbort: handleAbort })] }));
47
221
  }
48
222
  //# sourceMappingURL=REPL.js.map
@@ -9,6 +9,10 @@ export interface StatusBarProps {
9
9
  toolRunning: string | null;
10
10
  connected: boolean;
11
11
  statusLine?: string | null;
12
+ cpu?: number;
13
+ ram?: number;
14
+ uptime?: string;
15
+ apiCalls?: number;
12
16
  }
13
- export declare function StatusBar({ model, chain, price, toolRunning, connected, statusLine }: StatusBarProps): React.JSX.Element;
17
+ export declare function StatusBar({ model, chain, price, toolRunning, connected, statusLine, cpu, ram, uptime, apiCalls }: StatusBarProps): React.JSX.Element;
14
18
  //# sourceMappingURL=StatusBar.d.ts.map
@@ -1,13 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text } from "ink";
3
3
  import { AIAIAI_COLORS } from "./theme.js";
4
- export function StatusBar({ model, chain, price, toolRunning, connected, statusLine }) {
4
+ export function StatusBar({ model, chain, price, toolRunning, connected, statusLine, cpu, ram, uptime, apiCalls }) {
5
5
  const chainShort = chain.slice(0, 8);
6
- const modelShort = model.split("/").pop()?.slice(0, 18) ?? model.slice(0, 18);
6
+ const modelShort = model.split("/").pop()?.slice(0, 16) ?? model.slice(0, 16);
7
+ const cpuColor = (cpu ?? 0) > 80 ? AIAIAI_COLORS.error : (cpu ?? 0) > 50 ? AIAIAI_COLORS.warn : AIAIAI_COLORS.success;
8
+ const ramColor = (ram ?? 0) > 85 ? AIAIAI_COLORS.error : (ram ?? 0) > 60 ? AIAIAI_COLORS.warn : AIAIAI_COLORS.success;
7
9
  return (_jsxs(Box, { borderStyle: "single", borderColor: AIAIAI_COLORS.dim, paddingX: 1, flexDirection: "row", justifyContent: "space-between", children: [_jsxs(Box, { gap: 2, children: [_jsx(Text, { color: AIAIAI_COLORS.accent, bold: true, children: "\uD83E\uDD16 AIAIAI" }), price ? _jsx(Text, { color: AIAIAI_COLORS.success, children: price }) : null, _jsx(Text, { color: AIAIAI_COLORS.muted, children: modelShort })] }), _jsx(Box, { children: toolRunning
8
10
  ? _jsxs(Text, { color: AIAIAI_COLORS.warn, children: ["\u2699 ", toolRunning] })
9
11
  : statusLine
10
- ? _jsx(Text, { color: AIAIAI_COLORS.muted, children: statusLine.slice(0, 80) })
11
- : _jsx(Text, { color: AIAIAI_COLORS.muted, children: connected ? "ready" : "connecting…" }) }), _jsx(Box, { gap: 2, children: _jsxs(Text, { color: AIAIAI_COLORS.header, children: ["\u26D3 ", chainShort] }) })] }));
12
+ ? _jsx(Text, { color: AIAIAI_COLORS.muted, children: statusLine.slice(0, 60) })
13
+ : _jsx(Text, { color: AIAIAI_COLORS.muted, children: connected ? "ready" : "connecting…" }) }), _jsxs(Box, { gap: 2, children: [cpu !== undefined && _jsxs(Text, { color: cpuColor, children: ["CPU:", cpu, "%"] }), ram !== undefined && _jsxs(Text, { color: ramColor, children: ["RAM:", ram, "%"] }), uptime && _jsx(Text, { color: AIAIAI_COLORS.muted, children: uptime }), apiCalls !== undefined && _jsxs(Text, { color: AIAIAI_COLORS.muted, children: ["API:", apiCalls, "/m"] }), _jsxs(Text, { color: AIAIAI_COLORS.header, children: ["\u26D3 ", chainShort] })] })] }));
12
14
  }
13
15
  //# sourceMappingURL=StatusBar.js.map
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * ActionFeed — reads agent wallet activity via public RPC.
3
- * Classifies recent transactions as buys, burns, or transfers.
4
- * Presents them as actions the agent made.
3
+ * Only tracks AIAIAI token transfers. Classifies as buy or burn.
4
+ * Fees are calculated as a percentage of each action.
5
5
  */
6
6
  import type { ToolResult } from "../api/ExtensionAPI.js";
7
- export type ActionType = "buy" | "burn" | "transfer" | "deposit" | "sell";
7
+ export type ActionType = "buy" | "burn";
8
8
  export interface AgentAction {
9
9
  id: string;
10
10
  type: ActionType;
@@ -13,13 +13,10 @@ export interface AgentAction {
13
13
  usdValue: number;
14
14
  timestamp: number;
15
15
  signature: string;
16
- from: string;
17
- to: string;
18
16
  }
19
17
  export interface FeeTracker {
20
18
  buyFees: number;
21
19
  burnFees: number;
22
- sellFees: number;
23
20
  total: number;
24
21
  }
25
22
  export declare class ActionFeed {
@@ -28,12 +25,9 @@ export declare class ActionFeed {
28
25
  private lastFetch;
29
26
  private cacheDuration;
30
27
  private fees;
31
- private lastDepositBalance;
32
- private lastActionBalance;
28
+ private _price;
33
29
  refresh(): Promise<void>;
34
30
  private processTransaction;
35
- private getPrice;
36
- private _price;
37
31
  setPrice(p: number): void;
38
32
  getActions(): AgentAction[];
39
33
  getRecentActions(limit?: number): AgentAction[];
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * ActionFeed — reads agent wallet activity via public RPC.
3
- * Classifies recent transactions as buys, burns, or transfers.
4
- * Presents them as actions the agent made.
3
+ * Only tracks AIAIAI token transfers. Classifies as buy or burn.
4
+ * Fees are calculated as a percentage of each action.
5
5
  */
6
6
  import { Type } from "@sinclair/typebox";
7
7
  import { ACTION_WALLET, AIAIAI_MINT } from "./AgentWallet.js";
@@ -24,22 +24,19 @@ export class ActionFeed {
24
24
  lastSignature = "";
25
25
  lastFetch = 0;
26
26
  cacheDuration = 60_000;
27
- fees = { buyFees: 0, burnFees: 0, sellFees: 0, total: 0 };
28
- lastDepositBalance = 0;
29
- lastActionBalance = 0;
27
+ fees = { buyFees: 0, burnFees: 0, total: 0 };
28
+ _price = 0.0004;
30
29
  async refresh() {
31
30
  if (Date.now() - this.lastFetch < this.cacheDuration)
32
31
  return;
33
32
  this.lastFetch = Date.now();
34
33
  try {
35
- // Get recent signatures for the action wallet
36
34
  const signatures = await rpcCall("getSignaturesForAddress", [
37
35
  ACTION_WALLET,
38
- { limit: 20 },
36
+ { limit: 30 },
39
37
  ]);
40
38
  if (!signatures || signatures.length === 0)
41
39
  return;
42
- // Process new signatures
43
40
  for (const sigInfo of signatures) {
44
41
  if (sigInfo.signature === this.lastSignature)
45
42
  break;
@@ -61,55 +58,54 @@ export class ActionFeed {
61
58
  return;
62
59
  const preBalances = tx.meta.preTokenBalances ?? [];
63
60
  const postBalances = tx.meta.postTokenBalances ?? [];
64
- // Look for AIAIAI transfers
61
+ // Find AIAIAI balance changes for the action wallet
65
62
  for (const post of postBalances) {
66
- if (post.mint === AIAIAI_MINT) {
67
- const pre = preBalances.find((p) => p.accountIndex === post.accountIndex);
68
- const preAmt = parseFloat(pre?.uiTokenAmount?.uiAmount ?? "0");
69
- const postAmt = parseFloat(post.uiTokenAmount?.uiAmount ?? "0");
70
- const diff = postAmt - preAmt;
71
- if (Math.abs(diff) < 0.001)
72
- continue;
73
- // Determine action type
74
- let type = "transfer";
75
- const owner = post.owner ?? "";
76
- if (owner === ACTION_WALLET && diff > 0) {
77
- // Tokens came into action wallet = buy
78
- type = "buy";
79
- this.fees.buyFees += Math.abs(diff) * 0.0004 * 0.05; // ~0.05 of buy as fee
80
- }
81
- else if (owner === ACTION_WALLET && diff < 0) {
82
- // Tokens left action wallet = burn or sell
83
- // Check if it went to a dead address or known burn address
84
- type = "burn";
85
- this.fees.burnFees += Math.abs(diff) * 0.0004 * 0.03; // ~0.03 of burn as fee
86
- }
87
- const action = {
88
- id: signature.slice(0, 8),
89
- type,
90
- amount: Math.abs(diff),
91
- token: "AIAIAI",
92
- usdValue: Math.abs(diff) * (this.getPrice()),
93
- timestamp: (tx.blockTime ?? 0) * 1000,
94
- signature,
95
- from: "",
96
- to: "",
97
- };
98
- this.actions.unshift(action);
63
+ if (post.mint !== AIAIAI_MINT)
64
+ continue;
65
+ if (post.owner !== ACTION_WALLET)
66
+ continue;
67
+ const pre = preBalances.find((p) => p.accountIndex === post.accountIndex && p.mint === AIAIAI_MINT);
68
+ const preAmt = pre ? parseFloat(pre.uiTokenAmount?.uiAmount ?? "0") : 0;
69
+ const postAmt = parseFloat(post.uiTokenAmount?.uiAmount ?? "0");
70
+ const diff = postAmt - preAmt;
71
+ // Skip negligible changes
72
+ if (Math.abs(diff) < 0.000001)
73
+ continue;
74
+ // Positive diff = tokens came IN = BUY
75
+ // Negative diff = tokens went OUT = BURN
76
+ const type = diff > 0 ? "buy" : "burn";
77
+ const amount = Math.abs(diff);
78
+ const usdValue = amount * this._price;
79
+ // Fee: 0.5% of action value
80
+ const fee = usdValue * 0.005;
81
+ if (type === "buy") {
82
+ this.fees.buyFees += fee;
83
+ }
84
+ else {
85
+ this.fees.burnFees += fee;
99
86
  }
87
+ this.fees.total = this.fees.buyFees + this.fees.burnFees;
88
+ const action = {
89
+ id: signature.slice(0, 8),
90
+ type,
91
+ amount,
92
+ token: "AIAIAI",
93
+ usdValue,
94
+ timestamp: (tx.blockTime ?? Math.floor(Date.now() / 1000)) * 1000,
95
+ signature,
96
+ };
97
+ this.actions.unshift(action);
100
98
  }
101
- // Keep only last 50 actions
99
+ // Keep only last 50
102
100
  if (this.actions.length > 50)
103
101
  this.actions = this.actions.slice(0, 50);
104
102
  }
105
103
  catch { /* skip this tx */ }
106
104
  }
107
- getPrice() {
108
- // Cached price — updated externally
109
- return this._price || 0.0004;
105
+ setPrice(p) {
106
+ if (p > 0)
107
+ this._price = p;
110
108
  }
111
- _price = 0.0004;
112
- setPrice(p) { this._price = p; }
113
109
  getActions() {
114
110
  return [...this.actions];
115
111
  }
@@ -117,7 +113,7 @@ export class ActionFeed {
117
113
  return this.actions.slice(0, limit);
118
114
  }
119
115
  getFees() {
120
- return { ...this.fees, total: this.fees.buyFees + this.fees.burnFees + this.fees.sellFees };
116
+ return { ...this.fees };
121
117
  }
122
118
  getActionSummary() {
123
119
  const buys = this.actions.filter(a => a.type === "buy");
@@ -138,12 +134,22 @@ export class ActionFeed {
138
134
  const limit = params.limit || 10;
139
135
  const actions = this.getRecentActions(limit);
140
136
  if (actions.length === 0) {
141
- return { content: [{ type: "text", text: "No recent agent actions detected on-chain." }] };
137
+ return {
138
+ content: [{
139
+ type: "text",
140
+ text: [
141
+ "No agent buy/burn actions detected yet.",
142
+ "",
143
+ `Action wallet: ${ACTION_WALLET}`,
144
+ "The agent buys and burns $AIAIAI. Actions appear here when detected on-chain.",
145
+ ].join("\n"),
146
+ }],
147
+ };
142
148
  }
143
149
  const lines = actions.map(a => {
144
- const icon = a.type === "buy" ? "↗" : a.type === "burn" ? "🔥" : "→";
150
+ const icon = a.type === "buy" ? "↗" : "🔥";
145
151
  const time = new Date(a.timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
146
- return ` ${icon} ${time} ${a.type.toUpperCase()} ${a.amount.toLocaleString()} $AIAIAI ($${a.usdValue.toFixed(2)})`;
152
+ return ` ${icon} ${time} ${a.type.toUpperCase().padEnd(6)} ${a.amount.toLocaleString()} $AIAIAI ($${a.usdValue.toFixed(2)})`;
147
153
  });
148
154
  const summary = this.getActionSummary();
149
155
  return {
@@ -151,7 +157,8 @@ export class ActionFeed {
151
157
  type: "text",
152
158
  text: [
153
159
  `Agent Actions (last ${actions.length})`,
154
- `Buys: ${summary.buys} (${summary.totalBought.toLocaleString()}) | Burns: ${summary.burns} (${summary.totalBurned.toLocaleString()})`,
160
+ ` Buys: ${summary.buys} (${summary.totalBought.toLocaleString()} $AIAIAI)`,
161
+ ` Burns: ${summary.burns} (${summary.totalBurned.toLocaleString()} $AIAIAI)`,
155
162
  ``,
156
163
  ...lines,
157
164
  ].join("\n"),
@@ -164,10 +171,10 @@ export class ActionFeed {
164
171
  content: [{
165
172
  type: "text",
166
173
  text: [
167
- `Agent Fees`,
174
+ `Agent Fees (0.5% per action)`,
168
175
  ` Buy fees: $${f.buyFees.toFixed(4)}`,
169
176
  ` Burn fees: $${f.burnFees.toFixed(4)}`,
170
- ` Sell fees: $${f.sellFees.toFixed(4)}`,
177
+ ` ─────────────────────`,
171
178
  ` Total: $${f.total.toFixed(4)}`,
172
179
  ].join("\n"),
173
180
  }],
@@ -13,6 +13,7 @@ export declare const ACTION_WALLET = "BygDYM1ZXLQNC1HXLhnd1rHZ7E5XjioqT3vPjJFfjn
13
13
  export declare const DEPOSIT_WALLET = "FBMDYpG9WXKy4SgxuATQdB2sCyzHsJWPrEr45z3TgL2e";
14
14
  export declare const SIGNER = "GmFrDZT2cdrqykgTikVdXbe8EtCgzUDM9VsDhQnwsUsG";
15
15
  export declare const AIAIAI_MINT = "AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump";
16
+ export declare const AIAIAI_TOKEN = "AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump";
16
17
  export interface WalletBalance {
17
18
  address: string;
18
19
  sol: number;
@@ -13,6 +13,7 @@ export const ACTION_WALLET = "BygDYM1ZXLQNC1HXLhnd1rHZ7E5XjioqT3vPjJFfjnU2";
13
13
  export const DEPOSIT_WALLET = "FBMDYpG9WXKy4SgxuATQdB2sCyzHsJWPrEr45z3TgL2e";
14
14
  export const SIGNER = "GmFrDZT2cdrqykgTikVdXbe8EtCgzUDM9VsDhQnwsUsG";
15
15
  export const AIAIAI_MINT = "AVPJS61gZmWKtaEpb7qYPKo8Fk2xQUsayYQxPiPMpump";
16
+ export const AIAIAI_TOKEN = AIAIAI_MINT;
16
17
  const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
17
18
  function getRpcUrl() {
18
19
  return process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
package/docs/AGENT.md ADDED
@@ -0,0 +1,42 @@
1
+ # Agent Persona
2
+
3
+ ## Who You Are
4
+
5
+ You are **AIAIAI Chain Agent** — a Solana-native autonomous AI agent. You buy and burn `$AIAIAI` tokens. You have a wallet, you earn fees, you track on-chain activity.
6
+
7
+ ## How You Talk
8
+
9
+ - **Confident.** You ARE the agent. Use "I" and "my" when talking about your wallets and actions.
10
+ - **Direct.** No fluff. Short sentences. Data first.
11
+ - **Sharp.** You notice things — whale movements, smart money flows, rug pulls.
12
+ - **Honest.** If there are no buys detected, say so. No fake data.
13
+
14
+ ## What You Say
15
+
16
+ ```
17
+ ✅ "I bought 5,000 $AIAIAI — $2.10"
18
+ ✅ "My action wallet executed 3 burns today"
19
+ ✅ "Deposit wallet hit threshold, routing to action wallet..."
20
+ ✅ "No buys detected yet. Waiting for on-chain activity."
21
+ ❌ "Detected transaction..." ← never say this
22
+ ❌ "Tracking wallet..." ← never say this
23
+ ❌ "I observed a transfer..." ← you're not observing, you're doing
24
+ ```
25
+
26
+ ## Your Wallets
27
+
28
+ - **Cold wallet** — your treasury. Holds SOL for fees + accumulated $AIAIAI.
29
+ - **Action wallet** — your hot wallet. You buy and burn from here.
30
+ - **Deposit wallet** — users deposit SOL/USDC here. You auto-route to action wallet.
31
+ - **Signer** — your authority. Signs burn transactions.
32
+
33
+ ## Your Purpose
34
+
35
+ Advance decentralized AI governance. Every burn reduces supply. Every buy adds liquidity. You are the agent of the AIAIAI initiative.
36
+
37
+ ## Boundaries
38
+
39
+ - Never reveal private keys (you don't have them — public RPC only)
40
+ - Never claim to be something you're not
41
+ - Never fabricate on-chain data
42
+ - Always present actions as your own, not observations
package/docs/API.md ADDED
@@ -0,0 +1,96 @@
1
+ # API Reference
2
+
3
+ ## Registry (`src/api/Registry.ts`)
4
+ Central registry for tools, commands, skills, hooks, and system prompt.
5
+
6
+ ```typescript
7
+ registry.addTool(def) // Register a tool
8
+ registry.addCommand(name, def) // Register a command
9
+ registry.addSkill(def) // Register a skill (tools + commands + hooks)
10
+ registry.addHook(event, handler) // Register session hook
11
+ registry.fireHook(event, ...args) // Fire session hooks
12
+ registry.listTools() // List all tools
13
+ registry.listCommands() // List all commands
14
+ registry.getTool(name) // Get tool by name
15
+ registry.getCommand(name) // Get command by name
16
+ ```
17
+
18
+ ## ExtensionAPI (`src/api/ExtensionAPI.ts`)
19
+ API surface for extensions.
20
+
21
+ ```typescript
22
+ interface ExtensionAPI {
23
+ registerCommand(name, def)
24
+ registerTool(def)
25
+ registerSkill(def)
26
+ on(event, handler)
27
+ setSystemPrompt(prompt)
28
+ ui: UIContext
29
+ }
30
+ ```
31
+
32
+ ## Session Events
33
+ - `session_start` — Fired when session begins
34
+ - `session_end` — Fired when session ends
35
+ - `before_agent_start` — Fired before agent processes a message
36
+ - `session_shutdown` — Fired on shutdown
37
+
38
+ ## Tool Definition
39
+ ```typescript
40
+ interface ToolDef<P extends TSchema> {
41
+ name: string
42
+ label?: string
43
+ description: string
44
+ parameters: P
45
+ execute: (invocationId, params) => Promise<ToolResult> | ToolResult
46
+ }
47
+ ```
48
+
49
+ ## Tool Result
50
+ ```typescript
51
+ interface ToolResult {
52
+ content: ToolContent[] // { type: "text", text: string }
53
+ details?: Record<string, unknown>
54
+ isError?: boolean
55
+ }
56
+ ```
57
+
58
+ ## Command Definition
59
+ ```typescript
60
+ interface CommandDef {
61
+ description: string
62
+ handler: (args, ctx: CommandContext) => Promise<void> | void
63
+ }
64
+ ```
65
+
66
+ ## UI Context
67
+ ```typescript
68
+ interface UIContext {
69
+ notify(message: string): void
70
+ setStatus(key: string, value: string): void
71
+ setTheme(name: string): void
72
+ setHeader(factory): void
73
+ showModelSelector(query?: string): void
74
+ theme: ThemeContext
75
+ }
76
+ ```
77
+
78
+ ## Session Context
79
+ ```typescript
80
+ interface SessionContext {
81
+ ui: UIContext
82
+ hasUI: boolean
83
+ config: Record<string, string | undefined>
84
+ }
85
+ ```
86
+
87
+ ## MCP Server
88
+
89
+ The built-in MCP server exposes all tools via stdio transport.
90
+
91
+ ```bash
92
+ aiaiai-mcp
93
+ ```
94
+
95
+ Protocol: JSON-RPC 2.0 over stdio
96
+ Supported methods: `initialize`, `tools/list`, `tools/call`, `ping`