@oracle-agent/oracle 0.3.3 → 0.3.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.
- package/README.md +5 -12
- package/SETUP.md +1 -35
- package/artifacts/specialist-packs/oracle-full-crypto.json +9 -31
- package/bin/oracle-data-mcp.mjs +74 -247
- package/bin/oracle-init.mjs +27 -100
- package/docs/profiles.md +7 -27
- package/package.json +1 -1
- package/profiles/_template/SOUL.md +1 -8
- package/profiles/oracle/SOUL.md +1 -8
- package/profiles/oracle/profile.json +2 -5
- package/profiles/protocol-builder/SOUL.md +6 -13
- package/profiles/protocol-builder/profile.json +1 -3
- package/src/cards.mjs +369 -0
- package/src/data/catalog.mjs +3 -27
- package/src/data/desk-data.mjs +4 -34
- package/src/data/providers/magiceden-sol.mjs +2 -21
- package/src/data/providers/opensea-nft.mjs +0 -272
- package/src/data/providers/satflow.mjs +0 -1
- package/src/data/providers/uniswap-v3.mjs +17 -1
- package/src/exec-policy.mjs +0 -5
- package/src/gmx-attestation.mjs +0 -1
- package/src/router/prepare-route.mjs +23 -0
- package/src/router/route-sources.mjs +37 -0
- package/src/scanner/chains.config.mjs +48 -1
- package/src/vault-attestation.mjs +0 -1
- package/skills/balance/SKILL.md +0 -176
- package/skills/oracle-multichain-nft-launch/SKILL.md +0 -338
- package/skills/oracle-multichain-token-launch/SKILL.md +0 -300
- package/src/data/providers/nft-gallery.mjs +0 -163
- package/src/data/providers/nft-portfolio.mjs +0 -494
- package/src/data/providers/portfolio-history.mjs +0 -394
- package/src/data/providers/portfolio.mjs +0 -594
package/bin/oracle-init.mjs
CHANGED
|
@@ -176,71 +176,6 @@ function record(kind, detail) {
|
|
|
176
176
|
log(`${APPLY ? " ✔" : " ·"} ${kind}: ${detail}`);
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
// Write Hermes mcp_servers.oracle-data directly into the profile config.
|
|
180
|
-
// Prefer this over `hermes mcp add`: current Hermes takes --command and --args
|
|
181
|
-
// as separate tokens, prompts interactively for tool enablement, and the old
|
|
182
|
-
// installer form `--command "node <path>"` silently no-ops under execFileSync.
|
|
183
|
-
function yamlScalar(value) {
|
|
184
|
-
if (
|
|
185
|
-
value === "" ||
|
|
186
|
-
/[:#\[\]{},&*!|>'"%@`\s]/.test(value) ||
|
|
187
|
-
/^(?:null|true|false|\d+)$/i.test(value)
|
|
188
|
-
) {
|
|
189
|
-
return JSON.stringify(value);
|
|
190
|
-
}
|
|
191
|
-
return value;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
function mcpServerBlock(serverName, scriptPath) {
|
|
195
|
-
return [
|
|
196
|
-
` ${serverName}:`,
|
|
197
|
-
" command: node",
|
|
198
|
-
" args:",
|
|
199
|
-
` - ${yamlScalar(scriptPath)}`,
|
|
200
|
-
" enabled: true",
|
|
201
|
-
].join("\n");
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function wireMcpIntoConfig(configPath, serverName, scriptPath) {
|
|
205
|
-
const entry = mcpServerBlock(serverName, scriptPath);
|
|
206
|
-
if (!fs.existsSync(configPath)) {
|
|
207
|
-
fs.writeFileSync(configPath, `mcp_servers:\n${entry}\n`, "utf8");
|
|
208
|
-
return "created";
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
let txt = fs.readFileSync(configPath, "utf8");
|
|
212
|
-
if (
|
|
213
|
-
txt.includes(scriptPath) &&
|
|
214
|
-
new RegExp(`^\\s*${serverName}:\\s*$`, "m").test(txt)
|
|
215
|
-
) {
|
|
216
|
-
return "present";
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Replace an existing server block of the same name (simple indented map).
|
|
220
|
-
const serverRe = new RegExp(
|
|
221
|
-
`^([ \\t]*)${serverName}:\\s*\\n(?:\\1[ \\t]+.*\\n)*`,
|
|
222
|
-
"m",
|
|
223
|
-
);
|
|
224
|
-
if (serverRe.test(txt)) {
|
|
225
|
-
txt = txt.replace(serverRe, `${entry}\n`);
|
|
226
|
-
fs.writeFileSync(configPath, txt, "utf8");
|
|
227
|
-
return "updated";
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
if (/^mcp_servers:\s*$/m.test(txt) || /^mcp_servers:\s*\n/m.test(txt)) {
|
|
231
|
-
txt = txt.replace(/^(mcp_servers:\s*\n)/m, `$1${entry}\n`);
|
|
232
|
-
} else if (/^_config_version:.*$/m.test(txt)) {
|
|
233
|
-
txt = txt.replace(
|
|
234
|
-
/^(_config_version:.*\n)/m,
|
|
235
|
-
`$1mcp_servers:\n${entry}\n`,
|
|
236
|
-
);
|
|
237
|
-
} else {
|
|
238
|
-
txt = `mcp_servers:\n${entry}\n${txt}`;
|
|
239
|
-
}
|
|
240
|
-
fs.writeFileSync(configPath, txt, "utf8");
|
|
241
|
-
return "wired";
|
|
242
|
-
}
|
|
243
|
-
|
|
244
179
|
// ---------------------------------------------------------------- main
|
|
245
180
|
|
|
246
181
|
const schema = loadSchema();
|
|
@@ -428,40 +363,35 @@ for (const def of profiles) {
|
|
|
428
363
|
}
|
|
429
364
|
}
|
|
430
365
|
|
|
431
|
-
// MCP:
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
`${how}: ${path.relative(os.homedir(), configPath)}`,
|
|
454
|
-
);
|
|
455
|
-
} catch (err) {
|
|
456
|
-
record("mcp note", `could not write ${configPath}: ${err.message}`);
|
|
457
|
-
mcpManual.push({ lane: def.id, server: m, command: manual });
|
|
458
|
-
}
|
|
366
|
+
// MCP: the read plane. This is the one step that genuinely needs the CLI, since
|
|
367
|
+
// it edits the profile's own config. Without it, print the command instead.
|
|
368
|
+
for (const m of def.mcp || []) {
|
|
369
|
+
const cmd = path.join(ROOT, "bin", "oracle-data-mcp.mjs");
|
|
370
|
+
if (!hermes) {
|
|
371
|
+
record("mcp manual", `hermes -p ${def.id} mcp add ${m} --command "node ${cmd}"`);
|
|
372
|
+
mcpManual.push({ lane: def.id, server: m, command: `hermes -p ${def.id} mcp add ${m} --command "node ${cmd}"` });
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
record("wire mcp", `${m} (${def.id})`);
|
|
376
|
+
if (APPLY && m === "oracle-data") {
|
|
377
|
+
try {
|
|
378
|
+
execFileSync(
|
|
379
|
+
"hermes",
|
|
380
|
+
["-p", def.id, "mcp", "add", "oracle-data", "--command", `node ${cmd}`],
|
|
381
|
+
{ stdio: "pipe", timeout: 60_000 },
|
|
382
|
+
);
|
|
383
|
+
} catch {
|
|
384
|
+
// Already registered, or this Hermes build wants different flags. Not fatal:
|
|
385
|
+
// the profile is usable, it just needs the MCP wired by hand.
|
|
386
|
+
record("mcp note", `could not auto-wire ${m} for ${def.id}; add it manually`);
|
|
387
|
+
mcpManual.push({ lane: def.id, server: m, command: `hermes -p ${def.id} mcp add ${m} --command "node ${cmd}"` });
|
|
459
388
|
}
|
|
460
389
|
}
|
|
461
|
-
|
|
462
|
-
record("posture", `DISARMED (${(def.posture.grantActions || []).join(", ")})`);
|
|
463
390
|
}
|
|
464
391
|
|
|
392
|
+
record("posture", `DISARMED (${(def.posture.grantActions || []).join(", ")})`);
|
|
393
|
+
}
|
|
394
|
+
|
|
465
395
|
const summary = {
|
|
466
396
|
ok: true,
|
|
467
397
|
applied: APPLY,
|
|
@@ -484,13 +414,10 @@ if (JSON_OUT) {
|
|
|
484
414
|
log("pass --force to overwrite (a timestamped .bak is written first).");
|
|
485
415
|
}
|
|
486
416
|
if (mcpManual.length) {
|
|
487
|
-
log("\nMCP wiring
|
|
417
|
+
log("\nMCP wiring needs the hermes CLI. Run these when it is available:");
|
|
488
418
|
for (const m of mcpManual) log(` ${m.command}`);
|
|
489
419
|
}
|
|
490
420
|
if (!APPLY) log("re-run with --apply to make changes.");
|
|
491
|
-
log("\nEvery lane is DISARMED.
|
|
492
|
-
log(" npx oracle-data # 127.0.0.1:8787 — MCP tools need this");
|
|
493
|
-
log(" hermes -p oracle chat");
|
|
494
|
-
log("\nSet each lane's model in:");
|
|
421
|
+
log("\nEvery lane is DISARMED. Set each lane's model in:");
|
|
495
422
|
log(` ${path.join(hermesRoot(), "profiles", "<lane>", "config.yaml")}`);
|
|
496
423
|
}
|
package/docs/profiles.md
CHANGED
|
@@ -34,28 +34,19 @@ Three practical reasons, learned the hard way:
|
|
|
34
34
|
|
|
35
35
|
| Profile | Owns | Typical grant |
|
|
36
36
|
|---|---|---|
|
|
37
|
-
| `oracle` | routing, synthesis, multi-chain comparison
|
|
37
|
+
| `oracle` | routing, synthesis, multi-chain comparison | read + simulate only |
|
|
38
38
|
| `polymarket-agent` | prediction markets, event odds, CLOB cards/API-key order intents | read, quote, prepare |
|
|
39
39
|
| `hyperliquid-agent` | perps, spot, HIP-3 builder dexs, HIP-4 outcomes | read, quote, prepare |
|
|
40
40
|
| `robinhood-agent` | Robinhood Chain (4663) tokens, NFTs, tokenized Robinhood-style assets, capped NFT mints | read, quote, prepare |
|
|
41
41
|
| `solana-agent` | Solana swaps, research, Jupiter routes | read, quote, prepare |
|
|
42
42
|
| `bitcoin-agent` | Bitcoin L1, Ordinals/runes, inscriptions | read, prepare:inscription |
|
|
43
43
|
| `stable-agent` | Stable (988), USDT-native gas quirks | read, quote, prepare |
|
|
44
|
-
| `protocol-builder` | scaffold, review, prepare
|
|
44
|
+
| `protocol-builder` | scaffold, review, prepare protocol/NFT/gacha/DEX deploys and mint bots | prepare:deploy, prepare:mint, simulate |
|
|
45
45
|
| `_template` | your new lane | you decide |
|
|
46
46
|
|
|
47
|
-
`protocol-builder`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
metadata, liquidity, mint, and authority actions as separate user approvals.
|
|
51
|
-
|
|
52
|
-
The root `oracle` lane owns `/balance`, natural-language balance, and portfolio
|
|
53
|
-
history requests. Its `balance` skill calls the read-only
|
|
54
|
-
`portfolio_snapshot` MCP tool once, records a compact profile-local observation,
|
|
55
|
-
reports partial coverage and unavailable providers, and labels `knownUsd` as
|
|
56
|
-
incomplete instead of inventing a full portfolio total. `portfolio_history`
|
|
57
|
-
reads those observations and `portfolio_value_graph` renders the known-value
|
|
58
|
-
series while omitting unavailable values rather than plotting fake zeroes.
|
|
47
|
+
`protocol-builder` can design a protocol and prepare an unsigned deploy or mint
|
|
48
|
+
bot transaction. It never house-signs, and its destinations and gas-war caps are
|
|
49
|
+
allowlisted like any other lane.
|
|
59
50
|
|
|
60
51
|
## Model choice is yours
|
|
61
52
|
|
|
@@ -110,21 +101,10 @@ hermes profile create polymarket-agent
|
|
|
110
101
|
```
|
|
111
102
|
|
|
112
103
|
Then give it a `SOUL.md` (who it is, what it owns, what it must refuse) and a
|
|
113
|
-
`config.yaml` (model + provider). Point it at Oracle's MCP read plane
|
|
114
|
-
|
|
115
|
-
`oracle-init --apply` writes this for you. Manual form (Hermes wants command and
|
|
116
|
-
args as separate tokens):
|
|
104
|
+
`config.yaml` (model + provider). Point it at Oracle's MCP read plane:
|
|
117
105
|
|
|
118
106
|
```bash
|
|
119
|
-
|
|
120
|
-
npx oracle-data
|
|
121
|
-
|
|
122
|
-
# terminal 2 — wire MCP into a lane
|
|
123
|
-
hermes -p polymarket-agent mcp add oracle-data \
|
|
124
|
-
--command node \
|
|
125
|
-
--args "$(node -p "require.resolve('@oracle-agent/oracle/package.json').replace(/package\\.json$/, 'bin/oracle-data-mcp.mjs')")"
|
|
126
|
-
# or after npm link / PATH has the bin:
|
|
127
|
-
# hermes -p polymarket-agent mcp add oracle-data --command oracle-data-mcp
|
|
107
|
+
hermes mcp add oracle-data --command "oracle-data-mcp"
|
|
128
108
|
```
|
|
129
109
|
|
|
130
110
|
Now that lane can read 30+ providers across 11 chains, quote real routes, and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oracle-agent/oracle",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"description": "Oracle: prepare-only multichain agent control plane. Policy-bounded intents for a user-signed wallet. Self-custody by default — the public package never takes your key. Built for Hermes; no model key required.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -38,15 +38,8 @@ Terse. Answer first, evidence second. State confidence: `high` / `moderate` /
|
|
|
38
38
|
## Wiring it up
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
# preferred: installer writes SOUL, skills, and MCP config
|
|
42
|
-
npx oracle-init --apply
|
|
43
|
-
|
|
44
|
-
# or by hand
|
|
45
41
|
hermes profile create my-lane
|
|
46
|
-
|
|
47
|
-
hermes -p my-lane mcp add oracle-data --command oracle-data-mcp
|
|
48
|
-
# if the bin is not on PATH:
|
|
49
|
-
# hermes -p my-lane mcp add oracle-data --command node --args /abs/path/to/oracle-data-mcp.mjs
|
|
42
|
+
hermes mcp add oracle-data --command "oracle-data-mcp"
|
|
50
43
|
```
|
|
51
44
|
|
|
52
45
|
Then copy this `SOUL.md` into `~/.hermes/profiles/my-lane/SOUL.md` and set the
|
package/profiles/oracle/SOUL.md
CHANGED
|
@@ -20,11 +20,9 @@ value yourself.
|
|
|
20
20
|
| Stable (988), USDT-native gas | `stable-agent` |
|
|
21
21
|
| tokenized Robinhood-style assets / stock tokens | exact home-chain lane + `oracle-rfq-tokenized-assets` |
|
|
22
22
|
| meme-token launches, sniping, liquidity/pool watches | token's home-chain lane + `oracle-meme-token-sniper` |
|
|
23
|
-
|
|
|
24
|
-
| deploy/review custom contracts, gacha, DEX, launchpad, or capped NFT mint bot | `protocol-builder` + `oracle-nft-mint-gas-war` |
|
|
23
|
+
| deploy/review a contract, NFT/gacha launch, DEX, or capped NFT mint bot | `protocol-builder` + `oracle-nft-mint-gas-war` |
|
|
25
24
|
| RFQ / solver-intent route comparison across chains | `oracle` + `oracle-rfq-tokenized-assets` |
|
|
26
25
|
| graph/card alert rendering | token's home-chain lane + `oracle-chain-graphs-telegram-cards` |
|
|
27
|
-
| `/balance`, balance, holdings, wallet portfolio | `oracle` + `balance`; one deterministic `portfolio_snapshot` read plus profile-local observation |
|
|
28
26
|
| compare chains, "which is cheaper" | you, using the data plane |
|
|
29
27
|
|
|
30
28
|
If the chain is ambiguous, resolve the token's home chain first (DexScreener via
|
|
@@ -55,11 +53,6 @@ the data plane). If it stays ambiguous, ask. Do not guess a chain.
|
|
|
55
53
|
delta → the action did not succeed. Say so plainly.
|
|
56
54
|
7. **Never invent chain facts.** If it did not come from a live read, label it
|
|
57
55
|
`unknown`.
|
|
58
|
-
8. **Balance uses one source of truth.** `/balance` and plain-language balance
|
|
59
|
-
requests call `portfolio_snapshot`; use `portfolio_history` and
|
|
60
|
-
`portfolio_value_graph` for historical requests. Report `knownUsd` as
|
|
61
|
-
incomplete whenever a provider, address, price, token/NFT indexer, or chain
|
|
62
|
-
adapter is missing. Never turn an unavailable historical value into zero.
|
|
63
56
|
|
|
64
57
|
## Confidence
|
|
65
58
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"label": "oracle",
|
|
5
5
|
"role": "router",
|
|
6
6
|
"color": "#7CC4FF",
|
|
7
|
-
"description": "Router for multichain trading, building, analysis,
|
|
7
|
+
"description": "Router for multichain trading, building, analysis, scanners, RFQ, tokenized-asset buys, NFT mint gas limits, meme-token sniping, Solana, Bitcoin, and protocol launches.",
|
|
8
8
|
"model": {
|
|
9
9
|
"note": "Wants the strongest reasoner available: routing and synthesis are judgment calls.",
|
|
10
10
|
"suggested": "strong-reasoner"
|
|
@@ -18,10 +18,7 @@
|
|
|
18
18
|
"oracle-meme-token-sniper",
|
|
19
19
|
"oracle-chain-graphs-telegram-cards",
|
|
20
20
|
"oracle-rfq-tokenized-assets",
|
|
21
|
-
"oracle-nft-mint-gas-war"
|
|
22
|
-
"oracle-multichain-token-launch",
|
|
23
|
-
"oracle-multichain-nft-launch",
|
|
24
|
-
"balance"
|
|
21
|
+
"oracle-nft-mint-gas-war"
|
|
25
22
|
],
|
|
26
23
|
"mcp": [
|
|
27
24
|
"oracle-data"
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
# protocol builder
|
|
2
2
|
|
|
3
|
-
You
|
|
4
|
-
|
|
5
|
-
pages, and scanner-backed on-chain apps. You never sign one. Unsupported chain
|
|
6
|
-
adapters fail closed.
|
|
3
|
+
You design, review, and prepare deploys for protocols, NFT/gacha products, DEX
|
|
4
|
+
surfaces, launchpads, mint pages, and scanner-backed on-chain apps. You never sign one.
|
|
7
5
|
|
|
8
6
|
## What you own
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
protocols before cloning them.
|
|
8
|
+
Contract scaffolding, NFT/gacha mint mechanics, DEX/pool/launchpad design,
|
|
9
|
+
security review, deploy and verify scripts, and **unsigned** deploy transactions.
|
|
10
|
+
Research of existing protocols before cloning them.
|
|
14
11
|
|
|
15
12
|
## Deployment is permanent
|
|
16
13
|
|
|
@@ -45,11 +42,7 @@ what an attacker gains from each privileged function.
|
|
|
45
42
|
3. **Simulate before preparing.** An unsimulated deploy is a guess.
|
|
46
43
|
4. **State the authority model before the code.** A user who doesn't know who owns
|
|
47
44
|
the contract cannot consent to deploying it.
|
|
48
|
-
5. **Receipts or it didn't happen
|
|
49
|
-
6. **Chain-family support is explicit.** Use `TEMPLATE_READY`, `ADAPTER_READY`,
|
|
50
|
-
`GUIDED_BUILD`, `RESEARCH_ONLY`, or `UNSUPPORTED`. RPC reachability is not deploy support.
|
|
51
|
-
7. **One approval per side effect.** Deploy, metadata upload, mint, liquidity,
|
|
52
|
-
authority transfer/revoke, reveal, and verification remain separate.
|
|
45
|
+
5. **Receipts or it didn't happen** — deployed address, receipt, verified source.
|
|
53
46
|
|
|
54
47
|
## Voice
|
|
55
48
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"label": "protocol builder",
|
|
5
5
|
"role": "builder",
|
|
6
6
|
"color": "#ff8c5a",
|
|
7
|
-
"description": "Builder lane for protocol,
|
|
7
|
+
"description": "Builder lane for protocol, NFT/gacha, DEX, scanner, and mint-bot surfaces with unsigned deploy/mint preparation.",
|
|
8
8
|
"model": {
|
|
9
9
|
"note": "Contract review is unforgiving and mistakes are permanent; wants the strongest reasoner available.",
|
|
10
10
|
"suggested": "strong-reasoner"
|
|
@@ -13,8 +13,6 @@
|
|
|
13
13
|
"oracle-protocol-builder",
|
|
14
14
|
"oracle-contract-research",
|
|
15
15
|
"oracle-protocol-security",
|
|
16
|
-
"oracle-multichain-token-launch",
|
|
17
|
-
"oracle-multichain-nft-launch",
|
|
18
16
|
"oracle-nft-gacha-launch",
|
|
19
17
|
"oracle-dex-launch",
|
|
20
18
|
"oracle-receipts",
|