@oracle-agent/oracle 0.13.1 → 0.14.1

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 (449) hide show
  1. package/CONTRIBUTING.md +99 -0
  2. package/README.md +20 -14
  3. package/SECURITY.md +6 -8
  4. package/SETUP.md +25 -27
  5. package/bin/desk-server.mjs +473 -0
  6. package/bin/oracle-data-mcp.mjs +1252 -0
  7. package/bin/oracle-equities.mjs +168 -0
  8. package/bin/oracle-init.mjs +525 -0
  9. package/bin/oracle-public-server.mjs +36 -0
  10. package/bin/oracle-route.mjs +254 -0
  11. package/bin/oracle-scan.mjs +192 -0
  12. package/bin/oracle-upgrade.mjs +42 -0
  13. package/bin/oracle.mjs +34 -0
  14. package/docs/adding-a-chain.md +229 -0
  15. package/docs/architecture.md +139 -0
  16. package/docs/buzz-integration.md +115 -0
  17. package/docs/cli.md +143 -0
  18. package/docs/connectors.md +13 -0
  19. package/docs/hyperliquid-builder-code.md +50 -0
  20. package/docs/locals-only-fee-waiver.md +34 -0
  21. package/docs/oracle-pack-standard.md +29 -0
  22. package/docs/profiles.md +151 -0
  23. package/docs/public-surface.md +206 -0
  24. package/examples/add-a-chain.mjs +65 -0
  25. package/examples/oracle-pack-template.mjs +38 -0
  26. package/examples/research-a-token.mjs +70 -0
  27. package/package.json +78 -32
  28. package/plugins/oracle-owner-gate/__init__.py +288 -0
  29. package/plugins/oracle-owner-gate/plugin.yaml +9 -0
  30. package/{dist/assets/profiles → profiles}/oracle/SOUL.md +0 -14
  31. package/protocols/templates/safe-erc20/SECURITY.md +16 -0
  32. package/protocols/templates/safe-erc20/foundry.toml +12 -0
  33. package/protocols/templates/safe-erc20/remappings.txt +2 -0
  34. package/protocols/templates/safe-erc20/src/SafeERC20.sol +53 -0
  35. package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +72 -0
  36. package/public/oracle-splash/_variants/ice.html +3 -3
  37. package/public/oracle-splash/_variants/ivory.html +3 -3
  38. package/public/oracle-splash/downloads/index.html +34 -223
  39. package/public/oracle-splash/index.html +11 -11
  40. package/scripts/adversarial-bench.mjs +114 -0
  41. package/scripts/build-dist.mjs +119 -0
  42. package/scripts/build-inscription.py +230 -0
  43. package/scripts/check-doc-drift.mjs +123 -0
  44. package/scripts/check-test-count.mjs +105 -0
  45. package/scripts/e2e-hl-markets.mjs +21 -0
  46. package/scripts/e2e-hl-perps.mjs +48 -0
  47. package/scripts/e2e-hypercore-staking.mjs +128 -0
  48. package/scripts/e2e-solana-bitcoin.mjs +183 -0
  49. package/scripts/guard-publish.mjs +22 -0
  50. package/scripts/protocol-template-gate.mjs +15 -0
  51. package/scripts/public-api-scan.mjs +23 -0
  52. package/scripts/publish-dist.mjs +67 -0
  53. package/scripts/record-hero-cli.sh +80 -0
  54. package/scripts/secret-scan.mjs +169 -0
  55. package/scripts/smoke-dist-bins.mjs +89 -0
  56. package/scripts/verify-dist.mjs +29 -0
  57. package/scripts/verify-v3-venues.mjs +233 -0
  58. package/skins/oracle.yaml +56 -0
  59. package/src/action-receipts.mjs +265 -0
  60. package/src/action-semantics.mjs +62 -0
  61. package/src/address-book.mjs +208 -0
  62. package/src/agent-auth.mjs +206 -0
  63. package/src/approval-guard.mjs +282 -0
  64. package/src/attestation-secret.mjs +94 -0
  65. package/src/audit-log.mjs +196 -0
  66. package/src/auth/oauth.mjs +672 -0
  67. package/src/auto-slippage.mjs +378 -0
  68. package/src/capability-posture.mjs +125 -0
  69. package/src/cards.mjs +422 -0
  70. package/src/chains.mjs +62 -0
  71. package/src/cli/chain-catalog.mjs +215 -0
  72. package/src/cli/chain-state.mjs +74 -0
  73. package/src/cli/commands/auth.mjs +193 -0
  74. package/src/cli/commands/bootstrap.mjs +87 -0
  75. package/src/cli/commands/chain.mjs +143 -0
  76. package/src/cli/commands/chat.mjs +465 -0
  77. package/src/cli/commands/credential.mjs +9 -0
  78. package/src/cli/commands/data-mcp.mjs +18 -0
  79. package/src/cli/commands/data.mjs +75 -0
  80. package/src/cli/commands/doctor.mjs +136 -0
  81. package/src/cli/commands/equities.mjs +41 -0
  82. package/src/cli/commands/farm.mjs +129 -0
  83. package/src/cli/commands/fees.mjs +109 -0
  84. package/src/cli/commands/follow.mjs +130 -0
  85. package/src/cli/commands/harness.mjs +63 -0
  86. package/src/cli/commands/help.mjs +7 -0
  87. package/src/cli/commands/init.mjs +27 -0
  88. package/src/cli/commands/mcp.mjs +154 -0
  89. package/src/cli/commands/model.mjs +106 -0
  90. package/src/cli/commands/plugins.mjs +275 -0
  91. package/src/cli/commands/prepare.mjs +12 -0
  92. package/src/cli/commands/public.mjs +20 -0
  93. package/src/cli/commands/resolve.mjs +64 -0
  94. package/src/cli/commands/route.mjs +12 -0
  95. package/src/cli/commands/runner.mjs +9 -0
  96. package/src/cli/commands/scan.mjs +12 -0
  97. package/src/cli/commands/setup.mjs +294 -0
  98. package/src/cli/commands/sign.mjs +21 -0
  99. package/src/cli/commands/signer.mjs +9 -0
  100. package/src/cli/commands/swap.mjs +102 -0
  101. package/src/cli/commands/upgrade.mjs +12 -0
  102. package/src/cli/commands/vault.mjs +9 -0
  103. package/src/cli/commands/version.mjs +22 -0
  104. package/src/cli/first-run.mjs +23 -0
  105. package/src/cli/kernel.mjs +262 -0
  106. package/src/cli/mcp-targets/chatgpt.mjs +51 -0
  107. package/src/cli/mcp-targets/claude-code.mjs +39 -0
  108. package/src/cli/mcp-targets/claude-desktop.mjs +24 -0
  109. package/src/cli/mcp-targets/codex.mjs +41 -0
  110. package/src/cli/mcp-targets/cursor.mjs +32 -0
  111. package/src/cli/mcp-targets/shared.mjs +71 -0
  112. package/src/cli/mcp-targets/vscode.mjs +39 -0
  113. package/src/cli/messaging-platforms.mjs +217 -0
  114. package/src/cli/model-config.mjs +78 -0
  115. package/src/cli/operator-dispatch.mjs +194 -0
  116. package/src/cli/oracle-harness.py +415 -0
  117. package/src/cli/paths.mjs +107 -0
  118. package/src/cli/runtime.mjs +351 -0
  119. package/src/cli/setup-state.mjs +168 -0
  120. package/src/cli/spawn-child.mjs +43 -0
  121. package/src/data/catalog.mjs +858 -0
  122. package/src/data/desk-data.mjs +877 -0
  123. package/src/data/http.mjs +253 -0
  124. package/src/data/names.mjs +188 -0
  125. package/src/data/provider-endpoint.mjs +94 -0
  126. package/src/data/providers/aave-v3.mjs +139 -0
  127. package/src/data/providers/across-bridge.mjs +41 -0
  128. package/src/data/providers/aerodrome.mjs +245 -0
  129. package/src/data/providers/aevo.mjs +33 -0
  130. package/src/data/providers/approval-indexer.mjs +133 -0
  131. package/src/data/providers/approvals.mjs +594 -0
  132. package/src/data/providers/babylon-staking.mjs +149 -0
  133. package/src/data/providers/balancer.mjs +209 -0
  134. package/src/data/providers/beefy-yields.mjs +45 -0
  135. package/src/data/providers/birdeye-tokens.mjs +33 -0
  136. package/src/data/providers/bisq-markets.mjs +145 -0
  137. package/src/data/providers/bitcoin-esplora.mjs +216 -0
  138. package/src/data/providers/bitcoin-meta.mjs +378 -0
  139. package/src/data/providers/blockscout.mjs +14 -0
  140. package/src/data/providers/bob-rootstock.mjs +198 -0
  141. package/src/data/providers/braiins-insights.mjs +103 -0
  142. package/src/data/providers/bridge-aggregator.mjs +259 -0
  143. package/src/data/providers/bridges.mjs +242 -0
  144. package/src/data/providers/bungee.mjs +29 -0
  145. package/src/data/providers/celestia-da.mjs +38 -0
  146. package/src/data/providers/changenow.mjs +135 -0
  147. package/src/data/providers/compound.mjs +32 -0
  148. package/src/data/providers/connext.mjs +28 -0
  149. package/src/data/providers/convex.mjs +30 -0
  150. package/src/data/providers/cow-protocol.mjs +110 -0
  151. package/src/data/providers/cowswap.mjs +415 -0
  152. package/src/data/providers/curve.mjs +201 -0
  153. package/src/data/providers/das-assets.mjs +59 -0
  154. package/src/data/providers/debridge.mjs +109 -0
  155. package/src/data/providers/defillama.mjs +88 -0
  156. package/src/data/providers/dexscreener.mjs +43 -0
  157. package/src/data/providers/drift.mjs +32 -0
  158. package/src/data/providers/dydx.mjs +41 -0
  159. package/src/data/providers/evm-rpc.mjs +225 -0
  160. package/src/data/providers/farming.mjs +291 -0
  161. package/src/data/providers/geckoterminal.mjs +34 -0
  162. package/src/data/providers/gmx.mjs +496 -0
  163. package/src/data/providers/hiro-stacks.mjs +150 -0
  164. package/src/data/providers/hl-assets.mjs +165 -0
  165. package/src/data/providers/hl-info.mjs +108 -0
  166. package/src/data/providers/hl-markets.mjs +210 -0
  167. package/src/data/providers/hl-outcome.mjs +61 -0
  168. package/src/data/providers/hl-perps.mjs +419 -0
  169. package/src/data/providers/hl-staking.mjs +353 -0
  170. package/src/data/providers/hl-ws.mjs +119 -0
  171. package/src/data/providers/hyperevm-dex.mjs +49 -0
  172. package/src/data/providers/jito-mev.mjs +117 -0
  173. package/src/data/providers/jupiter-venues.mjs +119 -0
  174. package/src/data/providers/jupiter.mjs +315 -0
  175. package/src/data/providers/kamino-strategies.mjs +143 -0
  176. package/src/data/providers/l2beat-tvl.mjs +42 -0
  177. package/src/data/providers/lifi.mjs +166 -0
  178. package/src/data/providers/liquid-esplora.mjs +152 -0
  179. package/src/data/providers/magiceden-ordinals.mjs +141 -0
  180. package/src/data/providers/magiceden-sol.mjs +406 -0
  181. package/src/data/providers/mempool-lightning.mjs +144 -0
  182. package/src/data/providers/mempool-mining.mjs +142 -0
  183. package/src/data/providers/meteora-dlmm.mjs +168 -0
  184. package/src/data/providers/morpho.mjs +177 -0
  185. package/src/data/providers/nft-gallery.mjs +163 -0
  186. package/src/data/providers/nft-portfolio.mjs +494 -0
  187. package/src/data/providers/odos.mjs +156 -0
  188. package/src/data/providers/ondo.mjs +31 -0
  189. package/src/data/providers/oneinch.mjs +174 -0
  190. package/src/data/providers/opensea-multichain.mjs +136 -0
  191. package/src/data/providers/opensea-nft.mjs +371 -0
  192. package/src/data/providers/orca.mjs +29 -0
  193. package/src/data/providers/ordinals-runes.mjs +180 -0
  194. package/src/data/providers/pancakeswap.mjs +28 -0
  195. package/src/data/providers/paraswap.mjs +125 -0
  196. package/src/data/providers/pendle.mjs +188 -0
  197. package/src/data/providers/poly-clob.mjs +283 -0
  198. package/src/data/providers/poly-public.mjs +96 -0
  199. package/src/data/providers/poly-ws.mjs +103 -0
  200. package/src/data/providers/polygon-staking.mjs +227 -0
  201. package/src/data/providers/portfolio-history.mjs +394 -0
  202. package/src/data/providers/portfolio.mjs +600 -0
  203. package/src/data/providers/pyth-price-feeds.mjs +172 -0
  204. package/src/data/providers/raydium.mjs +35 -0
  205. package/src/data/providers/relayscan-mev.mjs +72 -0
  206. package/src/data/providers/rfq.mjs +15 -0
  207. package/src/data/providers/rh-agent.mjs +59 -0
  208. package/src/data/providers/sanctum-lst.mjs +180 -0
  209. package/src/data/providers/satflow.mjs +341 -0
  210. package/src/data/providers/signed-material-guard.mjs +108 -0
  211. package/src/data/providers/solana-rpc.mjs +197 -0
  212. package/src/data/providers/solend-lending.mjs +166 -0
  213. package/src/data/providers/spark-lend.mjs +42 -0
  214. package/src/data/providers/squid-router.mjs +29 -0
  215. package/src/data/providers/stargate.mjs +29 -0
  216. package/src/data/providers/sushiswap.mjs +30 -0
  217. package/src/data/providers/symbiotic-restaking.mjs +41 -0
  218. package/src/data/providers/thorchain.mjs +36 -0
  219. package/src/data/providers/traderjoe.mjs +28 -0
  220. package/src/data/providers/twap.mjs +152 -0
  221. package/src/data/providers/uniswap-v3.mjs +457 -0
  222. package/src/data/providers/uniswap-v4.mjs +414 -0
  223. package/src/data/providers/vertex.mjs +41 -0
  224. package/src/data/providers/wallet-watch.mjs +264 -0
  225. package/src/data/providers/wormhole.mjs +28 -0
  226. package/src/data/providers/yearn.mjs +31 -0
  227. package/src/data/providers/zerox.mjs +167 -0
  228. package/src/data/public-api-scan.mjs +61 -0
  229. package/src/data/quote-placeholder.mjs +31 -0
  230. package/src/desk/swap-prepare.mjs +194 -0
  231. package/src/equities/bridge.mjs +388 -0
  232. package/src/equities/fixtures/bridge_routes.json +159 -0
  233. package/src/equities/fixtures/dst_transitions.json +29 -0
  234. package/src/equities/fixtures/equity_dex_pools.json +154 -0
  235. package/src/equities/fixtures/hip3_l2books.json +2711 -0
  236. package/src/equities/fixtures/nyse_holidays.json +1 -0
  237. package/src/equities/fixtures/oracles.json +100 -0
  238. package/src/equities/fixtures/rh_pool_state.json +244 -0
  239. package/src/equities/fixtures/solana_xstocks.json +704 -0
  240. package/src/equities/fixtures/ton_xstocks.json +35 -0
  241. package/src/equities/fixtures/universe.json +411 -0
  242. package/src/equities/fixtures/venues.json +3542 -0
  243. package/src/equities/fixtures.mjs +405 -0
  244. package/src/equities/funding.mjs +142 -0
  245. package/src/equities/index.mjs +166 -0
  246. package/src/equities/liveness.mjs +148 -0
  247. package/src/equities/marketHours.mjs +249 -0
  248. package/src/equities/normalize.mjs +295 -0
  249. package/src/equities/num.mjs +146 -0
  250. package/src/equities/prepare.mjs +95 -0
  251. package/src/equities/rank.mjs +260 -0
  252. package/src/equities/sourceNum.mjs +69 -0
  253. package/src/equities/types.mjs +220 -0
  254. package/src/equities/venues/arcus-perp.mjs +84 -0
  255. package/src/equities/venues/arcus-spot.mjs +105 -0
  256. package/src/equities/venues/hyperliquid-hip3.mjs +224 -0
  257. package/src/equities/venues/rh-uniswap.mjs +216 -0
  258. package/src/equities/venues/solana-xstocks.mjs +139 -0
  259. package/src/equities/venues/ton-stonfi.mjs +139 -0
  260. package/src/exact-integer.mjs +72 -0
  261. package/src/exec-policy.mjs +419 -0
  262. package/src/flags.mjs +15 -0
  263. package/src/fresh-window.mjs +76 -0
  264. package/src/gmx-attestation.mjs +176 -0
  265. package/src/index.mjs +107 -0
  266. package/src/licensing/locals-only.mjs +25 -0
  267. package/src/nft-gas-war-guard.mjs +139 -0
  268. package/src/onboarding/agent-keys.mjs +161 -0
  269. package/src/onboarding/harness-configs.mjs +102 -0
  270. package/src/onboarding/index.mjs +18 -0
  271. package/src/onboarding/tiers.mjs +139 -0
  272. package/src/oracle-env.mjs +55 -0
  273. package/src/package-manifest.mjs +42 -0
  274. package/src/plugins/agent-plugin-loader.mjs +225 -0
  275. package/src/portfolio-risk.mjs +170 -0
  276. package/src/prepare-envelope.mjs +204 -0
  277. package/src/profile-upgrade.mjs +277 -0
  278. package/src/protocol-execution.mjs +84 -0
  279. package/src/protocol-templates/gate.mjs +179 -0
  280. package/src/protocol-templates/prepare-deploy.mjs +81 -0
  281. package/src/public-api/agent-grants.mjs +57 -0
  282. package/src/public-api/buzz-integration.mjs +267 -0
  283. package/src/public-api/connect-agent.mjs +424 -0
  284. package/src/public-api/grants.mjs +142 -0
  285. package/src/public-api/http.mjs +707 -0
  286. package/src/public-api/metering.mjs +111 -0
  287. package/src/public-control/aa-adapter.mjs +402 -0
  288. package/src/public-control/build-registry.mjs +227 -0
  289. package/src/public-control/bundler-client.mjs +357 -0
  290. package/src/public-control/grant-indexer.mjs +296 -0
  291. package/src/public-control/policy-render.mjs +69 -0
  292. package/src/public-control/policy-schema.mjs +322 -0
  293. package/src/public-control/runtime-config.mjs +275 -0
  294. package/src/public-control/session-key-model.mjs +379 -0
  295. package/src/public-control/session-orchestrator.mjs +418 -0
  296. package/src/rfq/intent.mjs +180 -0
  297. package/src/rfq/sources.mjs +181 -0
  298. package/src/route-attestation.mjs +132 -0
  299. package/src/router/best-execution.mjs +326 -0
  300. package/src/router/index.mjs +250 -0
  301. package/src/router/integrator-fee.mjs +135 -0
  302. package/src/router/prepare-bridge.mjs +293 -0
  303. package/src/router/prepare-route.mjs +398 -0
  304. package/src/router/proposal.mjs +311 -0
  305. package/src/router/risk-classifier.mjs +119 -0
  306. package/src/router/route-sources.mjs +364 -0
  307. package/src/scanner/chains.config.mjs +543 -0
  308. package/src/scanner/contract.mjs +270 -0
  309. package/src/scanner/evm-scanner.mjs +394 -0
  310. package/src/scanner/index.mjs +9 -0
  311. package/src/scanner/v2-venue.mjs +351 -0
  312. package/src/scanner/v3-venue.mjs +308 -0
  313. package/src/scopes.mjs +44 -0
  314. package/src/sell-simulation.mjs +167 -0
  315. package/src/signals/engine.mjs +146 -0
  316. package/src/signals/index.mjs +1 -0
  317. package/src/token-transfer-guard.mjs +188 -0
  318. package/src/tui/app.mjs +438 -0
  319. package/src/tui/backend.mjs +215 -0
  320. package/src/tui/format.mjs +272 -0
  321. package/src/tui/gateway-client.mjs +177 -0
  322. package/src/tui/input.mjs +501 -0
  323. package/src/tui/memory.mjs +105 -0
  324. package/src/tui/meta-learn.mjs +85 -0
  325. package/src/tui/renderer.mjs +443 -0
  326. package/src/tui/scheduler.mjs +205 -0
  327. package/src/tui/skills-loader.mjs +140 -0
  328. package/src/tui/standalone-client.mjs +752 -0
  329. package/src/tui/theme.mjs +81 -0
  330. package/src/vault-attestation.mjs +146 -0
  331. package/src/venues.mjs +206 -0
  332. package/src/watch-preferences.mjs +85 -0
  333. package/dist/action-receipts.mjs +0 -1
  334. package/dist/action-semantics.mjs +0 -1
  335. package/dist/address-book.mjs +0 -2
  336. package/dist/bin/desk-server.mjs +0 -59
  337. package/dist/bin/oracle-data-mcp.mjs +0 -8
  338. package/dist/bin/oracle-equities.mjs +0 -20
  339. package/dist/bin/oracle-init.mjs +0 -24
  340. package/dist/bin/oracle-public-server.mjs +0 -5
  341. package/dist/bin/oracle-route.mjs +0 -22
  342. package/dist/bin/oracle-scan.mjs +0 -18
  343. package/dist/bin/oracle-upgrade.mjs +0 -21
  344. package/dist/bin/oracle.mjs +0 -76
  345. package/dist/chains.mjs +0 -1
  346. package/dist/cli/commands/auth.mjs +0 -16
  347. package/dist/cli/commands/bootstrap.mjs +0 -18
  348. package/dist/cli/commands/chain.mjs +0 -21
  349. package/dist/cli/commands/chat.mjs +0 -45
  350. package/dist/cli/commands/credential.mjs +0 -1
  351. package/dist/cli/commands/data-mcp.mjs +0 -2
  352. package/dist/cli/commands/data.mjs +0 -12
  353. package/dist/cli/commands/doctor.mjs +0 -5
  354. package/dist/cli/commands/equities.mjs +0 -15
  355. package/dist/cli/commands/farm.mjs +0 -59
  356. package/dist/cli/commands/follow.mjs +0 -28
  357. package/dist/cli/commands/gate.mjs +0 -13
  358. package/dist/cli/commands/harness.mjs +0 -15
  359. package/dist/cli/commands/help.mjs +0 -1
  360. package/dist/cli/commands/init.mjs +0 -3
  361. package/dist/cli/commands/mcp.mjs +0 -60
  362. package/dist/cli/commands/model.mjs +0 -54
  363. package/dist/cli/commands/plugins.mjs +0 -38
  364. package/dist/cli/commands/prepare.mjs +0 -2
  365. package/dist/cli/commands/public.mjs +0 -3
  366. package/dist/cli/commands/resolve.mjs +0 -23
  367. package/dist/cli/commands/route.mjs +0 -2
  368. package/dist/cli/commands/runner.mjs +0 -1
  369. package/dist/cli/commands/scan.mjs +0 -2
  370. package/dist/cli/commands/setup.mjs +0 -34
  371. package/dist/cli/commands/sign.mjs +0 -21
  372. package/dist/cli/commands/signer.mjs +0 -1
  373. package/dist/cli/commands/swap.mjs +0 -36
  374. package/dist/cli/commands/upgrade.mjs +0 -2
  375. package/dist/cli/commands/vault.mjs +0 -1
  376. package/dist/cli/commands/version.mjs +0 -2
  377. package/dist/data/desk-data.mjs +0 -55
  378. package/dist/data/names.mjs +0 -2
  379. package/dist/data/providers/farming.mjs +0 -2
  380. package/dist/equities/index.mjs +0 -1
  381. package/dist/index.mjs +0 -60
  382. package/dist/nft-gas-war-guard.mjs +0 -1
  383. package/dist/onboarding/harness-configs.mjs +0 -4
  384. package/dist/portfolio-risk.mjs +0 -1
  385. package/dist/prepare-envelope.mjs +0 -1
  386. package/dist/public-api/agent-grants.mjs +0 -3
  387. package/dist/public-control/policy-schema.mjs +0 -1
  388. package/dist/router/index.mjs +0 -2
  389. package/dist/scanner/index.mjs +0 -4
  390. package/dist/signals/index.mjs +0 -1
  391. package/dist/watch-preferences.mjs +0 -1
  392. /package/{dist/assets/profiles → profiles}/_template/SOUL.md +0 -0
  393. /package/{dist/assets/profiles → profiles}/_template/profile.json +0 -0
  394. /package/{dist/assets/profiles → profiles}/bitcoin-agent/SOUL.md +0 -0
  395. /package/{dist/assets/profiles → profiles}/bitcoin-agent/profile.json +0 -0
  396. /package/{dist/assets/profiles → profiles}/hyperliquid-agent/SOUL.md +0 -0
  397. /package/{dist/assets/profiles → profiles}/hyperliquid-agent/profile.json +0 -0
  398. /package/{dist/assets/profiles → profiles}/oracle/profile.json +0 -0
  399. /package/{dist/assets/profiles → profiles}/polymarket-agent/SOUL.md +0 -0
  400. /package/{dist/assets/profiles → profiles}/polymarket-agent/profile.json +0 -0
  401. /package/{dist/assets/profiles → profiles}/profile.schema.json +0 -0
  402. /package/{dist/assets/profiles → profiles}/protocol-builder/SOUL.md +0 -0
  403. /package/{dist/assets/profiles → profiles}/protocol-builder/profile.json +0 -0
  404. /package/{dist/assets/profiles → profiles}/robinhood-agent/SOUL.md +0 -0
  405. /package/{dist/assets/profiles → profiles}/robinhood-agent/profile.json +0 -0
  406. /package/{dist/assets/profiles → profiles}/solana-agent/SOUL.md +0 -0
  407. /package/{dist/assets/profiles → profiles}/solana-agent/profile.json +0 -0
  408. /package/{dist/assets/profiles → profiles}/stable-agent/SOUL.md +0 -0
  409. /package/{dist/assets/profiles → profiles}/stable-agent/profile.json +0 -0
  410. /package/{dist/assets/skills → skills}/balance/SKILL.md +0 -0
  411. /package/{dist/assets/skills → skills}/bitcoin-l1.md +0 -0
  412. /package/{dist/assets/skills → skills}/chain-defi-ecosystem-profiling.md +0 -0
  413. /package/{dist/assets/skills → skills}/evm-contract-research.md +0 -0
  414. /package/{dist/assets/skills → skills}/hyperliquid.md +0 -0
  415. /package/{dist/assets/skills → skills}/multichain-exec-desk.md +0 -0
  416. /package/{dist/assets/skills → skills}/oracle-action-semantics/SKILL.md +0 -0
  417. /package/{dist/assets/skills → skills}/oracle-best-execution/SKILL.md +0 -0
  418. /package/{dist/assets/skills → skills}/oracle-best-execution.md +0 -0
  419. /package/{dist/assets/skills → skills}/oracle-bitcoin/SKILL.md +0 -0
  420. /package/{dist/assets/skills → skills}/oracle-chain-graphs-telegram-cards/SKILL.md +0 -0
  421. /package/{dist/assets/skills → skills}/oracle-chat/SKILL.md +0 -0
  422. /package/{dist/assets/skills → skills}/oracle-chat/chain.SKILL.md +0 -0
  423. /package/{dist/assets/skills → skills}/oracle-chat/setup.SKILL.md +0 -0
  424. /package/{dist/assets/skills → skills}/oracle-circuit-breaker/SKILL.md +0 -0
  425. /package/{dist/assets/skills → skills}/oracle-contract-research/SKILL.md +0 -0
  426. /package/{dist/assets/skills → skills}/oracle-desk/SKILL.md +0 -0
  427. /package/{dist/assets/skills → skills}/oracle-desk.md +0 -0
  428. /package/{dist/assets/skills → skills}/oracle-dex-launch/SKILL.md +0 -0
  429. /package/{dist/assets/skills → skills}/oracle-equities/SKILL.md +0 -0
  430. /package/{dist/assets/skills → skills}/oracle-grants/SKILL.md +0 -0
  431. /package/{dist/assets/skills → skills}/oracle-hypercore-staking/SKILL.md +0 -0
  432. /package/{dist/assets/skills → skills}/oracle-hyperliquid/SKILL.md +0 -0
  433. /package/{dist/assets/skills → skills}/oracle-meme-token-sniper/SKILL.md +0 -0
  434. /package/{dist/assets/skills → skills}/oracle-multichain-nft-launch/SKILL.md +0 -0
  435. /package/{dist/assets/skills → skills}/oracle-multichain-token-launch/SKILL.md +0 -0
  436. /package/{dist/assets/skills → skills}/oracle-nft-gacha-launch/SKILL.md +0 -0
  437. /package/{dist/assets/skills → skills}/oracle-nft-mint-gas-war/SKILL.md +0 -0
  438. /package/{dist/assets/skills → skills}/oracle-polymarket/SKILL.md +0 -0
  439. /package/{dist/assets/skills → skills}/oracle-protocol-builder/SKILL.md +0 -0
  440. /package/{dist/assets/skills → skills}/oracle-protocol-security/SKILL.md +0 -0
  441. /package/{dist/assets/skills → skills}/oracle-public-product/SKILL.md +0 -0
  442. /package/{dist/assets/skills → skills}/oracle-receipts/SKILL.md +0 -0
  443. /package/{dist/assets/skills → skills}/oracle-receipts.md +0 -0
  444. /package/{dist/assets/skills → skills}/oracle-rfq-tokenized-assets/SKILL.md +0 -0
  445. /package/{dist/assets/skills → skills}/oracle-smart-wallet-scanner/SKILL.md +0 -0
  446. /package/{dist/assets/skills → skills}/oracle-solana/SKILL.md +0 -0
  447. /package/{dist/assets/skills → skills}/oracle-solana-nft/SKILL.md +0 -0
  448. /package/{dist/assets/skills → skills}/oracle-token-research/SKILL.md +0 -0
  449. /package/{dist/assets/skills → skills}/solana.md +0 -0
@@ -0,0 +1,183 @@
1
+ // Oracle end-to-end LIVE lane probe: Solana + Bitcoin.
2
+ // Read/quote/prepare/simulate only. No signing. No broadcast. No keys required.
3
+ //
4
+ // Run: node scripts/e2e-solana-bitcoin.mjs
5
+ // Exit 0 = every mandatory lane answered live. Optional keyed lanes are reported, not failed.
6
+
7
+ import { data as desk } from "../src/data/desk-data.mjs";
8
+ import { jupiterQuote, jupiterPrepareSwap, SOL_MINT, USDC_MINT } from "../src/data/providers/jupiter.mjs";
9
+ import { solanaSimulateTransaction } from "../src/data/providers/solana-rpc.mjs";
10
+ import { magicEdenSolStats, magicEdenSolListings, magicEdenSolPrepareBuy } from "../src/data/providers/magiceden-sol.mjs";
11
+
12
+ const PROBE_WALLET = process.env.ORACLE_E2E_SOL_PUBKEY || "DtM6A1ivwvFeT14f7ggTAGvpUTZA5LeutV3rLe8wR6U3";
13
+ const PROBE_BTC = process.env.ORACLE_E2E_BTC_ADDRESS || "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
14
+
15
+ const results = [];
16
+ function record(lane, status, detail) {
17
+ results.push({ lane, status, detail });
18
+ const tag = status === "ok" ? "OK " : status === "keyed" ? "KEY " : "FAIL";
19
+ console.log(`${tag} ${lane} :: ${detail}`);
20
+ }
21
+
22
+ async function run(lane, fn, { optional = false } = {}) {
23
+ try {
24
+ const detail = await fn();
25
+ record(lane, "ok", detail);
26
+ return true;
27
+ } catch (error) {
28
+ const message = String(error?.message || error).slice(0, 140);
29
+ record(lane, optional ? "keyed" : "fail", message);
30
+ return optional;
31
+ }
32
+ }
33
+
34
+ console.log("== SOLANA ==");
35
+
36
+ await run("solana.rpc.health", async () => {
37
+ const health = await desk.solana.health();
38
+ if (!health?.ok) throw new Error(`rpc unhealthy ${JSON.stringify(health).slice(0, 80)}`);
39
+ return `cluster ok slot lane live`;
40
+ });
41
+
42
+ await run("solana.rpc.balance", async () => {
43
+ const bal = await desk.solana.balance(PROBE_WALLET);
44
+ return `lamports=${bal?.lamports ?? bal?.value ?? "n/a"}`;
45
+ });
46
+
47
+ await run("solana.rpc.tokenAccounts", async () => {
48
+ const accounts = await desk.solana.tokenAccounts({ owner: PROBE_WALLET });
49
+ return `accounts=${accounts?.accounts?.length ?? 0}`;
50
+ });
51
+
52
+ let jupQuote = null;
53
+ await run("solana.jupiter.quote(SOL->USDC)", async () => {
54
+ jupQuote = await jupiterQuote({ inputMint: SOL_MINT, outputMint: USDC_MINT, amount: "10000000", slippageBps: 50 });
55
+ const g = jupQuote.solanaGuard;
56
+ if (jupQuote.executionReady !== false) throw new Error("quote must not be executionReady");
57
+ if (g.slippageBps > 100) throw new Error("slippage cap breached");
58
+ return `out=${jupQuote.quote.outAmount} bps=${g.slippageBps} expires=${g.expiresAtMs - g.quotedAtMs}ms execReady=false`;
59
+ });
60
+
61
+ await run("solana.jupiter.slippageCap", async () => {
62
+ try {
63
+ await jupiterQuote({ inputMint: SOL_MINT, outputMint: USDC_MINT, amount: "10000000", slippageBps: 500 });
64
+ } catch (error) {
65
+ return `rejected 500bps: ${String(error.message).slice(0, 60)}`;
66
+ }
67
+ throw new Error("500 bps was NOT rejected");
68
+ });
69
+
70
+ let jupPrepared = null;
71
+ await run("solana.jupiter.prepareSwap", async () => {
72
+ jupPrepared = await jupiterPrepareSwap({
73
+ quoteResponse: jupQuote.quote,
74
+ userPublicKey: PROBE_WALLET,
75
+ });
76
+ if (jupPrepared.signingReady !== false || jupPrepared.broadcastReady !== false) throw new Error("prepare leaked signing/broadcast readiness");
77
+ if (!jupPrepared.requiresUserSignature) throw new Error("prepare must require user signature");
78
+ return `tx=${jupPrepared.swapTransaction.length}b64 requiresUserSig=true signingReady=false broadcastReady=false`;
79
+ });
80
+
81
+ await run("solana.rpc.simulate(preparedSwap)", async () => {
82
+ const sim = await solanaSimulateTransaction({ transaction: jupPrepared.swapTransaction, sigVerify: false });
83
+ const err = sim?.err ?? sim?.value?.err ?? sim?.raw?.value?.err ?? null;
84
+ const units = sim?.unitsConsumed ?? sim?.value?.unitsConsumed ?? sim?.raw?.value?.unitsConsumed ?? null;
85
+ return `err=${JSON.stringify(err)} unitsConsumed=${units}`;
86
+ });
87
+
88
+ await run("solana.nft.magiceden.stats", async () => {
89
+ const stats = await magicEdenSolStats({ symbol: "mad_lads" });
90
+ if (!(stats.floorPriceSol > 0)) throw new Error("no floor");
91
+ return `floor=${stats.floorPriceSol} SOL listed=${stats.listedCount}`;
92
+ });
93
+
94
+ let meListing = null;
95
+ await run("solana.nft.magiceden.listings", async () => {
96
+ const out = await magicEdenSolListings({ symbol: "mad_lads", limit: 1 });
97
+ meListing = out.listings[0];
98
+ if (!meListing?.tokenMint) throw new Error("no listing");
99
+ return `mint=${meListing.tokenMint.slice(0, 8)}.. price=${meListing.priceSol} SOL seller=${meListing.seller.slice(0, 6)}..`;
100
+ });
101
+
102
+ await run(
103
+ "solana.nft.magiceden.prepareBuy",
104
+ async () => {
105
+ const prep = await magicEdenSolPrepareBuy({
106
+ buyer: PROBE_WALLET,
107
+ seller: meListing.seller,
108
+ auctionHouse: meListing.auctionHouse,
109
+ tokenMint: meListing.tokenMint,
110
+ tokenATA: meListing.tokenATA,
111
+ priceSol: meListing.priceSol,
112
+ });
113
+ if (prep.broadcastReady !== false) throw new Error("prepare leaked broadcast readiness");
114
+ return `tx prepared bytes=${String(prep.transaction || "").length} requiresUserSig=${prep.requiresUserSignature}`;
115
+ },
116
+ { optional: true }
117
+ );
118
+
119
+ console.log("== BITCOIN ==");
120
+
121
+ await run("bitcoin.esplora.health", async () => {
122
+ const h = await desk.bitcoin.health();
123
+ if (!h?.ok) throw new Error("esplora unhealthy");
124
+ return `ok tip lane live`;
125
+ });
126
+
127
+ await run("bitcoin.esplora.tipHeight", async () => {
128
+ const t = await desk.bitcoin.tipHeight();
129
+ const height = t?.height ?? t?.tipHeight ?? t;
130
+ if (!Number(height)) throw new Error("no tip height");
131
+ return `tip=${height}`;
132
+ });
133
+
134
+ await run("bitcoin.esplora.fees", async () => {
135
+ const f = await desk.bitcoin.fees();
136
+ const fast = f?.fastestFee ?? f?.fees?.fastestFee ?? f?.["1"] ?? null;
137
+ return `fastest=${JSON.stringify(fast)}`;
138
+ });
139
+
140
+ await run("bitcoin.esplora.address", async () => {
141
+ const a = await desk.bitcoin.address(PROBE_BTC);
142
+ const funded = a?.chainStats?.fundedTxoSum ?? a?.balanceSats ?? a?.raw?.chain_stats?.funded_txo_sum ?? null;
143
+ return `fundedSats=${funded}`;
144
+ });
145
+
146
+ await run("bitcoin.esplora.utxos", async () => {
147
+ const u = await desk.bitcoin.utxos(PROBE_BTC);
148
+ const n = u?.utxos?.length ?? u?.length ?? 0;
149
+ return `utxos=${n}`;
150
+ });
151
+
152
+ await run("bitcoin.meta.health", async () => {
153
+ const h = await desk.bitcoin.metaHealth();
154
+ return `ok=${h?.ok} tier=${h?.tier ?? h?.mode ?? "keyless"}`;
155
+ });
156
+
157
+ await run(
158
+ "bitcoin.meta.inscriptionInfo",
159
+ async () => {
160
+ const info = await desk.bitcoin.inscriptions(PROBE_BTC);
161
+ return `inscriptions=${info?.inscriptions?.length ?? "unknown"}`;
162
+ },
163
+ { optional: true }
164
+ );
165
+
166
+ await run(
167
+ "bitcoin.satflow.health",
168
+ async () => {
169
+ const h = await desk.bitcoin.satflowHealth();
170
+ if (!h?.ok) throw new Error(`satflow ${JSON.stringify(h).slice(0, 90)}`);
171
+ return `ok`;
172
+ },
173
+ { optional: true }
174
+ );
175
+
176
+ const failed = results.filter((r) => r.status === "fail");
177
+ const keyed = results.filter((r) => r.status === "keyed");
178
+ console.log(`\nlanes=${results.length} ok=${results.length - failed.length - keyed.length} keyed=${keyed.length} failed=${failed.length}`);
179
+ if (failed.length) {
180
+ console.log(`FAILED: ${failed.map((f) => f.lane).join(", ")}`);
181
+ process.exit(1);
182
+ }
183
+ console.log("E2E OK: every mandatory Solana + Bitcoin lane answered live, prepare-only posture held.");
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ // prepublishOnly guard.
3
+ //
4
+ // `npm publish` run directly in packages/oracle would ship src/ — 36k lines of
5
+ // readable source. Publishing must go through scripts/publish-dist.mjs, which
6
+ // packs the bundled stage instead. That script sets ORACLE_PUBLISH_STAGED=1.
7
+ //
8
+ // This is a guard, not a policy decision: it fails closed on the accident.
9
+
10
+ if (process.env.ORACLE_PUBLISH_STAGED === "1") process.exit(0);
11
+
12
+ console.error(`
13
+ REFUSING to publish from the source tree.
14
+
15
+ Publishing here would ship src/ (readable source) to npm.
16
+
17
+ Use: npm run publish:dist -- --publish
18
+
19
+ That builds the bundle, verifies export parity, stages a clean directory
20
+ with a rewritten manifest, and publishes that instead.
21
+ `);
22
+ process.exit(1);
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ import { listProtocolTemplates, runProtocolTemplateGate } from "../src/protocol-templates/gate.mjs";
3
+
4
+ const id = process.argv[2];
5
+ if (!id || id === "list") {
6
+ console.log(JSON.stringify(listProtocolTemplates(), null, 2));
7
+ process.exit(0);
8
+ }
9
+ try {
10
+ const r = runProtocolTemplateGate(id, { allowSkipStatic: process.env.REQUIRE_SLITHER !== "1" });
11
+ console.log(JSON.stringify(r, null, 2));
12
+ } catch (e) {
13
+ console.error(String(e.message || e));
14
+ process.exit(1);
15
+ }
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { scanPublicApis } from "../src/data/public-api-scan.mjs";
5
+
6
+ const args = process.argv.slice(2);
7
+ const value = (flag) => {
8
+ const i = args.indexOf(flag);
9
+ return i >= 0 ? args[i + 1] : null;
10
+ };
11
+ const outPath = value("--out");
12
+ const timeoutMs = Number(value("--timeout-ms") || 12_000);
13
+ const providers = value("--providers")?.split(",").map((x) => x.trim()).filter(Boolean);
14
+
15
+ const report = await scanPublicApis({ providers, timeoutMs });
16
+ const json = `${JSON.stringify(report, null, 2)}\n`;
17
+ if (outPath) {
18
+ const target = path.resolve(outPath);
19
+ await fs.mkdir(path.dirname(target), { recursive: true });
20
+ await fs.writeFile(target, json, "utf8");
21
+ console.error(`wrote ${target}`);
22
+ }
23
+ process.stdout.write(json);
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ // Stage and publish the BUNDLED package.
3
+ //
4
+ // Publishing from packages/oracle directly would ship src/ (36k readable lines).
5
+ // This builds dist/, verifies export parity against source, stages a clean
6
+ // directory with a rewritten manifest, and publishes from there. The source
7
+ // tree is never the thing that gets packed.
8
+ //
9
+ // node scripts/publish-dist.mjs # pack only, leaves the tarball
10
+ // node scripts/publish-dist.mjs --publish # actually publish to npm
11
+
12
+ import { execFileSync } from "node:child_process";
13
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
14
+ import { dirname, join, resolve } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+
17
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
18
+ const STAGE = join(ROOT, ".publish-stage");
19
+ const doPublish = process.argv.includes("--publish");
20
+
21
+ const run = (cmd, args, cwd = ROOT) =>
22
+ execFileSync(cmd, args, { cwd, stdio: "inherit", env: { ...process.env } });
23
+
24
+ console.log("→ building bundle");
25
+ run("node", [join(ROOT, "scripts/build-dist.mjs")]);
26
+
27
+ console.log("→ verifying export parity against source");
28
+ run("node", [join(ROOT, "scripts/verify-dist.mjs")]);
29
+
30
+ console.log("→ staging");
31
+ if (existsSync(STAGE)) rmSync(STAGE, { recursive: true });
32
+ mkdirSync(STAGE, { recursive: true });
33
+
34
+ const manifest = JSON.parse(readFileSync(join(ROOT, "dist/package.publish.json"), "utf8"));
35
+ cpSync(join(ROOT, "dist"), join(STAGE, "dist"), { recursive: true });
36
+ rmSync(join(STAGE, "dist/package.publish.json"), { force: true });
37
+
38
+ for (const asset of ["public", "artifacts"]) {
39
+ if (existsSync(join(ROOT, asset))) {
40
+ cpSync(join(ROOT, asset), join(STAGE, asset), { recursive: true });
41
+ }
42
+ }
43
+ for (const doc of ["README.md", "SETUP.md", "LICENSE", "SECURITY.md"]) {
44
+ if (existsSync(join(ROOT, doc))) cpSync(join(ROOT, doc), join(STAGE, doc));
45
+ }
46
+ writeFileSync(join(STAGE, "package.json"), JSON.stringify(manifest, null, 2) + "\n");
47
+
48
+ // Fail closed: if source somehow reached the stage, do not publish it.
49
+ const leaked = [];
50
+ for (const forbidden of ["src", "scripts", "skills", "profiles", "test"]) {
51
+ if (existsSync(join(STAGE, forbidden))) leaked.push(forbidden);
52
+ }
53
+ if (leaked.length) {
54
+ console.error(`\nREFUSING: source directories reached the publish stage: ${leaked.join(", ")}`);
55
+ process.exit(1);
56
+ }
57
+
58
+ // Export parity proves the modules exist. It does NOT prove a bin can start:
59
+ // 0.12.0 passed parity and still shipped two bins that crashed on first line
60
+ // because they resolved assets relative to the wrong layout. Smoke the stage.
61
+ console.log("→ smoking staged bins");
62
+ run("node", [join(ROOT, "scripts/smoke-dist-bins.mjs"), STAGE]);
63
+
64
+ console.log(doPublish ? "→ publishing" : "→ packing (dry, no publish)");
65
+ run("npm", doPublish ? ["publish", "--access", "public"] : ["pack"], STAGE);
66
+
67
+ console.log(`\n${doPublish ? "published" : "packed"} from ${STAGE}`);
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env bash
2
+ # Re-record the hero CLI session. Deterministic: types a fixed script of REAL
3
+ # commands against the REAL CLI, so the hero can never drift from what Oracle
4
+ # actually does (the previous recording outlived a capability change and was
5
+ # still showing hyperevm 999 as fail-closed after it started routing).
6
+ set -euo pipefail
7
+ cd "$(dirname "$0")/.."
8
+ OUT=public/oracle-splash/assets/hero
9
+ CAST=/tmp/oracle-hero.cast
10
+
11
+ type_line() {
12
+ local text="$1"
13
+ printf '%s' "$text"
14
+ sleep 0.5
15
+ printf '\n'
16
+ }
17
+
18
+ prompt() { printf '\033[38;5;110moracle\033[0m \033[38;5;245m›\033[0m '; }
19
+
20
+ # ONE source of truth per command: typed on screen AND executed.
21
+ CMD_CHAINS='scan chains'
22
+ CMD_QUOTE='scan quote hyperevm 0x5555555555555555555555555555555555555555 0xB8CE59FC3717ada4C02eaDF9682A9e934F625ebb 1000000000000000000'
23
+
24
+ run_demo() {
25
+ clear
26
+ prompt
27
+ type_line "$CMD_CHAINS"
28
+ node bin/oracle.mjs $CMD_CHAINS 2>&1 | head -20
29
+ echo
30
+ sleep 2.5
31
+ prompt
32
+ type_line "$CMD_QUOTE"
33
+ node bin/oracle.mjs $CMD_QUOTE 2>&1 | tail -14 || true
34
+ echo
35
+ sleep 2.5
36
+ prompt
37
+ sleep 1.5
38
+ }
39
+ export -f type_line prompt run_demo
40
+ export CMD_CHAINS CMD_QUOTE
41
+
42
+ rm -f "$CAST"
43
+ asciinema rec "$CAST" --cols 104 --rows 30 --overwrite \
44
+ --command "bash -c run_demo" --quiet
45
+
46
+ TMP=$(mktemp -d)
47
+ trap 'rm -rf "$TMP"' EXIT
48
+
49
+ agg "$CAST" "$TMP/cli.gif" \
50
+ --theme 0d1117,c9d1d9,000000,ff7b72,3fb950,d29922,58a6ff,bc8cff,39c5cf,b1bac4,6e7681,ffa198,56d364,e3b341,79c0ff,d2a8ff,56d4dd,f0f6fc \
51
+ --font-size 16 --line-height 1.4 --speed 1.0 --fps-cap 30
52
+
53
+ # Two constraints, both mandatory:
54
+ # - format=yuv420p: agg's GIF decodes as `gbrap` (planar RGB+alpha) and
55
+ # libvpx-vp9 flatly refuses that pixel format. This is what actually broke the
56
+ # earlier encode, not the dimensions.
57
+ # - even width/height: yuv420p chroma subsampling requires it.
58
+ SCALE="scale=868:-2:flags=lanczos,crop=trunc(iw/2)*2:trunc(ih/2)*2,format=yuv420p"
59
+
60
+ ffmpeg -y -v error -i "$TMP/cli.gif" -vf "$SCALE" \
61
+ -c:v libvpx-vp9 -crf 34 -b:v 0 -an "$TMP/cli.webm"
62
+
63
+ ffmpeg -y -v error -i "$TMP/cli.gif" -vf "$SCALE" \
64
+ -c:v libx264 -pix_fmt yuv420p -crf 24 -movflags +faststart -an "$TMP/cli.mp4"
65
+
66
+ ffmpeg -y -v error -ss 6 -i "$TMP/cli.webm" -frames:v 1 -q:v 3 "$TMP/cli.jpg"
67
+
68
+ # Prove every artifact before it is allowed near the shipped tree.
69
+ for f in "$TMP/cli.webm" "$TMP/cli.mp4" "$TMP/cli.jpg"; do
70
+ [ -s "$f" ] || { echo "REFUSING: $f is empty, shipped assets untouched" >&2; exit 1; }
71
+ ffprobe -v error -show_entries stream=width,height -of csv=p=0 "$f" >/dev/null \
72
+ || { echo "REFUSING: $f is not decodable, shipped assets untouched" >&2; exit 1; }
73
+ done
74
+
75
+ mv "$TMP/cli.webm" "$OUT/cli-session.webm"
76
+ mv "$TMP/cli.mp4" "$OUT/cli-session.mp4"
77
+ mv "$TMP/cli.jpg" "$OUT/cli-session-poster.jpg"
78
+
79
+ ffprobe -v error -show_entries format=duration,size -show_entries stream=width,height \
80
+ -of default=noprint_wrappers=1 "$OUT/cli-session.webm"
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ // Pre-publication secret scan. Fails CLOSED: any hit is an error.
3
+ //
4
+ // Checks the working tree and every blob reachable from HEAD. Set
5
+ // ORACLE_SCAN_ALL_REFS=1 for an explicit audit of every fetched ref.
6
+
7
+ import { execFileSync } from "node:child_process";
8
+ import { validateMnemonic } from "@scure/bip39";
9
+ import { wordlist } from "@scure/bip39/wordlists/english";
10
+
11
+ const ROOT = execFileSync("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd(), encoding: "utf8" }).trim();
12
+
13
+ // Live values that must never appear. Sourced from the environment at scan
14
+ // time so the scanner itself contains no secrets.
15
+ function liveSecrets() {
16
+ const out = [];
17
+ const push = (label, value) => {
18
+ const v = String(value || "").trim();
19
+ if (v.length >= 8) out.push({ label, value: v });
20
+ };
21
+ for (const k of Object.keys(process.env)) {
22
+ if (/(_KEY|_SECRET|_TOKEN|_PASSPHRASE|_WIF|PRIVATE_KEY)$/i.test(k)) {
23
+ push(`env:${k}`, process.env[k]);
24
+ }
25
+ }
26
+ return out;
27
+ }
28
+
29
+ function isBip39Mnemonic(match) {
30
+ const words = match[0].trim().toLowerCase().split(/\s+/);
31
+ if (words.length !== 12 && words.length !== 24) return false;
32
+ return validateMnemonic(words.join(" "), wordlist);
33
+ }
34
+
35
+ const PATTERNS = [
36
+ { name: "private key (hex 64)", re: /\b(?:0x)?[0-9a-fA-F]{64}\b/, refine: (m, line) =>
37
+ /priv|secret|wif|seed|mnemonic|signer|wallet/i.test(line) && !/hash|digest|sha256|txid|commit|blob|sha1|0x0{40,}/i.test(line) },
38
+ { name: "BTC WIF", re: /\b[5KL][1-9A-HJ-NP-Za-km-z]{50,51}\b/ },
39
+ { name: "BIP39 seed phrase", re: /\b(?:[a-z]{3,8} ){11}(?:[a-z]{3,8})\b|\b(?:[a-z]{3,8} ){23}(?:[a-z]{3,8})\b/i, refine: isBip39Mnemonic },
40
+ { name: "AWS access key", re: /\bAKIA[0-9A-Z]{16}\b/ },
41
+ { name: "OpenAI key", re: /\bsk-[A-Za-z0-9_-]{20,}\b/ },
42
+ { name: "Anthropic key", re: /\bsk-ant-[A-Za-z0-9_-]{20,}\b/ },
43
+ { name: "GitHub token", re: /\bgh[pousr]_[A-Za-z0-9]{36,}\b/ },
44
+ { name: "Slack token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/ },
45
+ { name: "Telegram bot token", re: /\b\d{8,10}:[A-Za-z0-9_-]{35}\b/ },
46
+ { name: "PEM private key", re: /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY-----/ },
47
+ { name: "Solana keypair array", re: /\[\s*(?:\d{1,3}\s*,\s*){63}\d{1,3}\s*\]/ },
48
+ ];
49
+
50
+ // Paths whose matches are known-safe test fixtures.
51
+ const ALLOWED_PATHS = [
52
+ /^scripts\/secret-scan\.mjs$/,
53
+ /^package-lock\.json$/,
54
+ ];
55
+
56
+ // Literal strings that are documented, synthetic, or public by nature.
57
+ const ALLOWED_VALUES = [
58
+ "0x0123456789012345678901234567890123456789012345678901234567890123", // HL SDK public test vector
59
+ "L1aW4aubDFB7yfras2S1mN3bqg9nwySY8nkoLmJebSLD5BWv3ENZ",
60
+ "/-----BEGIN[A-Z ]*PRIVATE KEY-----/",
61
+ '{ value: "-----BEGIN EC PRIVATE KEY-----" }',
62
+ "0x0000000000000000000000000000000000000000",
63
+ ];
64
+
65
+ const PUBLIC_EMAIL_RE = /^(?:[0-9]+\+)?[a-z0-9_.-]+\[?bot\]?@users\.noreply\.github\.com$|^oracle@users\.noreply\.github\.com$|^noreply@github\.com$/i;
66
+ const PRIVATE_EMAIL_RE = /@(gmail|icloud|me|yahoo|outlook|hotmail|protonmail)\.com$|@(local|gmk)$|^fleet@|^agent@/i;
67
+ const HISTORY_SCOPE = process.env.ORACLE_SCAN_ALL_REFS === "1" ? "--all" : "HEAD";
68
+
69
+ function sh(cmd, args) {
70
+ return execFileSync(cmd, args, { cwd: ROOT, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
71
+ }
72
+
73
+ function redactSample(kind) {
74
+ return kind.startsWith("LIVE SECRET") ? "[REDACTED — real credential]" : "[REDACTED]";
75
+ }
76
+
77
+ function scanText(text, origin, findings) {
78
+ const lines = text.split("\n");
79
+ for (let i = 0; i < lines.length; i++) {
80
+ const line = lines[i];
81
+ if (line.length > 4000) continue;
82
+ for (const p of PATTERNS) {
83
+ const m = p.re.exec(line);
84
+ if (!m) continue;
85
+ if (ALLOWED_VALUES.some((v) => line.includes(v))) continue;
86
+ if (p.refine && !p.refine(m, line)) continue;
87
+ findings.push({ origin, line: i + 1, kind: p.name, sample: redactSample(p.name) });
88
+ }
89
+ for (const s of LIVE) {
90
+ if (line.includes(s.value)) {
91
+ findings.push({ origin, line: i + 1, kind: `LIVE SECRET ${s.label}`, sample: redactSample("LIVE SECRET") });
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ function parseEmail(identity) {
98
+ const match = /<([^<>\s]+)>$/.exec(identity.trim());
99
+ return match ? match[1].toLowerCase() : "";
100
+ }
101
+
102
+ function scanIdentities(findings) {
103
+ const identities = new Set(sh("git", ["log", HISTORY_SCOPE, "--format=%an <%ae>|%cn <%ce>"]).split(/[\n|]/).filter(Boolean));
104
+ for (const identity of identities) {
105
+ const email = parseEmail(identity);
106
+ if (!email) continue;
107
+ if (PRIVATE_EMAIL_RE.test(email) || !PUBLIC_EMAIL_RE.test(email)) {
108
+ findings.push({ origin: "git-history", line: 0, kind: "non-public git identity", sample: "[REDACTED]" });
109
+ }
110
+ }
111
+ return identities;
112
+ }
113
+
114
+ const LIVE = liveSecrets();
115
+ const findings = [];
116
+
117
+ // --- 1. working tree (tracked files only) ---
118
+ const tracked = sh("git", ["ls-files"]).split("\n").filter(Boolean);
119
+ for (const rel of tracked) {
120
+ if (ALLOWED_PATHS.some((r) => r.test(rel))) continue;
121
+ let content;
122
+ try {
123
+ content = sh("git", ["show", `:${rel}`]);
124
+ } catch {
125
+ continue; // binary or unreadable
126
+ }
127
+ if (content.includes("\u0000")) continue;
128
+ scanText(content, rel, findings);
129
+ }
130
+
131
+ // --- 2. every blob in history ---
132
+ const revs = sh("git", ["rev-list", HISTORY_SCOPE]).split("\n").filter(Boolean);
133
+ const seen = new Set();
134
+ let historyBlobs = 0;
135
+ for (const rev of revs) {
136
+ const entries = sh("git", ["ls-tree", "-r", rev]).split("\n").filter(Boolean);
137
+ for (const entry of entries) {
138
+ const [meta, path] = entry.split("\t");
139
+ const sha = meta.split(/\s+/)[2];
140
+ if (!sha || seen.has(sha)) continue;
141
+ seen.add(sha);
142
+ if (ALLOWED_PATHS.some((r) => r.test(path))) continue;
143
+ let content;
144
+ try {
145
+ content = sh("git", ["cat-file", "-p", sha]);
146
+ } catch {
147
+ continue;
148
+ }
149
+ if (content.includes("\u0000")) continue;
150
+ historyBlobs++;
151
+ scanText(content, `history:${rev.slice(0, 8)}:${path}`, findings);
152
+ }
153
+ }
154
+
155
+ // --- 3. author identity leakage ---
156
+ const identities = scanIdentities(findings);
157
+
158
+ console.log(`scanned ${tracked.length} tracked files, ${historyBlobs} historical blobs, ${revs.length} commits`);
159
+ console.log(`live env secrets checked: ${LIVE.length}`);
160
+ console.log(`git identities checked: ${identities.size}`);
161
+
162
+ if (findings.length) {
163
+ console.error(`\nFAIL — ${findings.length} finding(s):`);
164
+ for (const f of findings.slice(0, 40)) {
165
+ console.error(` ${f.origin}:${f.line} [${f.kind}] ${f.sample}`);
166
+ }
167
+ process.exit(1);
168
+ }
169
+ console.log("\nPASS — no secrets found in tree or history");
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ // Spawn every published bin from the STAGED layout and fail on a startup crash.
3
+ //
4
+ // This gate exists because 0.12.0 shipped two bins that died at module load:
5
+ // `oracle-data` read dist/package.json and `oracle init` read dist/profiles/,
6
+ // neither of which exists once the package is staged. Nothing caught it because
7
+ // verify-dist only compares export names, and every local run resolved the
8
+ // source tree where ../package.json happens to be real. Only the staged layout
9
+ // reproduces what a user installs, so the smoke has to run there.
10
+ //
11
+ // node scripts/smoke-dist-bins.mjs <stage-dir>
12
+
13
+ import { spawnSync } from "node:child_process";
14
+ import { existsSync, readFileSync } from "node:fs";
15
+ import { join, resolve } from "node:path";
16
+
17
+ const stage = resolve(process.argv[2] || ".publish-stage");
18
+ const manifest = JSON.parse(readFileSync(join(stage, "package.json"), "utf8"));
19
+
20
+ // Servers block forever on purpose; a bounded run that reaches "listening"
21
+ // without crashing is the pass condition for those.
22
+ const SERVER_BINS = new Set(["oracle-data", "oracle-public"]);
23
+ const ARGS = { "oracle-upgrade": ["--json"] };
24
+ const FATAL = /ENOENT|Cannot find module|ERR_MODULE_NOT_FOUND|is not a function|is not defined/;
25
+
26
+ let failed = 0;
27
+ for (const [name, target] of Object.entries(manifest.bin || {})) {
28
+ const entry = join(stage, target);
29
+ if (!existsSync(entry)) {
30
+ console.log(` FAIL ${name.padEnd(18)} missing entry ${target}`);
31
+ failed += 1;
32
+ continue;
33
+ }
34
+ const args = ARGS[name] || ["--help"];
35
+ const run = spawnSync(process.execPath, [entry, ...args], {
36
+ encoding: "utf8",
37
+ timeout: SERVER_BINS.has(name) ? 6000 : 30000,
38
+ env: {
39
+ ...process.env,
40
+ // A server that binds a live port would collide with a real one.
41
+ ORACLE_DATA_PORT: "8791",
42
+ ORACLE_PUBLIC_PORT: "8792",
43
+ },
44
+ });
45
+ const output = `${run.stdout || ""}${run.stderr || ""}`;
46
+ const crashed = FATAL.test(output);
47
+ const died = !SERVER_BINS.has(name) && run.status === null && !run.error?.code?.includes("TIMEDOUT");
48
+ if (crashed || died) {
49
+ const first = output.split("\n").filter(Boolean).slice(0, 4).join(" | ").slice(0, 200);
50
+ console.log(` FAIL ${name.padEnd(18)} ${first}`);
51
+ failed += 1;
52
+ continue;
53
+ }
54
+ console.log(` OK ${name.padEnd(18)} started clean`);
55
+ }
56
+
57
+ // Spawning each bin directly is NOT enough. The `oracle` dispatcher resolves
58
+ // sibling bins through its own path helper, and that helper computed
59
+ // `<root>/bin/` — correct in the source tree, absent in the bundle. So
60
+ // `oracle-init` started clean while `oracle init` died with MODULE_NOT_FOUND
61
+ // for every installer. Exercise the routed form too.
62
+ const DISPATCHED = [
63
+ ["init", ["init"], /Cannot find module|MODULE_NOT_FOUND/],
64
+ ["scan", ["scan", "chains"], /Cannot find module|MODULE_NOT_FOUND/],
65
+ ["route", ["route"], /Cannot find module|MODULE_NOT_FOUND/],
66
+ ["upgrade", ["upgrade", "--json"], /Cannot find module|MODULE_NOT_FOUND/],
67
+ ["fees", ["fees", "status"], /Cannot find module|MODULE_NOT_FOUND/],
68
+ ];
69
+ const dispatcher = join(stage, (manifest.bin || {}).oracle || "");
70
+ for (const [label, argv, fatal] of DISPATCHED) {
71
+ const run = spawnSync(process.execPath, [dispatcher, ...argv], {
72
+ encoding: "utf8",
73
+ timeout: 45_000,
74
+ env: {
75
+ ...process.env,
76
+ ORACLE_FAKE_HOME: join(stage, ".smoke-home"),
77
+ },
78
+ });
79
+ const output = `${run.stdout || ""}${run.stderr || ""}`;
80
+ if (fatal.test(output)) {
81
+ console.log(` FAIL oracle ${label.padEnd(11)} ${output.split("\n").filter(Boolean).slice(0, 3).join(" | ").slice(0, 200)}`);
82
+ failed += 1;
83
+ continue;
84
+ }
85
+ console.log(` OK oracle ${label.padEnd(11)} dispatched clean`);
86
+ }
87
+
88
+ console.log(`\n${Object.keys(manifest.bin || {}).length} bins + ${DISPATCHED.length} dispatched commands, ${failed} broken`);
89
+ process.exitCode = failed ? 1 : 0;