@oracle-agent/oracle 0.4.1 → 0.5.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 (80) hide show
  1. package/README.md +74 -20
  2. package/SETUP.md +15 -2
  3. package/bin/oracle-data-mcp.mjs +1 -1
  4. package/bin/oracle.mjs +33 -0
  5. package/docs/cli.md +19 -0
  6. package/docs/connectors.md +13 -0
  7. package/docs/oracle-pack-standard.md +29 -0
  8. package/docs/profiles.md +1 -1
  9. package/examples/oracle-pack-template.mjs +38 -0
  10. package/package.json +13 -4
  11. package/profiles/oracle/SOUL.md +3 -1
  12. package/profiles/robinhood-agent/SOUL.md +5 -3
  13. package/public/agent-connect/app.js +84 -0
  14. package/public/agent-connect/index.html +83 -0
  15. package/public/agent-connect/styles.css +70 -0
  16. package/public/oracle-splash/assets/wordmarks/across.svg +4 -0
  17. package/public/oracle-splash/assets/wordmarks/aerodrome.svg +23 -0
  18. package/public/oracle-splash/assets/wordmarks/balancer.svg +3 -0
  19. package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -0
  20. package/public/oracle-splash/assets/wordmarks/gmx.svg +13 -0
  21. package/public/oracle-splash/assets/wordmarks/hyperliquid.svg +21 -0
  22. package/public/oracle-splash/assets/wordmarks/hyperswap.svg +13 -0
  23. package/public/oracle-splash/assets/wordmarks/jupiter.svg +35 -0
  24. package/public/oracle-splash/assets/wordmarks/lifi.png +0 -0
  25. package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -0
  26. package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -0
  27. package/public/oracle-splash/assets/wordmarks/odos.svg +3 -0
  28. package/public/oracle-splash/assets/wordmarks/oneinch.svg +6 -0
  29. package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -0
  30. package/public/oracle-splash/assets/wordmarks/pancakeswap.svg +18 -0
  31. package/public/oracle-splash/assets/wordmarks/paraswap.svg +16 -0
  32. package/public/oracle-splash/assets/wordmarks/pendle.png +0 -0
  33. package/public/oracle-splash/assets/wordmarks/polymarket.png +0 -0
  34. package/public/oracle-splash/assets/wordmarks/quickswap.png +0 -0
  35. package/public/oracle-splash/assets/wordmarks/relay.svg +8 -0
  36. package/public/oracle-splash/assets/wordmarks/stargate.svg +15 -0
  37. package/public/oracle-splash/assets/wordmarks/uniswap.svg +18 -0
  38. package/public/oracle-splash/assets/wordmarks/velodrome.svg +84 -0
  39. package/public/oracle-splash/index.html +789 -485
  40. package/scripts/adversarial-bench.mjs +114 -0
  41. package/scripts/check-doc-drift.mjs +111 -0
  42. package/skills/oracle-action-semantics/SKILL.md +1 -1
  43. package/src/action-receipts.mjs +168 -0
  44. package/src/address-book.mjs +53 -5
  45. package/src/cli/commands/credential.mjs +9 -0
  46. package/src/cli/commands/data-mcp.mjs +18 -0
  47. package/src/cli/commands/data.mjs +73 -0
  48. package/src/cli/commands/doctor.mjs +131 -0
  49. package/src/cli/commands/help.mjs +7 -0
  50. package/src/cli/commands/init.mjs +27 -0
  51. package/src/cli/commands/mcp.mjs +142 -0
  52. package/src/cli/commands/prepare.mjs +12 -0
  53. package/src/cli/commands/public.mjs +20 -0
  54. package/src/cli/commands/route.mjs +12 -0
  55. package/src/cli/commands/runner.mjs +9 -0
  56. package/src/cli/commands/scan.mjs +12 -0
  57. package/src/cli/commands/sign.mjs +21 -0
  58. package/src/cli/commands/signer.mjs +9 -0
  59. package/src/cli/commands/upgrade.mjs +12 -0
  60. package/src/cli/commands/vault.mjs +9 -0
  61. package/src/cli/commands/version.mjs +22 -0
  62. package/src/cli/first-run.mjs +20 -0
  63. package/src/cli/kernel.mjs +198 -0
  64. package/src/cli/mcp-targets/chatgpt.mjs +51 -0
  65. package/src/cli/mcp-targets/claude-code.mjs +39 -0
  66. package/src/cli/mcp-targets/claude-desktop.mjs +24 -0
  67. package/src/cli/mcp-targets/codex.mjs +41 -0
  68. package/src/cli/mcp-targets/shared.mjs +61 -0
  69. package/src/cli/operator-dispatch.mjs +258 -0
  70. package/src/cli/paths.mjs +78 -0
  71. package/src/cli/spawn-child.mjs +43 -0
  72. package/src/exec-policy.mjs +6 -0
  73. package/src/index.mjs +24 -0
  74. package/src/onboarding/harness-configs.mjs +102 -0
  75. package/src/oracle-env.mjs +11 -2
  76. package/src/portfolio-risk.mjs +170 -0
  77. package/src/public-api/connect-agent.mjs +29 -10
  78. package/src/signals/engine.mjs +146 -0
  79. package/src/signals/index.mjs +1 -0
  80. package/src/watch-preferences.mjs +85 -0
package/README.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Oracle
2
2
 
3
+ ## Quickstart (unified CLI)
4
+
5
+ ```bash
6
+ npm i -g @oracle-agent/oracle
7
+ oracle init --apply # lanes + read plane only, no keys
8
+ oracle data serve # loopback read/prepare plane on 127.0.0.1:8787
9
+ oracle doctor # verify
10
+ # optional, explicit second step — signing stays a separate local package:
11
+ npm i -g @oracle-agent/operator
12
+ oracle sign init
13
+ ```
14
+
15
+
3
16
  **Prepare-only multichain agent control plane.** Policy-bounded intents; your wallet signs.
4
17
 
5
18
  Specialist agent profiles, real protocol intents, self-custody by default,
@@ -20,13 +33,31 @@ alongside it — same split we run ourselves.
20
33
 
21
34
  ## Start in 5 steps
22
35
 
23
- Latest: **oracle `0.3.6`** · **operator `0.6.1`**
36
+ Source tree: **oracle `0.5.0`** · **operator `0.14.0`**
37
+
38
+ Published npm: **oracle `0.4.2`** · **operator `0.13.7`** until this source release is published.
24
39
 
25
40
  ```bash
26
- # 1) install both packages
27
- npm i @oracle-agent/oracle@0.3.6 @oracle-agent/operator@0.6.1
41
+ # 1) install Oracle's public prepare plane
42
+ npm i @oracle-agent/oracle@latest
43
+ ```
28
44
 
29
- # 2) put keys ONLY on your machine (example: HL/EVM hex key file)
45
+ ```js
46
+ // 2) prepare an artifact (no keys)
47
+ import { data } from "@oracle-agent/oracle";
48
+ const prepared = await data.call("hl-perps", "prepareOrder", { /* coin, side, size... */ });
49
+ ```
50
+
51
+ **Path A — self-custody first:** review the prepared artifact and sign it with
52
+ the owner/main wallet, browser wallet, smart account, hardware wallet, or
53
+ protocol-native wallet. Oracle's public package stops at prepare: your wallet
54
+ authorizes and broadcasts.
55
+
56
+ ```bash
57
+ # 3) optional owner-local operator package for unattended signing on YOUR machine
58
+ npm i @oracle-agent/operator@latest
59
+
60
+ # 4) put operator keys ONLY on your machine (example: HL/EVM hex key file)
30
61
  mkdir -p ~/.config/oracle/keys && chmod 700 ~/.config/oracle/keys
31
62
  # write key, then: npx oracle-vault encrypt ~/.config/oracle/keys/evm.key
32
63
  export HL_KEY_FILE=~/.config/oracle/keys/evm.key.vault.json
@@ -34,24 +65,29 @@ export ORACLE_VAULT_PASSPHRASE='...' # signer shell only — never in the agen
34
65
  ```
35
66
 
36
67
  ```js
37
- // 3) prepare (no keys)
38
- import { data } from "@oracle-agent/oracle";
39
- const prepared = await data.call("hl-perps", "prepareOrder", { /* coin, side, size... */ });
40
-
41
- // 4) keys local → operator signs (this is the sign step — no MetaMask)
68
+ // Path B owner-local operator key signs after your app confirms the action
69
+ // (same host, your key, your policy; no model or remote agent custody)
42
70
  import { hlSignAndSubmit } from "@oracle-agent/operator";
43
71
  await hlSignAndSubmit(prepared, {
44
72
  keyFile: process.env.HL_KEY_FILE,
45
- userInitiated: true, // app confirmed the action; or use autonomous/daemon below
73
+ userInitiated: true,
46
74
  });
47
75
  ```
48
76
 
49
77
  ```bash
50
- # 5) unattended desk (no click each trade) HL/Poly capped
51
- export ORACLE_AUTONOMOUS_TRADING=1
52
- # or: npx oracle-signer
78
+ # 5) recommended agent-process path: run the signer daemon so the agent sees
79
+ # only ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN, never the vault passphrase.
80
+ npx oracle-signer
81
+ #
82
+ # Daemon signing requires the SAME HMAC secret in the preparer and the signer,
83
+ # otherwise every sign fails with "ORACLE_STAMP_HMAC_SECRET missing in signer":
84
+ export ORACLE_STAMP_HMAC_SECRET='long-random-secret'
53
85
  ```
54
86
 
87
+ `ORACLE_AUTONOMOUS_TRADING=1` is only for trusted, owner-controlled direct-exec
88
+ code running locally with your policy and caps. It is not a permission bit for a
89
+ model or remote agent process; use `oracle-signer` for the agent-facing path.
90
+
55
91
  Full vault / multi-chain / daemon detail → operator [SETUP](https://github.com/demi-hl/oracle-operator/blob/main/SETUP.md).
56
92
 
57
93
  ---
@@ -255,16 +291,33 @@ owner-local source lane.** The short version:
255
291
  - Reads and quotes need **no keys**.
256
292
  - The public package exposes no signer, key vault, or broadcast path.
257
293
  - User wallets authorize prepared actions outside the public data plane.
258
- - Owner-local signing is shipped separately as `@oracle-agent/operator`; its agent-facing daemon supports only policy-bounded Hyperliquid and Polymarket execution.
294
+ - Owner-local signing is shipped separately as `@oracle-agent/operator`; the
295
+ recommended agent-process path is `oracle-signer`. Its daemon exposes six
296
+ policy-bounded surfaces: `hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, and
297
+ `sol`, with explicit caps and fail-closed allowlists.
259
298
 
260
299
  ### Action vocabulary and execution planes
261
300
 
262
301
  Oracle keeps capability and authorization separate:
263
302
 
264
303
  - Public Oracle reads, quotes, simulates, and prepares unsigned artifacts.
265
- - The generic unattended signer remains limited to `hl` and `poly`.
266
- - Ordinary EVM preparation remains user-wallet signed.
267
- - A deployment may separately install a same-host, owner-gated EVM executor. Oracle must verify that executor before describing bounded EVM execution as available. Missing deployment capability means "unavailable here," not "Oracle can never execute EVM."
304
+ - **Path A:** owner/main, browser, smart-account, hardware, or protocol-native
305
+ wallets sign the prepared artifact. This is the default self-custody path.
306
+ - **Path B:** owner-local operator infrastructure may sign on the same host with
307
+ your key and your policy. For agent processes, prefer `oracle-signer` so the
308
+ agent receives only a signer URL/token and never the vault passphrase.
309
+ - The generic unattended signer exposes six bounded surfaces: `hl`, `poly`,
310
+ `evm-swap`, `evm-bridge`, `btc`, `sol`. Each surface decodes its own
311
+ envelope, enforces its caps, and refuses while its allowlists are empty.
312
+ - Ordinary EVM preparation remains user-wallet signed unless a trusted
313
+ owner-controlled direct-exec process is explicitly installed and armed.
314
+ - `ORACLE_AUTONOMOUS_TRADING=1` is direct execution for trusted owner-controlled
315
+ local code only. It is never model/agent authority and should not be framed as
316
+ equivalent to the `oracle-signer` agent-process path.
317
+ - A deployment may separately install a same-host, owner-gated EVM executor.
318
+ Oracle must verify that executor before describing bounded EVM execution as
319
+ available. Missing deployment capability means "unavailable here," not
320
+ "Oracle can never execute EVM."
268
321
  - `watch`, `watch this`, and `ping me` always create `active: true, actionMode: alert_only`.
269
322
  - `arm` creates `active: true, actionMode: execute` only for one exact owner-authorized action. It is never inferred from a watch.
270
323
 
@@ -408,8 +461,9 @@ it — verified in practice when Odos sunset their public API mid-development
408
461
  ## Examples
409
462
 
410
463
  ```bash
411
- node examples/add-a-chain.mjs # register an unseen chain, no code
412
- node examples/research-a-token.mjs # honest token research on live data
464
+ node examples/add-a-chain.mjs # register an unseen chain, no code
465
+ node examples/research-a-token.mjs # honest token research on live data
466
+ node examples/oracle-pack-template.mjs # skeleton for a safe Oracle protocol pack
413
467
  ```
414
468
 
415
469
  ## MCP
@@ -449,7 +503,7 @@ don't imply endorsement by an official deployment when shipping a fork.
449
503
  Prefer the local signer daemon so the agent never sees the vault passphrase:
450
504
 
451
505
  ```bash
452
- npx oracle-signer # has ORACLE_VAULT_PASSPHRASE
506
+ npx oracle-signer # reads the passphrase from the OS credential store
453
507
  # agent: ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN only
454
508
  ```
455
509
 
package/SETUP.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Setup
2
2
 
3
+ ## Unified CLI
4
+
5
+ Prefer the root `oracle` command:
6
+
7
+ ```bash
8
+ npm i -g @oracle-agent/oracle
9
+ oracle init --apply
10
+ oracle doctor
11
+ ```
12
+
13
+ Full reference: [docs/cli.md](./docs/cli.md). Connectors: [docs/connectors.md](./docs/connectors.md).
14
+
15
+
3
16
  Oracle's public surface runs locally against your API accounts and never accepts
4
17
  a wallet private key. Prepared actions are signed in the user's wallet.
5
18
 
@@ -45,7 +58,7 @@ The public Oracle profile must report these as separate planes:
45
58
  | Plane | Default capability |
46
59
  |---|---|
47
60
  | Public Oracle package | read, quote, simulate, unsigned prepare |
48
- | Generic `oracle-signer` daemon | policy-bounded `hl` and `poly` only |
61
+ | Generic `oracle-signer` daemon | six bounded surfaces: `hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, `sol` (each fails closed on empty allowlists) |
49
62
  | Ordinary EVM | unsigned preparation, user-wallet signature |
50
63
  | Optional owner-gated EVM executor | one exact bounded action after explicit `arm` |
51
64
 
@@ -302,7 +315,7 @@ router that knows which brain to use for which job.
302
315
  Prefer the local signer daemon so the agent never sees the vault passphrase:
303
316
 
304
317
  ```bash
305
- npx oracle-signer # has ORACLE_VAULT_PASSPHRASE
318
+ npx oracle-signer # reads the passphrase from the OS credential store
306
319
  # agent: ORACLE_SIGNER_URL + ORACLE_SIGNER_TOKEN only
307
320
  ```
308
321
 
@@ -552,7 +552,7 @@ const tools = [
552
552
  required: ["address", "label"],
553
553
  properties: {
554
554
  address: { type: "string", description: "0x address" },
555
- label: { type: "string", description: "short name, e.g. carlo-agent" },
555
+ label: { type: "string", description: "short name, e.g. research-agent" },
556
556
  who: { type: "string", description: "person or entity the wallet belongs to" },
557
557
  role: { type: "string", description: "agent | owner | person | counterparty | venue" },
558
558
  chainIds: { type: "array", items: { type: "number" } },
package/bin/oracle.mjs ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { realpathSync } from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+ import { run } from "../src/cli/kernel.mjs";
6
+
7
+ export const COMMANDS = Object.freeze({
8
+ data: "./desk-server.mjs",
9
+ public: "./oracle-public-server.mjs",
10
+ "data-mcp": "./oracle-data-mcp.mjs",
11
+ init: "./oracle-init.mjs",
12
+ upgrade: "./oracle-upgrade.mjs",
13
+ scan: "./oracle-scan.mjs",
14
+ route: "./oracle-route.mjs",
15
+ });
16
+
17
+ function isMainModule() {
18
+ if (!process.argv[1]) return false;
19
+ try {
20
+ return realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]);
21
+ } catch {
22
+ return false;
23
+ }
24
+ }
25
+
26
+ export async function main(argv = process.argv.slice(2)) {
27
+ return run(argv);
28
+ }
29
+
30
+ if (isMainModule()) {
31
+ const code = await main();
32
+ process.exit(typeof code === "number" ? code : 0);
33
+ }
package/docs/cli.md ADDED
@@ -0,0 +1,19 @@
1
+ # Oracle unified CLI
2
+
3
+ Root command: `oracle <noun> <verb> [args]`.
4
+
5
+ The public `@oracle-agent/oracle` package is **prepare-only**. Signing commands
6
+ dispatch to a separately installed `@oracle-agent/operator` process on the same
7
+ machine. Oracle never imports operator signing modules.
8
+
9
+ See also [connectors.md](./connectors.md).
10
+
11
+ ## Exit codes
12
+
13
+ | Code | Meaning |
14
+ |---|---|
15
+ | 0 | ok |
16
+ | 1 | usage / general error |
17
+ | 2 | operator self-reported error |
18
+ | 3 | operator package not installed |
19
+ | 4 | data server not running |
@@ -0,0 +1,13 @@
1
+ # Oracle AI-client connectors
2
+
3
+ ChatGPT is hosted and can NEVER sign or reach your keys. This connector is read/prepare only; anything it prepares is unsigned until you sign it locally.
4
+
5
+ ```bash
6
+ oracle mcp print --target claude-code
7
+ oracle mcp install claude-code
8
+ oracle mcp install codex
9
+ oracle mcp install chatgpt
10
+ oracle mcp install claude-code --with-control # requires local operator
11
+ ```
12
+
13
+ Oracle does not create tunnels for hosted clients.
@@ -0,0 +1,29 @@
1
+ # Oracle protocol pack standard
2
+
3
+ An Oracle protocol pack is a package-safe ESM module that turns an intent into an unsigned action and decodes independently obtained receipts. A pack is an adapter, not a wallet, signer, broadcaster, or authority. See `examples/oracle-pack-template.mjs` for the smallest complete shape.
4
+
5
+ ## Required surface
6
+
7
+ Every pack exports a default object with these members (named exports may mirror them):
8
+
9
+ - `provider`: stable provider identity, semantic version, supported chain IDs, and provenance/trust metadata. Remote token names, symbols, descriptions, image fields, URLs, and NFT metadata remain untrusted data.
10
+ - `prepare(intent)`: validates the intent and returns an unsigned transaction or typed action. It must not accept keys, sign, submit, broadcast, or report execution success.
11
+ - `decode(receipt)`: validates and converts a chain/provider receipt into a documented result. Unknown or malformed receipts fail closed.
12
+ - `riskRules`: an array or function describing enforceable limits and refusal conditions. Human-readable warnings alone are not rules.
13
+ - `tests`: non-empty metadata naming the local test command and covered properties. Tests must be deterministic and require no credentials or network.
14
+
15
+ ## Prompt-injection boundary
16
+
17
+ Treat every provider response and token/NFT metadata string as inert data. Never concatenate metadata into system/developer instructions, interpret it as tool directions, or let it modify recipients, calldata, limits, and policy. Render or quote it through a data channel and retain its provenance. Packs should test adversarial values such as “ignore previous instructions,” requests for secrets, and demands to sign or invoke tools.
18
+
19
+ ## Custody boundary
20
+
21
+ Pack exports must not expose signers, wallets, private keys, seed phrases, signing functions, transaction submission, or broadcasting. `prepare` returns data to a separately authorized custody surface. Environment variables and provider credentials must not appear in prepared output, logs, errors, fixtures, or metadata. Imports should be side-effect free; merely loading a pack must not make network calls.
22
+
23
+ ## Receipt gate
24
+
25
+ Preparation is not execution. A prepared result declares a `receiptGate` and consumers must not mark an action successful until `decode` receives a receipt from an independent, trusted transport and verifies its chain, transaction identity, status, and required confirmations. Timeouts, pending receipts, mismatches, reverts, and undecodable responses are not success.
26
+
27
+ ## Local adversarial benchmark
28
+
29
+ Run `node scripts/adversarial-bench.mjs <pack.mjs> [...]`. It imports only the named local modules, invokes no pack functions, emits one deterministic JSON summary, and exits `1` when a gate fails (`2` for usage/load errors). It checks required surface fields, forbidden custody exports, missing test metadata, and prompt-injection strings nested in provider or pack metadata. This static public gate complements, rather than replaces, behavioral tests of preparation and receipt verification.
package/docs/profiles.md CHANGED
@@ -44,7 +44,7 @@ Three practical reasons, learned the hard way:
44
44
  | `protocol-builder` | scaffold, review, prepare chain-family token/NFT collections, gacha, DEX, and protocol deploys | prepare:deploy, prepare:mint, simulate |
45
45
  | `_template` | your new lane | you decide |
46
46
 
47
- These grants describe the public prepare plane, not every capability an operator may install beside it. The generic unattended signer remains limited to `hl` and `poly`. A separately installed, same-host, owner-gated EVM executor may expose one exact bounded action after explicit `arm`; profiles must verify it before claiming availability. `watch`, `watch this`, and `ping me` remain `alert_only` regardless of executor presence.
47
+ These grants describe the public prepare plane, not every capability an operator may install beside it. The generic unattended signer exposes six bounded surfaces (`hl`, `poly`, `evm-swap`, `evm-bridge`, `btc`, `sol`), each of which decodes its own envelope and refuses while its allowlists are empty. A separately installed, same-host, owner-gated EVM executor may expose one exact bounded action after explicit `arm`; profiles must verify it before claiming availability. `watch`, `watch this`, and `ping me` remain `alert_only` regardless of executor presence.
48
48
 
49
49
  `protocol-builder` classifies each launch by chain family, then designs and
50
50
  prepares unsigned token, NFT collection, protocol, or mint-bot transactions. It
@@ -0,0 +1,38 @@
1
+ import assert from "node:assert/strict";
2
+
3
+ // Minimal Oracle protocol pack. It prepares unsigned actions; it never receives
4
+ // keys, signs, broadcasts, or claims that untrusted metadata is an instruction.
5
+
6
+ export const provider = Object.freeze({
7
+ id: "example-protocol",
8
+ version: "1.0.0",
9
+ chains: [8453],
10
+ metadata: { source: "on-chain", trust: "untrusted-data" },
11
+ });
12
+
13
+ export function prepare(intent) {
14
+ assert.ok(intent && provider.chains.includes(intent.chainId), "unsupported chain");
15
+ return {
16
+ kind: "unsigned-transaction",
17
+ chainId: intent.chainId,
18
+ transaction: { to: intent.to, data: intent.data ?? "0x", value: intent.value ?? "0" },
19
+ receiptGate: { required: true, confirmations: 1, match: ["chainId", "transaction.to"] },
20
+ };
21
+ }
22
+
23
+ export function decode(receipt) {
24
+ assert.ok(receipt && typeof receipt.status !== "undefined", "receipt required");
25
+ return { success: receipt.status === 1 || receipt.status === "0x1", transactionHash: receipt.transactionHash };
26
+ }
27
+
28
+ export const riskRules = Object.freeze([
29
+ { id: "explicit-recipient", field: "transaction.to", required: true },
30
+ { id: "receipt-before-success", field: "receiptGate.required", equals: true },
31
+ ]);
32
+
33
+ export const tests = Object.freeze({
34
+ command: "node --test test/oracle-pack-standard.test.mjs",
35
+ covers: ["prepare-is-unsigned", "decode-requires-receipt", "metadata-is-untrusted"],
36
+ });
37
+
38
+ export default Object.freeze({ provider, prepare, decode, riskRules, tests });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oracle-agent/oracle",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
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",
@@ -26,13 +26,15 @@
26
26
  "node": ">=20.19.0"
27
27
  },
28
28
  "bin": {
29
+ "oracle": "./bin/oracle.mjs",
29
30
  "oracle-data": "./bin/desk-server.mjs",
30
31
  "oracle-public": "./bin/oracle-public-server.mjs",
31
32
  "oracle-data-mcp": "./bin/oracle-data-mcp.mjs",
32
33
  "oracle-init": "./bin/oracle-init.mjs",
33
34
  "oracle-upgrade": "./bin/oracle-upgrade.mjs",
34
35
  "oracle-scan": "./bin/oracle-scan.mjs",
35
- "oracle-route": "./bin/oracle-route.mjs"
36
+ "oracle-route": "./bin/oracle-route.mjs",
37
+ "oracle": "./bin/oracle.mjs"
36
38
  },
37
39
  "exports": {
38
40
  ".": "./src/index.mjs",
@@ -44,7 +46,12 @@
44
46
  "./action-semantics": "./src/action-semantics.mjs",
45
47
  "./address-book": "./src/address-book.mjs",
46
48
  "./nft-gas-war": "./src/nft-gas-war-guard.mjs",
47
- "./prepare-envelope": "./src/prepare-envelope.mjs"
49
+ "./prepare-envelope": "./src/prepare-envelope.mjs",
50
+ "./connect": "./src/onboarding/harness-configs.mjs",
51
+ "./receipts": "./src/action-receipts.mjs",
52
+ "./risk": "./src/portfolio-risk.mjs",
53
+ "./watch": "./src/watch-preferences.mjs",
54
+ "./signals": "./src/signals/index.mjs"
48
55
  },
49
56
  "scripts": {
50
57
  "test": "ORACLE_TEST_ISOLATE_SECRETS=1 ORACLE_ROUTE_ATTESTATION_SECRET=oracle-unit-test-secret node --test test/*.test.mjs",
@@ -64,7 +71,9 @@
64
71
  "test:count": "node scripts/check-test-count.mjs",
65
72
  "test:count:update": "node scripts/check-test-count.mjs --update",
66
73
  "test:protocol-templates": "RUN_PROTOCOL_TEMPLATE_TESTS=1 node --test test/protocol-templates.test.mjs",
67
- "protocol:gate": "node scripts/protocol-template-gate.mjs"
74
+ "protocol:gate": "node scripts/protocol-template-gate.mjs",
75
+ "gate:docs": "node scripts/check-doc-drift.mjs",
76
+ "gate:release": "npm run gate:docs && node --test test/flag-polarity.test.mjs"
68
77
  },
69
78
  "dependencies": {
70
79
  "@msgpack/msgpack": "^3.1.3",
@@ -41,7 +41,9 @@ the data plane). If it stays ambiguous, ask. Do not guess a chain.
41
41
  1. **The public router never signs.** It prepares, simulates, and explains; ordinary
42
42
  EVM artifacts require the user's wallet signature. Do not turn that public-plane
43
43
  boundary into the false claim that EVM execution is universally impossible. The
44
- generic unattended signer remains limited to `hl` and `poly`; a deployment may
44
+ generic unattended signer exposes six bounded surfaces (`hl`, `poly`, `evm-swap`,
45
+ `evm-bridge`, `btc`, `sol`), each of which decodes its own envelope and refuses
46
+ while its allowlists are empty; a deployment may also
45
47
  separately expose a same-host, owner-gated EVM executor. Verify that executor
46
48
  before describing it as available.
47
49
  `watch`, `watch this`, and `ping me` always mean `actionMode: alert_only`.
@@ -35,9 +35,11 @@ that moves value.
35
35
  2. **Never size against stale or virtual reserves.**
36
36
  3. **A fuzzy ticker match is not confirmation** — surface the CA.
37
37
  4. **The public lane does not sign.** Ordinary swaps are prepared for the user's
38
- wallet. The generic unattended signer remains `hl`/`poly`; a separately installed,
39
- owner-gated EVM executor may handle one exact bounded Robinhood Chain action after
40
- explicit `arm`. Verify that executor before claiming it is available.
38
+ wallet. The generic unattended signer exposes six bounded surfaces (`hl`, `poly`,
39
+ `evm-swap`, `evm-bridge`, `btc`, `sol`), each fail-closed on its own policy. A
40
+ separately installed, owner-gated EVM executor may handle one exact bounded
41
+ Robinhood Chain action after explicit `arm`. Verify that executor before claiming
42
+ it is available.
41
43
  5. **Watch is alert-only.** `watch`, `watch this`, and `ping me` persist as
42
44
  `active: true, actionMode: alert_only`. Only explicit `arm` can produce
43
45
  `actionMode: execute`; never infer execution from a watch or legacy `status: armed`.
@@ -0,0 +1,84 @@
1
+ (() => {
2
+ "use strict";
3
+
4
+ const PACKAGE = "@oracle-agent/oracle";
5
+ const COMMAND = "npx";
6
+ const ARGS = ["-y", "--package", PACKAGE, "oracle-data-mcp"];
7
+ const INIT_COMMAND = "npx -y --package @oracle-agent/oracle oracle-init";
8
+
9
+ const apiUrl = document.querySelector("#api-url");
10
+ const apiKey = document.querySelector("#api-key");
11
+ const walletAddress = document.querySelector("#wallet-address");
12
+ const output = document.querySelector("#config-output");
13
+ const label = document.querySelector("#config-label");
14
+ const status = document.querySelector("#copy-status");
15
+ const tabs = [...document.querySelectorAll("[data-harness]")];
16
+ let selected = "hermes";
17
+
18
+ const cleanUrl = () => apiUrl.value.trim().replace(/\/+$/, "");
19
+ const env = () => {
20
+ const values = {
21
+ ORACLE_DATA_URL: cleanUrl() || "https://api.oracle-agent.dev",
22
+ ORACLE_AGENT_KEY: apiKey.value.trim() || "YOUR_AGENT_KEY"
23
+ };
24
+ if (walletAddress.value.trim()) values.ORACLE_WALLET_ADDRESS = walletAddress.value.trim();
25
+ return values;
26
+ };
27
+
28
+ const server = () => ({ command: COMMAND, args: [...ARGS], env: env() });
29
+
30
+ const configs = {
31
+ hermes: () => ({
32
+ mcpServers: { oracle: server() }
33
+ }),
34
+ claude: () => ({
35
+ mcpServers: { oracle: server() }
36
+ }),
37
+ codex: () => {
38
+ const values = env();
39
+ const lines = [
40
+ "[mcp_servers.oracle]",
41
+ `command = ${JSON.stringify(COMMAND)}`,
42
+ `args = [${ARGS.map((arg) => JSON.stringify(arg)).join(", ")}]`,
43
+ "",
44
+ "[mcp_servers.oracle.env]",
45
+ ...Object.entries(values).map(([key, value]) => `${key} = ${JSON.stringify(value)}`)
46
+ ];
47
+ return lines.join("\n");
48
+ },
49
+ cursor: () => ({
50
+ mcpServers: { oracle: server() }
51
+ }),
52
+ mcp: () => ({
53
+ mcpServers: { oracle: server() }
54
+ })
55
+ };
56
+
57
+ const names = { hermes: "Hermes", claude: "Claude Code", codex: "Codex", cursor: "Cursor", mcp: "Generic MCP" };
58
+
59
+ function render() {
60
+ const config = configs[selected]();
61
+ output.textContent = typeof config === "string" ? config : JSON.stringify(config, null, 2);
62
+ label.textContent = `${names[selected]} config`;
63
+ status.textContent = "";
64
+ }
65
+
66
+ async function copy(text, message) {
67
+ try {
68
+ await navigator.clipboard.writeText(text);
69
+ status.textContent = message;
70
+ } catch {
71
+ status.textContent = "Copy was blocked. Select the text and copy it manually.";
72
+ }
73
+ }
74
+
75
+ tabs.forEach((tab) => tab.addEventListener("click", () => {
76
+ selected = tab.dataset.harness;
77
+ tabs.forEach((item) => item.setAttribute("aria-selected", String(item === tab)));
78
+ render();
79
+ }));
80
+ [apiUrl, apiKey, walletAddress].forEach((input) => input.addEventListener("input", render));
81
+ document.querySelector("#copy-button").addEventListener("click", () => copy(output.textContent, `${names[selected]} config copied.`));
82
+ document.querySelector("#copy-install").addEventListener("click", () => copy(INIT_COMMAND, "Local operator install command copied."));
83
+ render();
84
+ })();
@@ -0,0 +1,83 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <meta name="description" content="Connect your agent harness to Oracle read tools without giving up custody." />
7
+ <title>Oracle Agent Connect</title>
8
+ <link rel="stylesheet" href="styles.css" />
9
+ </head>
10
+ <body>
11
+ <main class="shell">
12
+ <header class="hero">
13
+ <a class="wordmark" href="/">ORACLE</a>
14
+ <p class="eyebrow">AGENT CONNECT</p>
15
+ <h1>Give your agent market context.<br /><span>Keep custody local.</span></h1>
16
+ <p class="lede">Connect a read-only Oracle API to your preferred harness. The model proposes actions; you review and authorize them through your local operator.</p>
17
+ </header>
18
+
19
+ <section class="card setup" aria-labelledby="connection-title">
20
+ <div class="section-heading">
21
+ <span class="step">01</span>
22
+ <div>
23
+ <h2 id="connection-title">Your connection</h2>
24
+ <p>These values stay in this browser and are only used to build the config below.</p>
25
+ </div>
26
+ </div>
27
+ <div class="fields">
28
+ <label>Agent API URL
29
+ <input id="api-url" type="url" value="https://api.oracle-agent.dev" spellcheck="false" autocomplete="url" />
30
+ </label>
31
+ <label>Read API key
32
+ <input id="api-key" type="password" placeholder="Your read-only API key" spellcheck="false" autocomplete="off" />
33
+ <span class="hint">Use only a user-owned, read-only API credential.</span>
34
+ </label>
35
+ <label>Public wallet address <span class="optional">optional</span>
36
+ <input id="wallet-address" type="text" placeholder="0x... or a public Solana address" spellcheck="false" autocomplete="off" />
37
+ <span class="hint">Used to personalize portfolio reads. No wallet connection or signature.</span>
38
+ </label>
39
+ </div>
40
+ </section>
41
+
42
+ <section class="card config" aria-labelledby="config-title">
43
+ <div class="section-heading">
44
+ <span class="step">02</span>
45
+ <div>
46
+ <h2 id="config-title">Choose your harness</h2>
47
+ <p>Copy a ready-to-paste cloud/read MCP configuration.</p>
48
+ </div>
49
+ </div>
50
+ <div class="tabs" role="tablist" aria-label="Agent harness">
51
+ <button role="tab" aria-selected="true" data-harness="hermes">Hermes</button>
52
+ <button role="tab" aria-selected="false" data-harness="claude">Claude Code</button>
53
+ <button role="tab" aria-selected="false" data-harness="codex">Codex</button>
54
+ <button role="tab" aria-selected="false" data-harness="cursor">Cursor</button>
55
+ <button role="tab" aria-selected="false" data-harness="mcp">Generic MCP</button>
56
+ </div>
57
+ <div class="code-wrap">
58
+ <div class="code-bar">
59
+ <span id="config-label">Hermes config</span>
60
+ <button id="copy-button" class="copy" type="button">Copy config</button>
61
+ </div>
62
+ <pre><code id="config-output"></code></pre>
63
+ </div>
64
+ <p id="copy-status" class="status" aria-live="polite"></p>
65
+ </section>
66
+
67
+ <section class="operator" aria-labelledby="operator-title">
68
+ <div class="operator-mark" aria-hidden="true">LOCAL</div>
69
+ <div>
70
+ <p class="eyebrow">SEPARATE EXECUTION LANE</p>
71
+ <h2 id="operator-title">Install the local operator to execute</h2>
72
+ <p>The cloud/read MCP can research, quote, simulate, and prepare. Execution belongs in a separate local process under your policy and approval controls.</p>
73
+ <div class="command"><code>npx @oracle-agent/oracle init</code><button id="copy-install" type="button">Copy</button></div>
74
+ </div>
75
+ </section>
76
+
77
+ <footer>
78
+ <p><strong>Custody stays local.</strong> The model proposes; the owner authorizes. This page never connects a wallet, requests a signature, or sends the values you enter.</p>
79
+ </footer>
80
+ </main>
81
+ <script src="app.js"></script>
82
+ </body>
83
+ </html>