@oracle-agent/oracle 0.11.0 → 0.12.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.
- package/LICENSE +115 -201
- package/README.md +66 -84
- package/SECURITY.md +37 -12
- package/SETUP.md +207 -272
- package/dist/action-receipts.mjs +1 -0
- package/dist/action-semantics.mjs +1 -0
- package/dist/address-book.mjs +2 -0
- package/dist/bin/desk-server.mjs +14 -0
- package/dist/bin/oracle-data-mcp.mjs +8 -0
- package/dist/bin/oracle-init.mjs +24 -0
- package/dist/bin/oracle-public-server.mjs +5 -0
- package/dist/bin/oracle-route.mjs +22 -0
- package/dist/bin/oracle-scan.mjs +18 -0
- package/dist/bin/oracle-upgrade.mjs +21 -0
- package/dist/bin/oracle.mjs +68 -0
- package/dist/chains.mjs +1 -0
- package/dist/cli/commands/auth.mjs +16 -0
- package/dist/cli/commands/bootstrap.mjs +18 -0
- package/dist/cli/commands/chain.mjs +21 -0
- package/dist/cli/commands/chat.mjs +35 -0
- package/dist/cli/commands/credential.mjs +1 -0
- package/dist/cli/commands/data-mcp.mjs +2 -0
- package/dist/cli/commands/data.mjs +12 -0
- package/dist/cli/commands/doctor.mjs +5 -0
- package/dist/cli/commands/gate.mjs +13 -0
- package/dist/cli/commands/help.mjs +1 -0
- package/dist/cli/commands/init.mjs +3 -0
- package/dist/cli/commands/mcp.mjs +33 -0
- package/dist/cli/commands/model.mjs +44 -0
- package/dist/cli/commands/prepare.mjs +2 -0
- package/dist/cli/commands/public.mjs +3 -0
- package/dist/cli/commands/route.mjs +2 -0
- package/dist/cli/commands/runner.mjs +1 -0
- package/dist/cli/commands/scan.mjs +2 -0
- package/dist/cli/commands/setup.mjs +34 -0
- package/dist/cli/commands/sign.mjs +4 -0
- package/dist/cli/commands/signer.mjs +1 -0
- package/dist/cli/commands/upgrade.mjs +2 -0
- package/dist/cli/commands/vault.mjs +1 -0
- package/dist/cli/commands/version.mjs +2 -0
- package/dist/data/desk-data.mjs +12 -0
- package/dist/index.mjs +17 -0
- package/dist/nft-gas-war-guard.mjs +1 -0
- package/dist/onboarding/harness-configs.mjs +4 -0
- package/dist/portfolio-risk.mjs +1 -0
- package/dist/prepare-envelope.mjs +1 -0
- package/dist/public-control/policy-schema.mjs +1 -0
- package/dist/router/index.mjs +2 -0
- package/dist/scanner/index.mjs +4 -0
- package/dist/signals/index.mjs +1 -0
- package/dist/watch-preferences.mjs +1 -0
- package/package.json +27 -65
- package/public/oracle-splash/index.html +11 -1
- package/CONTRIBUTING.md +0 -98
- package/bin/desk-server.mjs +0 -440
- package/bin/oracle-data-mcp.mjs +0 -1019
- package/bin/oracle-init.mjs +0 -496
- package/bin/oracle-public-server.mjs +0 -36
- package/bin/oracle-route.mjs +0 -254
- package/bin/oracle-scan.mjs +0 -192
- package/bin/oracle-upgrade.mjs +0 -42
- package/bin/oracle.mjs +0 -33
- package/docs/adding-a-chain.md +0 -229
- package/docs/architecture.md +0 -138
- package/docs/cli.md +0 -47
- package/docs/connectors.md +0 -13
- package/docs/oracle-pack-standard.md +0 -29
- package/docs/profiles.md +0 -151
- package/docs/public-surface.md +0 -133
- package/examples/add-a-chain.mjs +0 -65
- package/examples/oracle-pack-template.mjs +0 -38
- package/examples/research-a-token.mjs +0 -70
- package/plugins/oracle-owner-gate/__init__.py +0 -227
- package/plugins/oracle-owner-gate/plugin.yaml +0 -9
- package/profiles/_template/SOUL.md +0 -54
- package/profiles/_template/profile.json +0 -22
- package/profiles/bitcoin-agent/SOUL.md +0 -31
- package/profiles/bitcoin-agent/profile.json +0 -32
- package/profiles/hyperliquid-agent/SOUL.md +0 -34
- package/profiles/hyperliquid-agent/profile.json +0 -37
- package/profiles/oracle/SOUL.md +0 -107
- package/profiles/oracle/profile.json +0 -39
- package/profiles/polymarket-agent/SOUL.md +0 -35
- package/profiles/polymarket-agent/profile.json +0 -34
- package/profiles/profile.schema.json +0 -90
- package/profiles/protocol-builder/SOUL.md +0 -57
- package/profiles/protocol-builder/profile.json +0 -39
- package/profiles/robinhood-agent/SOUL.md +0 -53
- package/profiles/robinhood-agent/profile.json +0 -40
- package/profiles/solana-agent/SOUL.md +0 -37
- package/profiles/solana-agent/profile.json +0 -37
- package/profiles/stable-agent/SOUL.md +0 -43
- package/profiles/stable-agent/profile.json +0 -37
- package/protocols/templates/safe-erc20/SECURITY.md +0 -16
- package/protocols/templates/safe-erc20/foundry.toml +0 -12
- package/protocols/templates/safe-erc20/remappings.txt +0 -2
- package/protocols/templates/safe-erc20/src/SafeERC20.sol +0 -53
- package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +0 -72
- package/scripts/adversarial-bench.mjs +0 -114
- package/scripts/build-inscription.py +0 -230
- package/scripts/check-doc-drift.mjs +0 -123
- package/scripts/check-test-count.mjs +0 -105
- package/scripts/e2e-hl-markets.mjs +0 -21
- package/scripts/e2e-hl-perps.mjs +0 -48
- package/scripts/e2e-hypercore-staking.mjs +0 -128
- package/scripts/e2e-solana-bitcoin.mjs +0 -183
- package/scripts/protocol-template-gate.mjs +0 -15
- package/scripts/public-api-scan.mjs +0 -23
- package/scripts/secret-scan.mjs +0 -181
- package/scripts/verify-v3-venues.mjs +0 -192
- package/skills/balance/SKILL.md +0 -176
- package/skills/oracle-action-semantics/SKILL.md +0 -40
- package/skills/oracle-best-execution/SKILL.md +0 -127
- package/skills/oracle-bitcoin/SKILL.md +0 -53
- package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +0 -59
- package/skills/oracle-chat/SKILL.md +0 -61
- package/skills/oracle-chat/chain.SKILL.md +0 -31
- package/skills/oracle-chat/setup.SKILL.md +0 -37
- package/skills/oracle-circuit-breaker/SKILL.md +0 -51
- package/skills/oracle-contract-research/SKILL.md +0 -55
- package/skills/oracle-desk/SKILL.md +0 -58
- package/skills/oracle-dex-launch/SKILL.md +0 -38
- package/skills/oracle-grants/SKILL.md +0 -69
- package/skills/oracle-hypercore-staking/SKILL.md +0 -57
- package/skills/oracle-hyperliquid/SKILL.md +0 -56
- package/skills/oracle-meme-token-sniper/SKILL.md +0 -73
- package/skills/oracle-multichain-nft-launch/SKILL.md +0 -338
- package/skills/oracle-multichain-token-launch/SKILL.md +0 -300
- package/skills/oracle-nft-gacha-launch/SKILL.md +0 -48
- package/skills/oracle-nft-mint-gas-war/SKILL.md +0 -63
- package/skills/oracle-polymarket/SKILL.md +0 -60
- package/skills/oracle-protocol-builder/SKILL.md +0 -59
- package/skills/oracle-protocol-security/SKILL.md +0 -60
- package/skills/oracle-public-product/SKILL.md +0 -44
- package/skills/oracle-receipts/SKILL.md +0 -52
- package/skills/oracle-rfq-tokenized-assets/SKILL.md +0 -69
- package/skills/oracle-smart-wallet-scanner/SKILL.md +0 -49
- package/skills/oracle-solana/SKILL.md +0 -65
- package/skills/oracle-solana-nft/SKILL.md +0 -54
- package/skills/oracle-token-research/SKILL.md +0 -67
- package/skins/oracle.yaml +0 -56
- package/src/action-receipts.mjs +0 -265
- package/src/action-semantics.mjs +0 -62
- package/src/address-book.mjs +0 -208
- package/src/agent-auth.mjs +0 -206
- package/src/approval-guard.mjs +0 -282
- package/src/attestation-secret.mjs +0 -88
- package/src/audit-log.mjs +0 -196
- package/src/auth/oauth.mjs +0 -672
- package/src/auto-slippage.mjs +0 -378
- package/src/capability-posture.mjs +0 -125
- package/src/chains.mjs +0 -62
- package/src/cli/chain-catalog.mjs +0 -215
- package/src/cli/chain-state.mjs +0 -74
- package/src/cli/commands/auth.mjs +0 -193
- package/src/cli/commands/bootstrap.mjs +0 -87
- package/src/cli/commands/chain.mjs +0 -143
- package/src/cli/commands/chat.mjs +0 -434
- package/src/cli/commands/credential.mjs +0 -9
- package/src/cli/commands/data-mcp.mjs +0 -18
- package/src/cli/commands/data.mjs +0 -75
- package/src/cli/commands/doctor.mjs +0 -136
- package/src/cli/commands/help.mjs +0 -7
- package/src/cli/commands/init.mjs +0 -27
- package/src/cli/commands/mcp.mjs +0 -142
- package/src/cli/commands/model.mjs +0 -99
- package/src/cli/commands/prepare.mjs +0 -12
- package/src/cli/commands/public.mjs +0 -20
- package/src/cli/commands/route.mjs +0 -12
- package/src/cli/commands/runner.mjs +0 -9
- package/src/cli/commands/scan.mjs +0 -12
- package/src/cli/commands/setup.mjs +0 -275
- package/src/cli/commands/sign.mjs +0 -21
- package/src/cli/commands/signer.mjs +0 -9
- package/src/cli/commands/upgrade.mjs +0 -12
- package/src/cli/commands/vault.mjs +0 -9
- package/src/cli/commands/version.mjs +0 -22
- package/src/cli/first-run.mjs +0 -23
- package/src/cli/kernel.mjs +0 -239
- package/src/cli/mcp-targets/chatgpt.mjs +0 -51
- package/src/cli/mcp-targets/claude-code.mjs +0 -39
- package/src/cli/mcp-targets/claude-desktop.mjs +0 -24
- package/src/cli/mcp-targets/codex.mjs +0 -41
- package/src/cli/mcp-targets/shared.mjs +0 -61
- package/src/cli/messaging-platforms.mjs +0 -209
- package/src/cli/model-config.mjs +0 -70
- package/src/cli/operator-dispatch.mjs +0 -258
- package/src/cli/oracle-harness.py +0 -415
- package/src/cli/paths.mjs +0 -83
- package/src/cli/runtime.mjs +0 -351
- package/src/cli/setup-state.mjs +0 -168
- package/src/cli/spawn-child.mjs +0 -43
- package/src/data/catalog.mjs +0 -585
- package/src/data/desk-data.mjs +0 -695
- package/src/data/http.mjs +0 -253
- package/src/data/provider-endpoint.mjs +0 -94
- package/src/data/providers/aerodrome.mjs +0 -245
- package/src/data/providers/balancer.mjs +0 -209
- package/src/data/providers/bitcoin-esplora.mjs +0 -216
- package/src/data/providers/bitcoin-meta.mjs +0 -378
- package/src/data/providers/blockscout.mjs +0 -14
- package/src/data/providers/bridges.mjs +0 -242
- package/src/data/providers/cowswap.mjs +0 -415
- package/src/data/providers/curve.mjs +0 -201
- package/src/data/providers/defillama.mjs +0 -88
- package/src/data/providers/dexscreener.mjs +0 -43
- package/src/data/providers/evm-rpc.mjs +0 -225
- package/src/data/providers/geckoterminal.mjs +0 -34
- package/src/data/providers/gmx.mjs +0 -496
- package/src/data/providers/hl-assets.mjs +0 -165
- package/src/data/providers/hl-info.mjs +0 -108
- package/src/data/providers/hl-markets.mjs +0 -210
- package/src/data/providers/hl-outcome.mjs +0 -61
- package/src/data/providers/hl-perps.mjs +0 -387
- package/src/data/providers/hl-staking.mjs +0 -353
- package/src/data/providers/hl-ws.mjs +0 -119
- package/src/data/providers/hyperevm-dex.mjs +0 -49
- package/src/data/providers/jupiter-venues.mjs +0 -119
- package/src/data/providers/jupiter.mjs +0 -315
- package/src/data/providers/lifi.mjs +0 -151
- package/src/data/providers/magiceden-sol.mjs +0 -406
- package/src/data/providers/morpho.mjs +0 -177
- package/src/data/providers/nft-gallery.mjs +0 -163
- package/src/data/providers/nft-portfolio.mjs +0 -494
- package/src/data/providers/odos.mjs +0 -156
- package/src/data/providers/oneinch.mjs +0 -174
- package/src/data/providers/opensea-multichain.mjs +0 -136
- package/src/data/providers/opensea-nft.mjs +0 -371
- package/src/data/providers/paraswap.mjs +0 -118
- package/src/data/providers/pendle.mjs +0 -188
- package/src/data/providers/poly-clob.mjs +0 -283
- package/src/data/providers/poly-public.mjs +0 -96
- package/src/data/providers/poly-ws.mjs +0 -103
- package/src/data/providers/portfolio-history.mjs +0 -394
- package/src/data/providers/portfolio.mjs +0 -594
- package/src/data/providers/rfq.mjs +0 -15
- package/src/data/providers/rh-agent.mjs +0 -59
- package/src/data/providers/satflow.mjs +0 -341
- package/src/data/providers/signed-material-guard.mjs +0 -108
- package/src/data/providers/solana-rpc.mjs +0 -197
- package/src/data/providers/uniswap-v3.mjs +0 -349
- package/src/data/providers/uniswap-v4.mjs +0 -414
- package/src/data/providers/zerox.mjs +0 -167
- package/src/data/public-api-scan.mjs +0 -61
- package/src/data/quote-placeholder.mjs +0 -31
- package/src/exact-integer.mjs +0 -72
- package/src/exec-policy.mjs +0 -455
- package/src/flags.mjs +0 -15
- package/src/fresh-window.mjs +0 -76
- package/src/gmx-attestation.mjs +0 -176
- package/src/index.mjs +0 -100
- package/src/nft-gas-war-guard.mjs +0 -139
- package/src/onboarding/agent-keys.mjs +0 -161
- package/src/onboarding/harness-configs.mjs +0 -102
- package/src/onboarding/index.mjs +0 -18
- package/src/onboarding/tiers.mjs +0 -139
- package/src/oracle-env.mjs +0 -47
- package/src/portfolio-risk.mjs +0 -170
- package/src/prepare-envelope.mjs +0 -204
- package/src/profile-upgrade.mjs +0 -277
- package/src/protocol-execution.mjs +0 -84
- package/src/protocol-templates/gate.mjs +0 -179
- package/src/protocol-templates/prepare-deploy.mjs +0 -81
- package/src/public-api/buzz-integration.mjs +0 -256
- package/src/public-api/connect-agent.mjs +0 -416
- package/src/public-api/grants.mjs +0 -142
- package/src/public-api/http.mjs +0 -389
- package/src/public-control/aa-adapter.mjs +0 -402
- package/src/public-control/build-registry.mjs +0 -227
- package/src/public-control/bundler-client.mjs +0 -357
- package/src/public-control/grant-indexer.mjs +0 -296
- package/src/public-control/policy-render.mjs +0 -69
- package/src/public-control/policy-schema.mjs +0 -318
- package/src/public-control/runtime-config.mjs +0 -275
- package/src/public-control/session-key-model.mjs +0 -374
- package/src/public-control/session-orchestrator.mjs +0 -412
- package/src/rfq/intent.mjs +0 -180
- package/src/rfq/sources.mjs +0 -181
- package/src/route-attestation.mjs +0 -132
- package/src/router/best-execution.mjs +0 -326
- package/src/router/index.mjs +0 -226
- package/src/router/prepare-bridge.mjs +0 -289
- package/src/router/prepare-route.mjs +0 -398
- package/src/router/proposal.mjs +0 -311
- package/src/router/risk-classifier.mjs +0 -119
- package/src/router/route-sources.mjs +0 -364
- package/src/scanner/chains.config.mjs +0 -430
- package/src/scanner/contract.mjs +0 -270
- package/src/scanner/evm-scanner.mjs +0 -394
- package/src/scanner/index.mjs +0 -9
- package/src/scanner/v2-venue.mjs +0 -335
- package/src/scanner/v3-venue.mjs +0 -290
- package/src/scopes.mjs +0 -44
- package/src/sell-simulation.mjs +0 -167
- package/src/signals/engine.mjs +0 -146
- package/src/signals/index.mjs +0 -1
- package/src/token-transfer-guard.mjs +0 -188
- package/src/tui/app.mjs +0 -438
- package/src/tui/backend.mjs +0 -145
- package/src/tui/format.mjs +0 -272
- package/src/tui/gateway-client.mjs +0 -177
- package/src/tui/input.mjs +0 -501
- package/src/tui/renderer.mjs +0 -443
- package/src/tui/standalone-client.mjs +0 -666
- package/src/tui/theme.mjs +0 -81
- package/src/vault-attestation.mjs +0 -146
- package/src/venues.mjs +0 -206
- package/src/watch-preferences.mjs +0 -85
package/src/cli/runtime.mjs
DELETED
|
@@ -1,351 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { spawnSync } from "node:child_process";
|
|
5
|
-
import { homeDir, oracleConfigDir, ensureDir } from "./paths.mjs";
|
|
6
|
-
|
|
7
|
-
export const HERMES_VERSION = "0.19.0";
|
|
8
|
-
export const HERMES_PYPI = `hermes-agent==${HERMES_VERSION}`;
|
|
9
|
-
const MIN_PY = [3, 11];
|
|
10
|
-
const MAX_PY_EXCLUSIVE = [3, 14];
|
|
11
|
-
export const UV_PYTHON = "3.13";
|
|
12
|
-
export const UV_VERSION = "0.12.1";
|
|
13
|
-
export const UV_INSTALLERS = Object.freeze({
|
|
14
|
-
posix: Object.freeze({
|
|
15
|
-
url: `https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-installer.sh`,
|
|
16
|
-
sha256: "d3f5412d38c99f9d024901843bf98206f0d2c6dbe64df40d0b740e2751ca62c1",
|
|
17
|
-
}),
|
|
18
|
-
windows: Object.freeze({
|
|
19
|
-
url: `https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-installer.ps1`,
|
|
20
|
-
sha256: "b9ec035151bfbb11d616dbd69886498d885551489eddf095ea3c0ad59f640eb0",
|
|
21
|
-
}),
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
export function verifyUvInstaller(bytes, { windows = process.platform === "win32" } = {}) {
|
|
25
|
-
const body = Buffer.isBuffer(bytes) ? bytes : Buffer.from(bytes);
|
|
26
|
-
const spec = windows ? UV_INSTALLERS.windows : UV_INSTALLERS.posix;
|
|
27
|
-
const digest = createHash("sha256").update(body).digest("hex");
|
|
28
|
-
const text = body.toString("utf8");
|
|
29
|
-
return digest === spec.sha256 && text.length >= 1_000 && text.includes(UV_VERSION);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function runtimeDir() {
|
|
33
|
-
return path.join(oracleConfigDir(), "runtime");
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function runtimeVenvDir() {
|
|
37
|
-
return path.join(runtimeDir(), "venv");
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function venvBin(name) {
|
|
41
|
-
const dir = process.platform === "win32" ? "Scripts" : "bin";
|
|
42
|
-
const exe = process.platform === "win32" ? `${name}.exe` : name;
|
|
43
|
-
return path.join(runtimeVenvDir(), dir, exe);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function managedHermesPath() {
|
|
47
|
-
return venvBin("hermes");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function managedPythonPath() {
|
|
51
|
-
const py = venvBin("python3");
|
|
52
|
-
return fs.existsSync(py) ? py : venvBin("python");
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function managedUvPath() {
|
|
56
|
-
return path.join(runtimeDir(), "uv", process.platform === "win32" ? "uv.exe" : "uv");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function whichBin(bin) {
|
|
60
|
-
const suffixes = process.platform === "win32" && !path.extname(bin)
|
|
61
|
-
? ["", ".exe", ".cmd", ".bat"]
|
|
62
|
-
: [""];
|
|
63
|
-
for (const dir of (process.env.PATH || "").split(path.delimiter)) {
|
|
64
|
-
if (!dir) continue;
|
|
65
|
-
for (const suffix of suffixes) {
|
|
66
|
-
const c = path.join(dir, `${bin}${suffix}`);
|
|
67
|
-
try {
|
|
68
|
-
if (fs.existsSync(c)) return c;
|
|
69
|
-
} catch {}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function parsePyVersion(out) {
|
|
76
|
-
const m = /Python (\d+)\.(\d+)\.(\d+)/.exec(out || "");
|
|
77
|
-
if (!m) return null;
|
|
78
|
-
return [Number(m[1]), Number(m[2]), Number(m[3])];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function versionSupported(v) {
|
|
82
|
-
if (!v) return false;
|
|
83
|
-
const [maj, min] = v;
|
|
84
|
-
if (maj < MIN_PY[0] || (maj === MIN_PY[0] && min < MIN_PY[1])) return false;
|
|
85
|
-
if (maj > MAX_PY_EXCLUSIVE[0] || (maj === MAX_PY_EXCLUSIVE[0] && min >= MAX_PY_EXCLUSIVE[1])) {
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function findHostPython() {
|
|
92
|
-
const candidates = [
|
|
93
|
-
process.env.ORACLE_PYTHON,
|
|
94
|
-
"python3.13",
|
|
95
|
-
"python3.12",
|
|
96
|
-
"python3.11",
|
|
97
|
-
"python3",
|
|
98
|
-
"python",
|
|
99
|
-
].filter(Boolean);
|
|
100
|
-
for (const cand of candidates) {
|
|
101
|
-
const bin = path.isAbsolute(cand) ? (fs.existsSync(cand) ? cand : null) : whichBin(cand);
|
|
102
|
-
if (!bin) continue;
|
|
103
|
-
const r = spawnSync(bin, ["--version"], { encoding: "utf8", timeout: 15_000 });
|
|
104
|
-
const v = parsePyVersion(`${r.stdout || ""}${r.stderr || ""}`);
|
|
105
|
-
if (versionSupported(v)) return { bin, version: v.join("."), source: "host" };
|
|
106
|
-
}
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function uvBin() {
|
|
111
|
-
return (
|
|
112
|
-
process.env.ORACLE_UV_BIN ||
|
|
113
|
-
whichBin("uv") ||
|
|
114
|
-
(fs.existsSync(path.join(homeDir(), ".local", "bin", "uv"))
|
|
115
|
-
? path.join(homeDir(), ".local", "bin", "uv")
|
|
116
|
-
: null) ||
|
|
117
|
-
(fs.existsSync(managedUvPath()) ? managedUvPath() : null)
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function downloadFile(url, dest) {
|
|
122
|
-
const script = [
|
|
123
|
-
"const fs=require('node:fs');",
|
|
124
|
-
"const [url,dest]=process.argv.slice(1);",
|
|
125
|
-
"fetch(url).then(r=>{if(!r.ok)throw new Error('http '+r.status);return r.arrayBuffer()})",
|
|
126
|
-
".then(b=>fs.writeFileSync(dest,Buffer.from(b)))",
|
|
127
|
-
".catch(e=>{console.error(e.message);process.exit(1)});",
|
|
128
|
-
].join("");
|
|
129
|
-
return spawnSync(process.execPath, ["-e", script, url, dest], {
|
|
130
|
-
encoding: "utf8",
|
|
131
|
-
timeout: 2 * 60_000,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function installManagedUv({ quiet = false } = {}) {
|
|
136
|
-
const existing = uvBin();
|
|
137
|
-
if (existing) return { ok: true, bin: existing, reused: true };
|
|
138
|
-
|
|
139
|
-
ensureDir(runtimeDir());
|
|
140
|
-
const windows = process.platform === "win32";
|
|
141
|
-
const installer = path.join(runtimeDir(), windows ? "uv-install.ps1" : "uv-install.sh");
|
|
142
|
-
const spec = windows ? UV_INSTALLERS.windows : UV_INSTALLERS.posix;
|
|
143
|
-
const dl = downloadFile(spec.url, installer);
|
|
144
|
-
if (dl.status !== 0) {
|
|
145
|
-
return {
|
|
146
|
-
ok: false,
|
|
147
|
-
reason: `could not download the uv installer (${dl.status})`,
|
|
148
|
-
stderr: (dl.stderr || "").slice(-800),
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const body = fs.readFileSync(installer);
|
|
153
|
-
if (!verifyUvInstaller(body, { windows })) {
|
|
154
|
-
return { ok: false, reason: `uv ${UV_VERSION} installer checksum mismatch` };
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const installDir = path.dirname(managedUvPath());
|
|
158
|
-
ensureDir(installDir);
|
|
159
|
-
const command = windows
|
|
160
|
-
? (whichBin("powershell.exe") || whichBin("powershell"))
|
|
161
|
-
: (whichBin("sh") || "/bin/sh");
|
|
162
|
-
if (!command) return { ok: false, reason: windows ? "PowerShell not found" : "sh not found" };
|
|
163
|
-
const args = windows
|
|
164
|
-
? ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", installer]
|
|
165
|
-
: [installer];
|
|
166
|
-
const inst = spawnSync(command, args, {
|
|
167
|
-
stdio: quiet ? "pipe" : "inherit",
|
|
168
|
-
encoding: "utf8",
|
|
169
|
-
timeout: 5 * 60_000,
|
|
170
|
-
env: {
|
|
171
|
-
...process.env,
|
|
172
|
-
UV_INSTALL_DIR: installDir,
|
|
173
|
-
UV_NO_MODIFY_PATH: "1",
|
|
174
|
-
},
|
|
175
|
-
});
|
|
176
|
-
if (inst.status !== 0 || !fs.existsSync(managedUvPath())) {
|
|
177
|
-
return {
|
|
178
|
-
ok: false,
|
|
179
|
-
reason: `uv install failed (${inst.status})`,
|
|
180
|
-
stderr: (inst.stderr || "").slice(-800),
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
return { ok: true, bin: managedUvPath(), reused: false };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function provisionPythonViaUv({ quiet = false } = {}) {
|
|
187
|
-
const installed = installManagedUv({ quiet });
|
|
188
|
-
if (!installed.ok) return installed;
|
|
189
|
-
const uv = installed.bin;
|
|
190
|
-
|
|
191
|
-
const uvEnv = {
|
|
192
|
-
...process.env,
|
|
193
|
-
UV_PYTHON_INSTALL_DIR: path.join(runtimeDir(), "python"),
|
|
194
|
-
UV_CACHE_DIR: path.join(runtimeDir(), "cache"),
|
|
195
|
-
};
|
|
196
|
-
const inst = spawnSync(uv, ["python", "install", "--no-bin", UV_PYTHON], {
|
|
197
|
-
stdio: quiet ? "pipe" : "inherit",
|
|
198
|
-
encoding: "utf8",
|
|
199
|
-
timeout: 15 * 60_000,
|
|
200
|
-
env: uvEnv,
|
|
201
|
-
});
|
|
202
|
-
if (inst.status !== 0) {
|
|
203
|
-
return {
|
|
204
|
-
ok: false,
|
|
205
|
-
reason: `uv python install ${UV_PYTHON} failed (${inst.status})`,
|
|
206
|
-
stderr: (inst.stderr || "").slice(-800),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
const found = spawnSync(uv, ["python", "find", UV_PYTHON], {
|
|
211
|
-
encoding: "utf8",
|
|
212
|
-
timeout: 60_000,
|
|
213
|
-
env: uvEnv,
|
|
214
|
-
});
|
|
215
|
-
const bin = (found.stdout || "").trim().split(/\r?\n/)[0];
|
|
216
|
-
if (found.status !== 0 || !bin || !fs.existsSync(bin)) {
|
|
217
|
-
return { ok: false, reason: `uv could not locate python ${UV_PYTHON}` };
|
|
218
|
-
}
|
|
219
|
-
return { ok: true, bin, version: UV_PYTHON, source: "uv" };
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Resolve the hermes runtime this Oracle install should use.
|
|
224
|
-
* Order: explicit override -> system PATH -> oracle-managed venv.
|
|
225
|
-
*/
|
|
226
|
-
export function resolveHermes() {
|
|
227
|
-
if (process.env.ORACLE_HERMES_BIN) {
|
|
228
|
-
return { ok: true, bin: process.env.ORACLE_HERMES_BIN, source: "env" };
|
|
229
|
-
}
|
|
230
|
-
const onPath = whichBin("hermes");
|
|
231
|
-
if (onPath) return { ok: true, bin: onPath, source: "path" };
|
|
232
|
-
const managed = managedHermesPath();
|
|
233
|
-
if (fs.existsSync(managed)) return { ok: true, bin: managed, source: "managed" };
|
|
234
|
-
return { ok: false, bin: null, source: null };
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export function runtimeStatus() {
|
|
238
|
-
const resolved = resolveHermes();
|
|
239
|
-
const host = findHostPython();
|
|
240
|
-
return {
|
|
241
|
-
hermes: resolved,
|
|
242
|
-
managedVenv: runtimeVenvDir(),
|
|
243
|
-
managedInstalled: fs.existsSync(managedHermesPath()),
|
|
244
|
-
hostPython: host,
|
|
245
|
-
uv: uvBin(),
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function run(cmd, args, { quiet }) {
|
|
250
|
-
return spawnSync(cmd, args, {
|
|
251
|
-
stdio: quiet ? "pipe" : "inherit",
|
|
252
|
-
encoding: "utf8",
|
|
253
|
-
timeout: 20 * 60_000,
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Create ~/.config/oracle/runtime/venv and install hermes-agent into it.
|
|
259
|
-
* Never touches system python or global site-packages.
|
|
260
|
-
*/
|
|
261
|
-
export function installManagedHermes({ quiet = false, upgrade = false } = {}) {
|
|
262
|
-
let host = findHostPython();
|
|
263
|
-
if (!host) {
|
|
264
|
-
const viaUv = provisionPythonViaUv({ quiet });
|
|
265
|
-
if (viaUv.ok) {
|
|
266
|
-
host = { bin: viaUv.bin, version: viaUv.version, source: "uv" };
|
|
267
|
-
} else {
|
|
268
|
-
return {
|
|
269
|
-
ok: false,
|
|
270
|
-
reason:
|
|
271
|
-
`no supported python found (need 3.11-3.13) and uv could not provide one: ${viaUv.reason}. ` +
|
|
272
|
-
"install uv (https://docs.astral.sh/uv) or python 3.13, then re-run 'oracle bootstrap'",
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
ensureDir(runtimeDir());
|
|
278
|
-
const venv = runtimeVenvDir();
|
|
279
|
-
const alreadyInstalled = fs.existsSync(managedHermesPath());
|
|
280
|
-
if (alreadyInstalled && !upgrade) {
|
|
281
|
-
return { ok: true, bin: managedHermesPath(), reused: true };
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (!fs.existsSync(path.join(venv, "pyvenv.cfg"))) {
|
|
285
|
-
let mk = run(host.bin, ["-m", "venv", venv], { quiet });
|
|
286
|
-
if (mk.status !== 0 && host.source !== "uv") {
|
|
287
|
-
fs.rmSync(venv, { recursive: true, force: true });
|
|
288
|
-
const viaUv = provisionPythonViaUv({ quiet });
|
|
289
|
-
if (viaUv.ok) {
|
|
290
|
-
host = { bin: viaUv.bin, version: viaUv.version, source: "uv" };
|
|
291
|
-
mk = run(host.bin, ["-m", "venv", venv], { quiet });
|
|
292
|
-
} else {
|
|
293
|
-
return {
|
|
294
|
-
ok: false,
|
|
295
|
-
reason: `python -m venv failed (${mk.status}) and uv fallback failed: ${viaUv.reason}`,
|
|
296
|
-
stderr: (mk.stderr || "").slice(-800),
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
if (mk.status !== 0) {
|
|
301
|
-
return {
|
|
302
|
-
ok: false,
|
|
303
|
-
reason: `isolated python -m venv failed (${mk.status})`,
|
|
304
|
-
stderr: (mk.stderr || "").slice(-800),
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const py = managedPythonPath();
|
|
310
|
-
if (!fs.existsSync(py)) {
|
|
311
|
-
return { ok: false, reason: `venv python missing at ${py}` };
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const pipArgs = ["-m", "pip", "install", "--disable-pip-version-check"];
|
|
315
|
-
if (upgrade) pipArgs.push("--upgrade");
|
|
316
|
-
pipArgs.push(HERMES_PYPI);
|
|
317
|
-
const inst = run(py, pipArgs, { quiet });
|
|
318
|
-
if (inst.status !== 0) {
|
|
319
|
-
return {
|
|
320
|
-
ok: false,
|
|
321
|
-
reason: `pip install ${HERMES_PYPI} failed (${inst.status})`,
|
|
322
|
-
stderr: (inst.stderr || "").slice(-1200),
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const bin = managedHermesPath();
|
|
327
|
-
if (!fs.existsSync(bin)) {
|
|
328
|
-
return { ok: false, reason: `hermes entrypoint not found after install (${bin})` };
|
|
329
|
-
}
|
|
330
|
-
return { ok: true, bin, reused: false, python: host.version };
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
export const runtime = {
|
|
334
|
-
HERMES_PYPI,
|
|
335
|
-
HERMES_VERSION,
|
|
336
|
-
UV_PYTHON,
|
|
337
|
-
runtimeDir,
|
|
338
|
-
runtimeVenvDir,
|
|
339
|
-
managedHermesPath,
|
|
340
|
-
managedPythonPath,
|
|
341
|
-
managedUvPath,
|
|
342
|
-
findHostPython,
|
|
343
|
-
installManagedUv,
|
|
344
|
-
provisionPythonViaUv,
|
|
345
|
-
resolveHermes,
|
|
346
|
-
runtimeStatus,
|
|
347
|
-
installManagedHermes,
|
|
348
|
-
whichBin,
|
|
349
|
-
};
|
|
350
|
-
|
|
351
|
-
export default runtime;
|
package/src/cli/setup-state.mjs
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import os from "node:os";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
listMessagingPlatforms,
|
|
6
|
-
findMessagingPlatform,
|
|
7
|
-
renderSetupMenu,
|
|
8
|
-
} from "./messaging-platforms.mjs";
|
|
9
|
-
import { hermesRoot, ensureDir, oracleConfigDir } from "./paths.mjs";
|
|
10
|
-
|
|
11
|
-
const SECRETISH = /(TOKEN|SECRET|PASSWORD|KEY|AUTH|PRIVATE|MNEMONIC|SEED)/i;
|
|
12
|
-
|
|
13
|
-
export function profileEnvPath(profile = "oracle") {
|
|
14
|
-
return path.join(hermesRoot(), "profiles", profile, ".env");
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function parseDotEnv(text) {
|
|
18
|
-
const out = {};
|
|
19
|
-
for (const line of String(text || "").split(/\r?\n/)) {
|
|
20
|
-
const trimmed = line.trim();
|
|
21
|
-
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
22
|
-
const eq = trimmed.indexOf("=");
|
|
23
|
-
if (eq <= 0) continue;
|
|
24
|
-
const key = trimmed.slice(0, eq).trim();
|
|
25
|
-
let val = trimmed.slice(eq + 1).trim();
|
|
26
|
-
if (
|
|
27
|
-
(val.startsWith('"') && val.endsWith('"')) ||
|
|
28
|
-
(val.startsWith("'") && val.endsWith("'"))
|
|
29
|
-
) {
|
|
30
|
-
val = val.slice(1, -1);
|
|
31
|
-
}
|
|
32
|
-
out[key] = val;
|
|
33
|
-
}
|
|
34
|
-
return out;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function readProfileEnv(profile = "oracle") {
|
|
38
|
-
const p = profileEnvPath(profile);
|
|
39
|
-
if (!fs.existsSync(p)) return {};
|
|
40
|
-
return parseDotEnv(fs.readFileSync(p, "utf8"));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function writeProfileEnvKey(profile, key, value) {
|
|
44
|
-
if (!key || SECRETISH.test(key) === false && /[^A-Z0-9_]/.test(key)) {
|
|
45
|
-
// keep simple env keys
|
|
46
|
-
}
|
|
47
|
-
if (!/^[A-Z][A-Z0-9_]*$/.test(key)) {
|
|
48
|
-
const err = new Error(`invalid env key '${key}'`);
|
|
49
|
-
err.code = "BAD_KEY";
|
|
50
|
-
throw err;
|
|
51
|
-
}
|
|
52
|
-
if (value == null || String(value).trim() === "") {
|
|
53
|
-
const err = new Error(`empty value for ${key}`);
|
|
54
|
-
err.code = "EMPTY";
|
|
55
|
-
throw err;
|
|
56
|
-
}
|
|
57
|
-
const p = profileEnvPath(profile);
|
|
58
|
-
ensureDir(path.dirname(p));
|
|
59
|
-
let text = fs.existsSync(p) ? fs.readFileSync(p, "utf8") : "";
|
|
60
|
-
const lines = text ? text.split(/\r?\n/) : [];
|
|
61
|
-
const next = [];
|
|
62
|
-
let replaced = false;
|
|
63
|
-
const assignment = `${key}=${String(value)}`;
|
|
64
|
-
for (const line of lines) {
|
|
65
|
-
if (line.startsWith(`${key}=`)) {
|
|
66
|
-
next.push(assignment);
|
|
67
|
-
replaced = true;
|
|
68
|
-
} else if (line.length || next.length) {
|
|
69
|
-
next.push(line);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (!replaced) {
|
|
73
|
-
if (next.length && next[next.length - 1] !== "") next.push("");
|
|
74
|
-
next.push(assignment);
|
|
75
|
-
}
|
|
76
|
-
while (next.length && next[next.length - 1] === "") next.pop();
|
|
77
|
-
next.push("");
|
|
78
|
-
fs.writeFileSync(p, next.join("\n"), { mode: 0o600 });
|
|
79
|
-
try {
|
|
80
|
-
fs.chmodSync(p, 0o600);
|
|
81
|
-
} catch {
|
|
82
|
-
// best effort on platforms that ignore mode
|
|
83
|
-
}
|
|
84
|
-
return { path: p, key, set: true };
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function platformStatus(profile = "oracle") {
|
|
88
|
-
const env = readProfileEnv(profile);
|
|
89
|
-
const statuses = {};
|
|
90
|
-
for (const p of listMessagingPlatforms()) {
|
|
91
|
-
if (!p.required.length) {
|
|
92
|
-
statuses[p.key] = "manual";
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
const missing = p.required.filter((k) => !String(env[k] || "").trim());
|
|
96
|
-
statuses[p.key] = missing.length ? "unset" : "ready";
|
|
97
|
-
}
|
|
98
|
-
return { profile, statuses, envPath: profileEnvPath(profile) };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export function renderStatus(profile = "oracle") {
|
|
102
|
-
const { statuses } = platformStatus(profile);
|
|
103
|
-
return renderSetupMenu({ profile, statuses });
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export function setPlatformToken(profile, platformKey, token, extra = {}) {
|
|
107
|
-
const platform = findMessagingPlatform(platformKey);
|
|
108
|
-
if (!platform) {
|
|
109
|
-
const err = new Error(`unknown platform '${platformKey}'`);
|
|
110
|
-
err.code = "UNKNOWN_PLATFORM";
|
|
111
|
-
throw err;
|
|
112
|
-
}
|
|
113
|
-
if (!platform.required.length) {
|
|
114
|
-
const err = new Error(
|
|
115
|
-
`${platform.key} uses hermes interactive setup (oracle setup messaging)`,
|
|
116
|
-
);
|
|
117
|
-
err.code = "NEEDS_INTERACTIVE";
|
|
118
|
-
throw err;
|
|
119
|
-
}
|
|
120
|
-
const primary = platform.required[0];
|
|
121
|
-
writeProfileEnvKey(profile, primary, token);
|
|
122
|
-
for (const [k, v] of Object.entries(extra || {})) {
|
|
123
|
-
if (v != null && String(v).trim()) writeProfileEnvKey(profile, k, v);
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
platform: platform.key,
|
|
127
|
-
set: platform.required,
|
|
128
|
-
profile,
|
|
129
|
-
path: profileEnvPath(profile),
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export function setupStatePath() {
|
|
134
|
-
return path.join(oracleConfigDir(), "setup-state.json");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export function touchSetupState(patch = {}) {
|
|
138
|
-
ensureDir(oracleConfigDir());
|
|
139
|
-
const p = setupStatePath();
|
|
140
|
-
let cur = {};
|
|
141
|
-
if (fs.existsSync(p)) {
|
|
142
|
-
try {
|
|
143
|
-
cur = JSON.parse(fs.readFileSync(p, "utf8"));
|
|
144
|
-
} catch {
|
|
145
|
-
cur = {};
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
const next = {
|
|
149
|
-
...cur,
|
|
150
|
-
...patch,
|
|
151
|
-
updatedAt: new Date().toISOString(),
|
|
152
|
-
host: os.hostname(),
|
|
153
|
-
};
|
|
154
|
-
fs.writeFileSync(p, JSON.stringify(next, null, 2) + "\n", { mode: 0o600 });
|
|
155
|
-
return next;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
export default {
|
|
159
|
-
profileEnvPath,
|
|
160
|
-
parseDotEnv,
|
|
161
|
-
readProfileEnv,
|
|
162
|
-
writeProfileEnvKey,
|
|
163
|
-
platformStatus,
|
|
164
|
-
renderStatus,
|
|
165
|
-
setPlatformToken,
|
|
166
|
-
setupStatePath,
|
|
167
|
-
touchSetupState,
|
|
168
|
-
};
|
package/src/cli/spawn-child.mjs
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
|
|
3
|
-
const FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
4
|
-
|
|
5
|
-
export function spawnChild(command, args = [], options = {}, label = command) {
|
|
6
|
-
return new Promise((resolve) => {
|
|
7
|
-
const child = spawn(command, args, options);
|
|
8
|
-
let settled = false;
|
|
9
|
-
let forwardedSignal = null;
|
|
10
|
-
|
|
11
|
-
const handlers = new Map(
|
|
12
|
-
FORWARDED_SIGNALS.map((signal) => [signal, () => {
|
|
13
|
-
forwardedSignal ||= signal;
|
|
14
|
-
if (child.exitCode === null && child.signalCode === null) child.kill(signal);
|
|
15
|
-
}]),
|
|
16
|
-
);
|
|
17
|
-
for (const [signal, handler] of handlers) process.on(signal, handler);
|
|
18
|
-
|
|
19
|
-
const cleanup = () => {
|
|
20
|
-
for (const [signal, handler] of handlers) process.off(signal, handler);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
child.once("error", (error) => {
|
|
24
|
-
if (settled) return;
|
|
25
|
-
settled = true;
|
|
26
|
-
cleanup();
|
|
27
|
-
process.stderr.write(`oracle: could not start ${label}: ${error.message}\n`);
|
|
28
|
-
resolve(1);
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
child.once("exit", (code, signal) => {
|
|
32
|
-
if (settled) return;
|
|
33
|
-
settled = true;
|
|
34
|
-
cleanup();
|
|
35
|
-
const propagated = forwardedSignal || signal;
|
|
36
|
-
if (propagated) {
|
|
37
|
-
process.kill(process.pid, propagated);
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
resolve(code ?? 1);
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
}
|