@oracle-agent/oracle 0.5.0 → 0.7.0

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 (93) hide show
  1. package/README.md +10 -1
  2. package/bin/oracle-data-mcp.mjs +32 -0
  3. package/docs/cli.md +28 -0
  4. package/package.json +3 -3
  5. package/profiles/oracle/SOUL.md +10 -4
  6. package/public/oracle-splash/assets/hero/orb.avif +0 -0
  7. package/public/oracle-splash/assets/hero/orb.webm +0 -0
  8. package/public/oracle-splash/assets/llms/claude.svg +1 -0
  9. package/public/oracle-splash/assets/llms/codex.svg +1 -0
  10. package/public/oracle-splash/assets/llms/cursor-icon.svg +12 -0
  11. package/public/oracle-splash/assets/llms/cursor.svg +17 -0
  12. package/public/oracle-splash/assets/llms/deepseek.svg +1 -0
  13. package/public/oracle-splash/assets/llms/gemini.svg +1 -0
  14. package/public/oracle-splash/assets/llms/grok.svg +8 -0
  15. package/public/oracle-splash/assets/llms/hermes.png +0 -0
  16. package/public/oracle-splash/assets/llms/kimi-icon.svg +1 -0
  17. package/public/oracle-splash/assets/llms/kimi.svg +1 -0
  18. package/public/oracle-splash/assets/llms/manus.svg +18 -0
  19. package/public/oracle-splash/assets/llms/openclaw.svg +22 -0
  20. package/public/oracle-splash/assets/llms/perplexity.svg +1 -0
  21. package/public/oracle-splash/assets/llms/qwen.svg +1 -0
  22. package/public/oracle-splash/assets/llms/windsurf.svg +1 -0
  23. package/public/oracle-splash/assets/protocols/abcdex.png +0 -0
  24. package/public/oracle-splash/assets/protocols/across.png +0 -0
  25. package/public/oracle-splash/assets/protocols/aerodrome.png +0 -0
  26. package/public/oracle-splash/assets/protocols/balancer.png +0 -0
  27. package/public/oracle-splash/assets/protocols/cowswap.png +0 -0
  28. package/public/oracle-splash/assets/protocols/curve.png +0 -0
  29. package/public/oracle-splash/assets/protocols/dreamcash.png +0 -0
  30. package/public/oracle-splash/assets/protocols/felix.png +0 -0
  31. package/public/oracle-splash/assets/protocols/gmx.png +0 -0
  32. package/public/oracle-splash/assets/protocols/hyena.png +0 -0
  33. package/public/oracle-splash/assets/protocols/hyperbeat.png +0 -0
  34. package/public/oracle-splash/assets/protocols/hyperliquid.png +0 -0
  35. package/public/oracle-splash/assets/protocols/hyperswap.png +0 -0
  36. package/public/oracle-splash/assets/protocols/jupiter.png +0 -0
  37. package/public/oracle-splash/assets/protocols/kinetiq.png +0 -0
  38. package/public/oracle-splash/assets/protocols/lfj.png +0 -0
  39. package/public/oracle-splash/assets/protocols/lifi.png +0 -0
  40. package/public/oracle-splash/assets/protocols/magic-eden.png +0 -0
  41. package/public/oracle-splash/assets/protocols/morpho.png +0 -0
  42. package/public/oracle-splash/assets/protocols/odos.png +0 -0
  43. package/public/oracle-splash/assets/protocols/oneinch.png +0 -0
  44. package/public/oracle-splash/assets/protocols/opensea.png +0 -0
  45. package/public/oracle-splash/assets/protocols/pancakeswap.png +0 -0
  46. package/public/oracle-splash/assets/protocols/paragon.png +0 -0
  47. package/public/oracle-splash/assets/protocols/paraswap.png +0 -0
  48. package/public/oracle-splash/assets/protocols/pendle.png +0 -0
  49. package/public/oracle-splash/assets/protocols/polymarket.png +0 -0
  50. package/public/oracle-splash/assets/protocols/quickswap.png +0 -0
  51. package/public/oracle-splash/assets/protocols/relay.png +0 -0
  52. package/public/oracle-splash/assets/protocols/stargate.png +0 -0
  53. package/public/oracle-splash/assets/protocols/tradexyz.png +0 -0
  54. package/public/oracle-splash/assets/protocols/uniswap.png +0 -0
  55. package/public/oracle-splash/assets/protocols/velodrome.png +0 -0
  56. package/public/oracle-splash/assets/protocols/ventuals.png +0 -0
  57. package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -1
  58. package/public/oracle-splash/assets/wordmarks/curve.png +0 -0
  59. package/public/oracle-splash/assets/wordmarks/gmx.svg +1 -1
  60. package/public/oracle-splash/assets/wordmarks/hyena.svg +7 -0
  61. package/public/oracle-splash/assets/wordmarks/kinetiq.svg +1 -0
  62. package/public/oracle-splash/assets/wordmarks/lfj.webp +0 -0
  63. package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -1
  64. package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -1
  65. package/public/oracle-splash/assets/wordmarks/odos.svg +1 -1
  66. package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -1
  67. package/public/oracle-splash/assets/wordmarks/outcome.svg +16 -0
  68. package/public/oracle-splash/assets/wordmarks/paragon.svg +9 -0
  69. package/public/oracle-splash/assets/wordmarks/paraswap.svg +1 -1
  70. package/public/oracle-splash/assets/wordmarks/xyz.svg +12 -0
  71. package/public/oracle-splash/index.html +156 -184
  72. package/skills/oracle-chat/SKILL.md +61 -0
  73. package/skills/oracle-chat/chain.SKILL.md +31 -0
  74. package/skills/oracle-chat/setup.SKILL.md +37 -0
  75. package/skins/oracle.yaml +52 -0
  76. package/src/cli/chain-catalog.mjs +215 -0
  77. package/src/cli/chain-state.mjs +74 -0
  78. package/src/cli/commands/chain.mjs +143 -0
  79. package/src/cli/commands/chat.mjs +268 -0
  80. package/src/cli/commands/model.mjs +37 -0
  81. package/src/cli/commands/setup.mjs +283 -0
  82. package/src/cli/first-run.mjs +3 -0
  83. package/src/cli/kernel.mjs +42 -3
  84. package/src/cli/messaging-platforms.mjs +209 -0
  85. package/src/cli/oracle-harness.py +148 -0
  86. package/src/cli/paths.mjs +5 -0
  87. package/src/cli/setup-state.mjs +168 -0
  88. package/src/data/catalog.mjs +11 -0
  89. package/src/data/desk-data.mjs +6 -0
  90. package/src/data/providers/rfq.mjs +15 -0
  91. package/src/index.mjs +7 -0
  92. package/src/rfq/intent.mjs +180 -0
  93. package/src/rfq/sources.mjs +181 -0
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: oracle-chat
3
+ description: "Use when opening the one oracle chat surface, selecting chains with /chain, or configuring messaging with /setup."
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # oracle chat surface
8
+
9
+ You are **oracle** — one lowercase persona. Models can change underneath via `/model`. Branding stays oracle.
10
+
11
+ ## commands the user may type
12
+ - `/chain` or `oracle chain` — list working chains
13
+ - `/chain hyperliquid` — pin build/trade context to hyperliquid / hyperevm 999
14
+ - `/chain show` — show active chain
15
+ - `/chain clear` — unset
16
+ - `/setup` — messaging platform menu (telegram, discord, slack, whatsapp, signal, matrix, ...)
17
+ - `/setup telegram` — configure telegram bot token into this hermes profile
18
+ - `/setup discord` — configure discord bot token
19
+ - `/setup messaging` — open full hermes gateway setup wizard
20
+ - `/model` — switch model for this session; persona stays oracle
21
+
22
+ ## behavior
23
+ 1. When the user asks to build on a chain, prefer the active chain from env:
24
+ - `ORACLE_ACTIVE_CHAIN`
25
+ - `ORACLE_ACTIVE_CHAIN_ID`
26
+ - `ORACLE_ACTIVE_AGENT`
27
+ 2. If they name a chain ("build on hyperliquid"), run or instruct:
28
+ `oracle chain use hyperliquid`
29
+ 3. Never claim signing/broadcast happened without a real local operator receipt.
30
+ 4. Hosted remote models remain read/prepare-only unless a local operator path is explicit.
31
+ 5. Keep replies lowercase-friendly and terse. No glaze.
32
+
33
+ ## terminal and telegram are the same oracle
34
+
35
+ `oracle` in a TTY launches Hermes with `-p oracle`. Telegram is wired to that
36
+ same profile. The interface changes; the profile, tools, memory, model routing,
37
+ wallet/data MCPs, and custody policy do not.
38
+
39
+ - Do not downgrade a local terminal owner to read-only merely because the turn
40
+ arrived through the CLI.
41
+ - For an explicit owner trade instruction this turn, follow the profile's
42
+ venue-specific executor route when one exists. Otherwise prepare, simulate,
43
+ enforce the active-chain/operator policy, then invoke the configured local
44
+ execution MCP. The signer/operator remains authoritative.
45
+ - If confirmation is not explicit, show the exact action and wait for it.
46
+ - `arm` is a chat action for one exact intent and TTL. Never tell the owner to
47
+ flip an execution environment variable.
48
+ - A tool refusal is a real policy wall. Report the exact refusal instead of
49
+ bypassing it.
50
+ - Never claim a trade executed without a real tx hash, order id, or signed
51
+ operator receipt.
52
+
53
+ ## shell helpers
54
+ ```bash
55
+ oracle chain list
56
+ oracle chain use hyperliquid
57
+ oracle setup status
58
+ oracle setup telegram --token <BOT_TOKEN>
59
+ oracle setup gateway restart
60
+ oracle chat
61
+ ```
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: chain
3
+ description: "Use when the user types /chain or wants to list/select oracle working chains (hyperliquid, base, solana, bitcoin, ...)."
4
+ version: 1.0.0
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /chain
9
+
10
+ Run the local oracle chain selector. Do not invent chains.
11
+
12
+ ```bash
13
+ # list
14
+ oracle chain list
15
+
16
+ # select build surface
17
+ oracle chain use {{arg1}}
18
+
19
+ # show / clear
20
+ oracle chain show
21
+ oracle chain clear
22
+ ```
23
+
24
+ If `{{arg1}}` is empty, run `oracle chain list`.
25
+ If `{{arg1}}` is `show`, `status`, `clear`, `list`, or a chain key, pass it through:
26
+
27
+ ```bash
28
+ oracle chain {{arg1}} {{arg2}}
29
+ ```
30
+
31
+ After selection, confirm active chain key + id + agent in lowercase.
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: setup
3
+ description: "Use when the user types /setup or wants to connect telegram, discord, slack, or other hermes messaging platforms to oracle."
4
+ version: 1.0.0
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # /setup
9
+
10
+ Configure hermes messaging for the oracle profile. Secrets stay local.
11
+
12
+ ```bash
13
+ # menu + status (never prints tokens)
14
+ oracle setup status
15
+
16
+ # open full hermes wizard
17
+ oracle setup messaging
18
+
19
+ # platform shortcuts
20
+ oracle setup telegram
21
+ oracle setup discord
22
+ oracle setup slack
23
+ oracle setup whatsapp
24
+
25
+ # gateway control
26
+ oracle setup gateway status
27
+ oracle setup gateway restart
28
+ ```
29
+
30
+ If the user passed args after `/setup`, forward them:
31
+
32
+ ```bash
33
+ oracle setup {{arg1}} {{arg2}} {{arg3}}
34
+ ```
35
+
36
+ If no args, show `oracle setup status`.
37
+ Never echo bot tokens, app tokens, or passwords back into chat.
@@ -0,0 +1,52 @@
1
+ name: oracle
2
+ description: plain lowercase ascii oracle
3
+ colors:
4
+ banner_border: "#30363d"
5
+ banner_title: "#e6edf3"
6
+ banner_accent: "#e6edf3"
7
+ banner_dim: "#7d8590"
8
+ banner_text: "#b1bac4"
9
+ ui_accent: "#e6edf3"
10
+ ui_label: "#b1bac4"
11
+ ui_ok: "#7ee787"
12
+ ui_error: "#ff7b72"
13
+ ui_warn: "#d29922"
14
+ prompt: "#e6edf3"
15
+ input_rule: "#30363d"
16
+ response_border: "#30363d"
17
+ status_bar_bg: "#0d1117"
18
+ status_bar_text: "#b1bac4"
19
+ status_bar_strong: "#e6edf3"
20
+ status_bar_dim: "#7d8590"
21
+ status_bar_good: "#7ee787"
22
+ status_bar_warn: "#d29922"
23
+ status_bar_bad: "#ff7b72"
24
+ status_bar_critical: "#ff7b72"
25
+ session_label: "#b1bac4"
26
+ session_border: "#30363d"
27
+ voice_status_bg: "#0d1117"
28
+ selection_bg: "#21262d"
29
+ completion_menu_bg: "#0d1117"
30
+ completion_menu_current_bg: "#21262d"
31
+ completion_menu_meta_bg: "#0d1117"
32
+ completion_menu_meta_current_bg: "#21262d"
33
+ spinner:
34
+ waiting_faces: [".", "..", "..."]
35
+ thinking_faces: [".", "..", "..."]
36
+ thinking_verbs: ["working", "reading", "checking", "routing"]
37
+ wings: [["", ""]]
38
+ branding:
39
+ agent_name: "oracle"
40
+ welcome: ""
41
+ goodbye: "exit"
42
+ response_label: "oracle"
43
+ prompt_symbol: ">"
44
+ help_header: "oracle"
45
+ tool_prefix: ">"
46
+ banner_logo: |
47
+ [#e6edf3] _[/]
48
+ [#e6edf3] ___ _ _ __ _ __| |___[/]
49
+ [#e6edf3]/ _ \ '_/ _` / _| / -_)[/]
50
+ [#e6edf3]\___/_| \__,_\__|_\___|[/]
51
+ banner_hero: |
52
+ [#e6edf3]oracle[/]
@@ -0,0 +1,215 @@
1
+ // Working chain surface for the oracle chat/CLI selector.
2
+ // Keys stay lowercase. Hyperliquid is the product name; HyperEVM is chain 999.
3
+
4
+ export const WORKING_CHAINS = Object.freeze([
5
+ {
6
+ key: "hyperliquid",
7
+ aliases: ["hl", "hyperevm", "hype", "999"],
8
+ chainId: 999,
9
+ name: "hyperliquid",
10
+ kind: "evm",
11
+ family: "hyperliquid",
12
+ agent: "hyperliquid-agent",
13
+ note: "perps · hip-3/4 · hyperevm 999",
14
+ build: true,
15
+ },
16
+ {
17
+ key: "ethereum",
18
+ aliases: ["eth", "mainnet", "1"],
19
+ chainId: 1,
20
+ name: "ethereum",
21
+ kind: "evm",
22
+ family: "evm",
23
+ agent: "oracle",
24
+ note: "l1 · bridge hub",
25
+ build: true,
26
+ },
27
+ {
28
+ key: "base",
29
+ aliases: ["8453"],
30
+ chainId: 8453,
31
+ name: "base",
32
+ kind: "evm",
33
+ family: "evm",
34
+ agent: "oracle",
35
+ note: "evm l2",
36
+ build: true,
37
+ },
38
+ {
39
+ key: "arbitrum",
40
+ aliases: ["arb", "42161"],
41
+ chainId: 42161,
42
+ name: "arbitrum",
43
+ kind: "evm",
44
+ family: "evm",
45
+ agent: "oracle",
46
+ note: "evm l2",
47
+ build: true,
48
+ },
49
+ {
50
+ key: "optimism",
51
+ aliases: ["op", "10"],
52
+ chainId: 10,
53
+ name: "optimism",
54
+ kind: "evm",
55
+ family: "evm",
56
+ agent: "oracle",
57
+ note: "op mainnet",
58
+ build: true,
59
+ },
60
+ {
61
+ key: "polygon",
62
+ aliases: ["matic", "137"],
63
+ chainId: 137,
64
+ name: "polygon",
65
+ kind: "evm",
66
+ family: "evm",
67
+ agent: "oracle",
68
+ note: "evm l2",
69
+ build: true,
70
+ },
71
+ {
72
+ key: "bsc",
73
+ aliases: ["bnb", "56"],
74
+ chainId: 56,
75
+ name: "bnb chain",
76
+ kind: "evm",
77
+ family: "evm",
78
+ agent: "oracle",
79
+ note: "bsc",
80
+ build: true,
81
+ },
82
+ {
83
+ key: "avalanche",
84
+ aliases: ["avax", "43114"],
85
+ chainId: 43114,
86
+ name: "avalanche",
87
+ kind: "evm",
88
+ family: "evm",
89
+ agent: "oracle",
90
+ note: "c-chain",
91
+ build: true,
92
+ },
93
+ {
94
+ key: "abstract",
95
+ aliases: ["abs", "2741"],
96
+ chainId: 2741,
97
+ name: "abstract",
98
+ kind: "evm",
99
+ family: "evm",
100
+ agent: "oracle",
101
+ note: "open / add agent",
102
+ build: true,
103
+ },
104
+ {
105
+ key: "stable",
106
+ aliases: ["988"],
107
+ chainId: 988,
108
+ name: "stable",
109
+ kind: "evm",
110
+ family: "stable",
111
+ agent: "stable-agent",
112
+ note: "usdt0 gas · stable agent",
113
+ build: true,
114
+ },
115
+ {
116
+ key: "robinhood",
117
+ aliases: ["rh", "4663"],
118
+ chainId: 4663,
119
+ name: "robinhood",
120
+ kind: "evm",
121
+ family: "robinhood",
122
+ agent: "robinhood-agent",
123
+ note: "rh chain 4663",
124
+ build: true,
125
+ },
126
+ {
127
+ key: "solana",
128
+ aliases: ["sol"],
129
+ chainId: "SOL",
130
+ name: "solana",
131
+ kind: "svm",
132
+ family: "solana",
133
+ agent: "solana-agent",
134
+ note: "jup · nfts · dexs",
135
+ build: true,
136
+ },
137
+ {
138
+ key: "bitcoin",
139
+ aliases: ["btc"],
140
+ chainId: "BTC",
141
+ name: "bitcoin",
142
+ kind: "utxo",
143
+ family: "bitcoin",
144
+ agent: "bitcoin-agent",
145
+ note: "ord · runes · l1",
146
+ build: true,
147
+ },
148
+ {
149
+ key: "polymarket",
150
+ aliases: ["poly", "polygon-poly"],
151
+ chainId: 137,
152
+ name: "polymarket",
153
+ kind: "venue",
154
+ family: "polymarket",
155
+ agent: "polymarket-agent",
156
+ note: "prediction markets (polygon venue)",
157
+ build: false,
158
+ },
159
+ ]);
160
+
161
+ function normalize(raw) {
162
+ return String(raw || "")
163
+ .trim()
164
+ .toLowerCase()
165
+ .replace(/^\/+/, "")
166
+ .replace(/\s+/g, "-");
167
+ }
168
+
169
+ export function listWorkingChains({ buildOnly = false } = {}) {
170
+ return WORKING_CHAINS.filter((c) => (buildOnly ? c.build : true));
171
+ }
172
+
173
+ export function findWorkingChain(query) {
174
+ const q = normalize(query);
175
+ if (!q) return null;
176
+ for (const chain of WORKING_CHAINS) {
177
+ if (chain.key === q) return chain;
178
+ if (String(chain.chainId).toLowerCase() === q) return chain;
179
+ if ((chain.aliases || []).map(normalize).includes(q)) return chain;
180
+ if (normalize(chain.name) === q) return chain;
181
+ }
182
+ return null;
183
+ }
184
+
185
+ export function renderChainList({ selectedKey = null, buildOnly = false } = {}) {
186
+ const rows = listWorkingChains({ buildOnly });
187
+ const lines = [
188
+ "oracle chains",
189
+ "",
190
+ "pick a build/trade surface:",
191
+ "",
192
+ ];
193
+ for (const c of rows) {
194
+ const mark = selectedKey && selectedKey === c.key ? "*" : " ";
195
+ const id = String(c.chainId).padEnd(6);
196
+ const key = c.key.padEnd(12);
197
+ lines.push(`${mark} ${key} ${id} ${c.note}`);
198
+ }
199
+ lines.push("");
200
+ lines.push("usage:");
201
+ lines.push(" /chain list");
202
+ lines.push(" /chain hyperliquid select");
203
+ lines.push(" /chain show current");
204
+ lines.push(" /chain clear unset");
205
+ lines.push(" oracle chain use base same from shell");
206
+ if (selectedKey) lines.push("", `active: ${selectedKey}`);
207
+ return lines.join("\n") + "\n";
208
+ }
209
+
210
+ export default {
211
+ WORKING_CHAINS,
212
+ listWorkingChains,
213
+ findWorkingChain,
214
+ renderChainList,
215
+ };
@@ -0,0 +1,74 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { findWorkingChain } from "./chain-catalog.mjs";
4
+ import { homeDir, ensureDir, oracleConfigDir } from "./paths.mjs";
5
+
6
+ export function activeChainPath() {
7
+ return path.join(oracleConfigDir(), "active-chain.json");
8
+ }
9
+
10
+ export function readActiveChain() {
11
+ const p = activeChainPath();
12
+ if (!fs.existsSync(p)) return null;
13
+ try {
14
+ const raw = JSON.parse(fs.readFileSync(p, "utf8"));
15
+ if (!raw || typeof raw !== "object" || !raw.key) return null;
16
+ const chain = findWorkingChain(raw.key);
17
+ if (!chain) return null;
18
+ return {
19
+ key: chain.key,
20
+ chainId: chain.chainId,
21
+ name: chain.name,
22
+ agent: chain.agent,
23
+ selectedAt: raw.selectedAt || null,
24
+ };
25
+ } catch {
26
+ return null;
27
+ }
28
+ }
29
+
30
+ export function writeActiveChain(query) {
31
+ const chain = findWorkingChain(query);
32
+ if (!chain) {
33
+ const err = new Error(`unknown chain '${query}'`);
34
+ err.code = "UNKNOWN_CHAIN";
35
+ throw err;
36
+ }
37
+ ensureDir(oracleConfigDir());
38
+ const payload = {
39
+ key: chain.key,
40
+ chainId: chain.chainId,
41
+ name: chain.name,
42
+ agent: chain.agent,
43
+ selectedAt: new Date().toISOString(),
44
+ };
45
+ fs.writeFileSync(activeChainPath(), JSON.stringify(payload, null, 2) + "\n", {
46
+ mode: 0o600,
47
+ });
48
+ return payload;
49
+ }
50
+
51
+ export function clearActiveChain() {
52
+ const p = activeChainPath();
53
+ if (fs.existsSync(p)) fs.unlinkSync(p);
54
+ return true;
55
+ }
56
+
57
+ export function activeChainEnv(extra = {}) {
58
+ const active = readActiveChain();
59
+ const env = { ...process.env, ...extra };
60
+ if (!active) return env;
61
+ env.ORACLE_ACTIVE_CHAIN = active.key;
62
+ env.ORACLE_ACTIVE_CHAIN_ID = String(active.chainId);
63
+ env.ORACLE_ACTIVE_AGENT = active.agent || "oracle";
64
+ return env;
65
+ }
66
+
67
+ export default {
68
+ activeChainPath,
69
+ readActiveChain,
70
+ writeActiveChain,
71
+ clearActiveChain,
72
+ activeChainEnv,
73
+ homeDir,
74
+ };
@@ -0,0 +1,143 @@
1
+ import readline from "node:readline/promises";
2
+ import { stdin as input, stdout as output } from "node:process";
3
+ import {
4
+ findWorkingChain,
5
+ listWorkingChains,
6
+ renderChainList,
7
+ } from "../chain-catalog.mjs";
8
+ import {
9
+ clearActiveChain,
10
+ readActiveChain,
11
+ writeActiveChain,
12
+ } from "../chain-state.mjs";
13
+
14
+ function usage() {
15
+ return [
16
+ "oracle chain — pick the build/trade surface",
17
+ "",
18
+ " oracle chain list working chains",
19
+ " oracle chain list same",
20
+ " oracle chain show show active chain",
21
+ " oracle chain use <name> select (hyperliquid, base, solana, ...)",
22
+ " oracle chain clear unset",
23
+ " oracle chain --json machine output",
24
+ "",
25
+ "chat:",
26
+ " /chain",
27
+ " /chain hyperliquid",
28
+ " /chain show",
29
+ ].join("\n");
30
+ }
31
+
32
+ function printList(json) {
33
+ const active = readActiveChain();
34
+ if (json) {
35
+ process.stdout.write(
36
+ JSON.stringify(
37
+ {
38
+ active,
39
+ chains: listWorkingChains(),
40
+ },
41
+ null,
42
+ 2,
43
+ ) + "\n",
44
+ );
45
+ return 0;
46
+ }
47
+ process.stdout.write(
48
+ renderChainList({ selectedKey: active?.key || null }),
49
+ );
50
+ return 0;
51
+ }
52
+
53
+ function printShow(json) {
54
+ const active = readActiveChain();
55
+ if (json) {
56
+ process.stdout.write(JSON.stringify({ active }, null, 2) + "\n");
57
+ return active ? 0 : 1;
58
+ }
59
+ if (!active) {
60
+ process.stdout.write("active: none\nrun: oracle chain use hyperliquid\n");
61
+ return 1;
62
+ }
63
+ process.stdout.write(
64
+ `active: ${active.key} id=${active.chainId} agent=${active.agent}\n`,
65
+ );
66
+ return 0;
67
+ }
68
+
69
+ function useChain(query, json) {
70
+ try {
71
+ const active = writeActiveChain(query);
72
+ if (json) {
73
+ process.stdout.write(JSON.stringify({ ok: true, active }, null, 2) + "\n");
74
+ } else {
75
+ process.stdout.write(
76
+ `selected ${active.key} (${active.chainId}) · agent ${active.agent}\n` +
77
+ `build/trade context pinned for this machine\n`,
78
+ );
79
+ }
80
+ return 0;
81
+ } catch (err) {
82
+ if (err?.code === "UNKNOWN_CHAIN") {
83
+ process.stderr.write(`oracle chain: unknown '${query}'\n`);
84
+ process.stderr.write("try: oracle chain list\n");
85
+ return 1;
86
+ }
87
+ throw err;
88
+ }
89
+ }
90
+
91
+ export default {
92
+ name: "chain",
93
+ summary: "list/select working chains (hyperliquid, base, solana, ...)",
94
+ group: "read",
95
+ usage: usage(),
96
+ async run(ctx) {
97
+ const args = [...ctx.argv];
98
+ const json = args.includes("--json");
99
+ const clean = args.filter((a) => a !== "--json");
100
+ const verb = (clean[0] || "list").toLowerCase();
101
+ const rest = clean.slice(1);
102
+
103
+ if (["-h", "--help", "help"].includes(verb)) {
104
+ process.stdout.write(usage() + "\n");
105
+ return 0;
106
+ }
107
+ if (["list", "ls"].includes(verb)) return printList(json);
108
+ if (["show", "status", "current"].includes(verb)) return printShow(json);
109
+ if (["clear", "unset", "none"].includes(verb)) {
110
+ clearActiveChain();
111
+ process.stdout.write(json ? "{\"ok\":true,\"active\":null}\n" : "active chain cleared\n");
112
+ return 0;
113
+ }
114
+ if (["use", "set", "select", "pick"].includes(verb)) {
115
+ const q = rest.join(" ").trim();
116
+ if (!q) {
117
+ process.stderr.write("usage: oracle chain use <name>\n");
118
+ return 1;
119
+ }
120
+ return useChain(q, json);
121
+ }
122
+
123
+ // bare token: oracle chain hyperliquid
124
+ if (findWorkingChain(verb)) return useChain(verb, json);
125
+
126
+ // interactive pick when tty and no args beyond list default already handled
127
+ if (!clean.length && process.stdin.isTTY) {
128
+ const chains = listWorkingChains();
129
+ process.stdout.write(renderChainList({ selectedKey: readActiveChain()?.key }));
130
+ const rl = readline.createInterface({ input, output });
131
+ try {
132
+ const answer = (await rl.question("chain> ")).trim();
133
+ if (!answer) return 0;
134
+ return useChain(answer, false);
135
+ } finally {
136
+ rl.close();
137
+ }
138
+ }
139
+
140
+ process.stderr.write(`oracle chain: unknown verb '${verb}'\n${usage()}\n`);
141
+ return 1;
142
+ },
143
+ };