dexterm-cli 0.1.6 → 0.1.7
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/dist/packages/agents/src/schema.js +22 -1
- package/dist/packages/agents/src/story.js +11 -2
- package/dist/packages/agents/src/tiers.js +27 -2
- package/dist/packages/agents/src/tools.js +30 -2
- package/dist/packages/autotrade/assets/exit-profile.schema.json +492 -0
- package/dist/packages/autotrade/assets/profiles/moonbag.json +46 -0
- package/dist/packages/autotrade/assets/profiles/runner.json +88 -0
- package/dist/packages/autotrade/assets/profiles/scalp.json +88 -0
- package/dist/packages/autotrade/assets/profiles/swing.json +88 -0
- package/dist/packages/autotrade/assets/strategies/moonbag.json +101 -0
- package/dist/packages/autotrade/assets/strategies/runner.json +101 -0
- package/dist/packages/autotrade/assets/strategies/sample-dip-ladder.json +188 -0
- package/dist/packages/autotrade/assets/strategies/scalp.json +98 -0
- package/dist/packages/autotrade/assets/strategies/swing.json +97 -0
- package/dist/packages/autotrade/assets/strategies/yolo.json +157 -0
- package/dist/packages/autotrade/assets/tapes/yolo-rehearsal.json +1 -0
- package/dist/packages/autotrade/src/account.js +74 -0
- package/dist/packages/autotrade/src/backtest.js +357 -0
- package/dist/packages/autotrade/src/basis-text.js +32 -0
- package/dist/packages/autotrade/src/chat/approvals.js +484 -0
- package/dist/packages/autotrade/src/chat/audit.js +140 -0
- package/dist/packages/autotrade/src/chat/config.js +93 -0
- package/dist/packages/autotrade/src/chat/connector.js +24 -0
- package/dist/packages/autotrade/src/chat/control.js +103 -0
- package/dist/packages/autotrade/src/chat/fake.js +100 -0
- package/dist/packages/autotrade/src/chat/format.js +71 -0
- package/dist/packages/autotrade/src/chat/hub.js +187 -0
- package/dist/packages/autotrade/src/chat/index.js +18 -0
- package/dist/packages/autotrade/src/chat/notify.js +292 -0
- package/dist/packages/autotrade/src/chat/pairing.js +46 -0
- package/dist/packages/autotrade/src/chat/redact.js +48 -0
- package/dist/packages/autotrade/src/chat/secrets.js +99 -0
- package/dist/packages/autotrade/src/chat/service.js +248 -0
- package/dist/packages/autotrade/src/chat/telegram.js +290 -0
- package/dist/packages/autotrade/src/desk-executor.js +188 -0
- package/dist/packages/autotrade/src/engine.js +387 -0
- package/dist/packages/autotrade/src/execution-port.js +97 -0
- package/dist/packages/autotrade/src/fleet-config.js +169 -0
- package/dist/packages/autotrade/src/fleet-control.js +276 -0
- package/dist/packages/autotrade/src/fleet.js +639 -0
- package/dist/packages/autotrade/src/index.js +53 -0
- package/dist/packages/autotrade/src/ledger.js +108 -0
- package/dist/packages/autotrade/src/live-source.js +182 -0
- package/dist/packages/autotrade/src/monitor-daemon.js +715 -0
- package/dist/packages/autotrade/src/monitor.js +190 -0
- package/dist/packages/autotrade/src/ollama-sessions.js +137 -0
- package/dist/packages/autotrade/src/paper-accounts.js +72 -0
- package/dist/packages/autotrade/src/replay.js +198 -0
- package/dist/packages/autotrade/src/runner-config.js +99 -0
- package/dist/packages/autotrade/src/runner.js +872 -0
- package/dist/packages/autotrade/src/safety.js +243 -0
- package/dist/packages/autotrade/src/session.js +269 -0
- package/dist/packages/autotrade/src/sessions.js +503 -0
- package/dist/packages/autotrade/src/store.js +250 -0
- package/dist/packages/autotrade/src/strategy.js +256 -0
- package/dist/packages/autotrade/src/trade-ledger.js +241 -0
- package/dist/packages/autotrade/src/yolo.js +140 -0
- package/dist/packages/cli/assets/claude/analyst-system.md +4 -4
- package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +1 -1
- package/dist/packages/cli/src/ai-cmd.js +412 -0
- package/dist/packages/cli/src/analyst/backend.js +82 -15
- package/dist/packages/cli/src/analyst/codex.js +14 -9
- package/dist/packages/cli/src/analyst/ollama.js +263 -0
- package/dist/packages/cli/src/analyst/session.js +5 -2
- package/dist/packages/cli/src/app-help-gen.js +44 -8
- package/dist/packages/cli/src/autotrade-cmd/audit.js +57 -0
- package/dist/packages/cli/src/autotrade-cmd/backtest.js +199 -0
- package/dist/packages/cli/src/autotrade-cmd/flatten.js +64 -0
- package/dist/packages/cli/src/autotrade-cmd/fleet.js +397 -0
- package/dist/packages/cli/src/autotrade-cmd/requests.js +79 -0
- package/dist/packages/cli/src/autotrade-cmd/run.js +413 -0
- package/dist/packages/cli/src/autotrade-cmd/stop.js +76 -0
- package/dist/packages/cli/src/autotrade-cmd/strategies.js +198 -0
- package/dist/packages/cli/src/autotrade-cmd/strategy-control.js +174 -0
- package/dist/packages/cli/src/autotrade-cmd/telegram-host.js +101 -0
- package/dist/packages/cli/src/autotrade-cmd.js +168 -0
- package/dist/packages/cli/src/display.js +156 -17
- package/dist/packages/cli/src/doctor.js +62 -3
- package/dist/packages/cli/src/export.js +10 -2
- package/dist/packages/cli/src/index.js +1 -1
- package/dist/packages/cli/src/ledger-cmd.js +288 -0
- package/dist/packages/cli/src/live/chart-fills.js +46 -0
- package/dist/packages/cli/src/live/index.js +23 -89
- package/dist/packages/cli/src/live/screens/token-live.js +9 -6
- package/dist/packages/cli/src/live/trade.js +12 -457
- package/dist/packages/cli/src/live/watchlist.js +1 -1
- package/dist/packages/cli/src/main.js +147 -190
- package/dist/packages/cli/src/mcp-cmd.js +7 -1
- package/dist/packages/cli/src/plan-cmd.js +1 -1
- package/dist/packages/cli/src/pnl-app.js +31 -21
- package/dist/packages/cli/src/pnl-card.js +158 -21
- package/dist/packages/cli/src/popup.js +22 -6
- package/dist/packages/cli/src/record-cmd.js +141 -20
- package/dist/packages/cli/src/screens/agent-hud.js +34 -2
- package/dist/packages/cli/src/screens/analyst-session.js +7 -4
- package/dist/packages/cli/src/screens/analyst.js +3 -2
- package/dist/packages/cli/src/screens/autotrade-keys.js +169 -0
- package/dist/packages/cli/src/screens/autotrade-proposals.js +123 -0
- package/dist/packages/cli/src/screens/autotrade-screen.js +725 -0
- package/dist/packages/cli/src/screens/autotrade-ui.js +640 -0
- package/dist/packages/cli/src/screens/autotrade-worker.js +89 -0
- package/dist/packages/cli/src/screens/brain.js +37 -11
- package/dist/packages/cli/src/screens/overlay.js +5 -2
- package/dist/packages/cli/src/screens/plans.js +5 -17
- package/dist/packages/cli/src/screens/pnl-chip.js +9 -8
- package/dist/packages/cli/src/screens/positions.js +6 -28
- package/dist/packages/cli/src/screens/ticket.js +38 -205
- package/dist/packages/cli/src/screens/token.js +3 -3
- package/dist/packages/cli/src/state.js +25 -19
- package/dist/packages/cli/src/telegram-cmd.js +451 -0
- package/dist/packages/cli/src/trade.js +3 -128
- package/dist/packages/cli/src/version.js +1 -1
- package/dist/packages/cli/src/wallet-cmd.js +39 -340
- package/dist/packages/cli/src/wallet-command.js +8 -11
- package/dist/packages/cli/src/widgets.js +0 -12
- package/dist/packages/custom/src/config.js +20 -2
- package/dist/packages/custom/src/schema.js +35 -10
- package/dist/packages/custom/src/workspace.js +3 -3
- package/dist/packages/data/src/basis.js +191 -0
- package/dist/packages/data/src/detail.js +53 -2
- package/dist/packages/data/src/index.js +0 -14
- package/dist/packages/data/src/store.js +14 -5
- package/dist/packages/data/src/trade/agent/paper-desk.js +228 -16
- package/dist/packages/data/src/trade/agent/rendezvous.js +3 -2
- package/dist/packages/data/src/trade/bridge.js +4 -102
- package/dist/packages/data/src/trade/ledger/export.js +101 -0
- package/dist/packages/data/src/trade/ledger/file.js +135 -0
- package/dist/packages/data/src/trade/ledger/fold.js +191 -0
- package/dist/packages/data/src/trade/ledger/index.js +9 -0
- package/dist/packages/data/src/trade/ledger/schema.js +83 -0
- package/dist/packages/data/src/trade/ledger/sources.js +307 -0
- package/dist/packages/data/src/trade/ledger/stats.js +123 -0
- package/dist/packages/data/src/trade/ledger/tags.js +116 -0
- package/dist/packages/data/src/trade/ledger/view.js +51 -0
- package/dist/packages/data/src/trade/plans/index.js +0 -1
- package/dist/packages/data/src/trade/plans/service.js +3 -27
- package/dist/packages/mcp/assets/kb/app-help/autotrade-chat.md +48 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-parallel.md +42 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-runner.md +35 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-stop.md +37 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-strategies.md +35 -0
- package/dist/packages/mcp/assets/kb/app-help/autotrade-telegram.md +40 -0
- package/dist/packages/mcp/assets/kb/app-help/chart-trade-markers.md +42 -0
- package/dist/packages/mcp/assets/kb/app-help/link-a-wallet.md +4 -10
- package/dist/packages/mcp/assets/kb/app-help/live-trading.md +38 -0
- package/dist/packages/mcp/assets/kb/app-help/live-yolo.md +34 -0
- package/dist/packages/mcp/assets/kb/app-help/order-plans.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/price-or-marketcap.md +5 -2
- package/dist/packages/mcp/assets/kb/app-help/screen-analyst.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-autotrade.md +217 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-kol.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-newpairs.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-screener.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-token.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-trending.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/screen-watchlist.md +3 -0
- package/dist/packages/mcp/assets/kb/app-help/standing-mandates.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/trade-ledger.md +54 -0
- package/dist/packages/mcp/assets/kb/app-help/use-local-model.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +4 -1
- package/dist/packages/mcp/assets/kb/docs/docs-agents-reading-your-trade-ledger.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-a-local-model-instead.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-backtests-and-their-limits.md +56 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-change-a-strategy-by-chat.md +49 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-checking-the-record-of-a-run.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-comparing-them.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-exits-and-wakes.md +76 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-how-a-stop-reaches-the-runner.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-on-the-q-screen.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-one-strategy-or-all-of-them.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-paper-accounts.md +50 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-presets.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-running-it-all-day.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-sessions-and-their-limits.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-several-strategies-at-once.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-stopping-it.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-strategies-and-presets.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-autotrade-json-file.md +48 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-heartbeat.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-run-file-and-the-heartbeat.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-the-runner-and-candidate-sessions.md +45 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-each-session-shows-first.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-costs-claude-usage-per-session.md +58 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-is-paper-self-directed.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-which-account-day-caps-and-the-usage-guard.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade-your-strategies.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-autotrade.md +22 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +2 -2
- package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-markers.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-chart-y-axis.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +4 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +1 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +3 -1
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +8 -6
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-recorded-history-and-retention.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +1 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +3 -3
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-changed-in-0-1-7.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-stopping.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-the-short-version.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-using-a-trading-bot-with-dexterm.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does-not-do.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading-what-dexterm-does.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-live-trading.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-another-machine.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-autotrade-on-a-local-model.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-check-your-model-dexterm-ai-probe.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-how-we-checked.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-models-without-tool-calling.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-pick-the-engine-globally-or-per-surface.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-restriction-profiles.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-set-it-up-in-two-minutes.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-troubleshooting.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-runs-on-a-local-model.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-what-stays-outside-the-model.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-which-model.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama-your-own-agent-on-the-local-model.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-ollama.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet-read-only.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +4 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-paper-only-mandates.md +6 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +7 -7
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-safety-model.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +3 -4
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-trade-ledger.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +4 -5
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-buy-and-sell-markers.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +2 -1
- package/dist/packages/mcp/assets/kb/docs/docs-screens-autotrade-paper.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-brain-view-and-the-pnl-chip.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-approve-one-tap-entries.md +50 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-control-the-commands.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-if-something-goes-wrong.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-notify-what-reaches-your-phone.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-set-it-up.md +47 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-the-record.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-is.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-telegram.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +4 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-voice.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-1-replay-it-on-your-own-history.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-2-run-it-on-paper.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-3-watch-it-and-stop-it.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-the-rules.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-is.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo-what-it-will-not-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-yolo.md +26 -0
- package/dist/packages/mcp/assets/kb/entries/autotrade.md +38 -0
- package/dist/packages/mcp/src/app-help.js +1 -1
- package/dist/packages/mcp/src/autotrade-tools.js +944 -0
- package/dist/packages/mcp/src/backtest-requests.js +71 -0
- package/dist/packages/mcp/src/engine/config.js +159 -0
- package/dist/packages/mcp/src/engine/index.js +10 -0
- package/dist/packages/mcp/src/engine/loop.js +101 -0
- package/dist/packages/mcp/src/engine/mcp-client.js +123 -0
- package/dist/packages/mcp/src/engine/ollama.js +258 -0
- package/dist/packages/mcp/src/engine/probe.js +110 -0
- package/dist/packages/mcp/src/engine/reason.js +35 -0
- package/dist/packages/mcp/src/engine/restrictions.js +111 -0
- package/dist/packages/mcp/src/index.js +7 -1
- package/dist/packages/mcp/src/ledger-tools.js +346 -0
- package/dist/packages/mcp/src/paper-agent.js +2 -0
- package/dist/packages/mcp/src/server.js +127 -19
- package/dist/packages/packs/src/backtest.js +3 -1
- package/dist/packages/popup/src/pages/chart-lib.js +134 -21
- package/dist/packages/popup/src/pages/chart.css +9 -0
- package/dist/packages/popup/src/pages/chart.html +3 -1
- package/dist/packages/popup/src/pages/chart.js +104 -7
- package/dist/packages/popup/src/protocol.js +2 -0
- package/dist/packages/popup/src/server.js +4 -0
- package/dist/packages/recorder/src/index.js +2 -0
- package/dist/packages/recorder/src/recorder.js +63 -6
- package/dist/packages/recorder/src/retention.js +100 -0
- package/dist/packages/recorder/src/schema.js +34 -1
- package/dist/packages/recorder/src/ticks.js +237 -0
- package/dist/packages/tui/src/index.js +1 -0
- package/dist/packages/tui/src/keymap.js +21 -1
- package/dist/packages/tui/src/markers.js +219 -0
- package/dist/packages/tui/src/widgets.js +149 -2
- package/package.json +2 -1
- package/dist/packages/data/src/trade/caps.js +0 -323
- package/dist/packages/data/src/trade/executor.js +0 -933
- package/dist/packages/data/src/trade/plans/executor-live.js +0 -220
- package/dist/packages/data/src/trade/rpc-exec.js +0 -229
- package/dist/packages/data/src/trade/signer/client.js +0 -197
- package/dist/packages/data/src/trade/signer/fast-wallet.js +0 -154
- package/dist/packages/data/src/trade/signer/host.js +0 -97
- package/dist/packages/data/src/trade/signer/main.js +0 -121
- package/dist/packages/data/src/trade/signer/probe-builder.js +0 -85
- package/dist/packages/data/src/trade/signer/protocol.js +0 -92
- package/dist/packages/data/src/trade/signer/service.js +0 -400
- package/dist/packages/data/src/trade/signer/sol-usd-feed.js +0 -98
- package/dist/packages/data/src/trade/sol-usd.js +0 -86
- package/dist/packages/data/src/trade/swap-build.js +0 -108
- package/dist/packages/data/src/trade/token-delta.js +0 -201
- package/dist/packages/data/vendor/solana-web3/LICENSE +0 -20
- package/dist/packages/data/vendor/solana-web3/NOTICE.md +0 -13
- package/dist/packages/data/vendor/solana-web3/index.iife.min.js +0 -20
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +0 -42
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +0 -34
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +0 -35
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +0 -33
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +0 -32
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +0 -30
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +0 -31
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +0 -41
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +0 -34
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +0 -37
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +0 -41
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
// dexterm — trade ticket screen (task-1310 T0
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
// the RPC it talks to) — never from a flag the UI holds, so the label cannot disagree with the
|
|
7
|
-
// connection. Pure renderer: the state machine + bindings live elsewhere; nothing here signs.
|
|
8
|
-
import { Canvas, badge, header, footer, breakpoint, mix, isCalm, fmtPrice, fmtPriceBare, fmtAmount, fmtPct, } from '../../../tui/src/index.js';
|
|
1
|
+
// dexterm — trade ticket screen (task-1310 T0). PAPER only: a simulated buy/sell priced from a live keyless
|
|
2
|
+
// Jupiter quote, every frame labelled PAPER. task-1571: there is no LIVE ticket — dexterm holds no key and signs
|
|
3
|
+
// nothing; live trading happens in the Telegram trading bot of the user's choice. Pure renderer.
|
|
4
|
+
import { Canvas, badge, header, footer, breakpoint, mix, isCalm, fmtPrice, fmtPriceBare, fmtAmount, fmtPct, fmtMcap, } from '../../../tui/src/index.js';
|
|
5
|
+
import { priceModeOf, supplyForMint } from "../display.js";
|
|
9
6
|
import { lamportsToSol, rawToTokens } from '../../../data/src/index.js';
|
|
10
7
|
import { headerModel } from "../state.js";
|
|
11
|
-
import { slippageBps
|
|
8
|
+
import { slippageBps } from "../trade.js";
|
|
12
9
|
function fmtSol(sol, digits = 4) {
|
|
13
10
|
const a = Math.abs(sol);
|
|
14
11
|
return `${a.toFixed(digits)} SOL`;
|
|
@@ -22,83 +19,41 @@ function tokenAmount(raw, decimals, symbol, decimalsKnown) {
|
|
|
22
19
|
return `${symbol}: decimals unknown yet (raw ${raw.toString()})`;
|
|
23
20
|
return `${fmtAmount(rawToTokens(raw, decimals))} ${symbol}`;
|
|
24
21
|
}
|
|
25
|
-
/** Word-wrap `text` into at most `maxLines` lines of `width` columns; the last line is cut with an ellipsis. */
|
|
26
|
-
function wrapLines(text, width, maxLines) {
|
|
27
|
-
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
28
|
-
const lines = [];
|
|
29
|
-
let cur = '';
|
|
30
|
-
for (const w of words) {
|
|
31
|
-
const next = cur ? `${cur} ${w}` : w;
|
|
32
|
-
if (next.length <= width) {
|
|
33
|
-
cur = next;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (cur)
|
|
37
|
-
lines.push(cur);
|
|
38
|
-
cur = w.length > width ? `${w.slice(0, Math.max(1, width - 1))}…` : w;
|
|
39
|
-
if (lines.length === maxLines)
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
if (cur && lines.length < maxLines)
|
|
43
|
-
lines.push(cur);
|
|
44
|
-
if (lines.length > maxLines)
|
|
45
|
-
lines.length = maxLines;
|
|
46
|
-
const joined = lines.join(' ');
|
|
47
|
-
if (joined.length < text.length && lines.length === maxLines) {
|
|
48
|
-
const last = lines[maxLines - 1];
|
|
49
|
-
lines[maxLines - 1] = last.length >= width - 1 ? `${last.slice(0, Math.max(1, width - 1))}…` : `${last}…`;
|
|
50
|
-
}
|
|
51
|
-
return lines;
|
|
52
|
-
}
|
|
53
22
|
export function renderTicket(c, state) {
|
|
54
23
|
const t = c.theme;
|
|
55
24
|
header(c, headerModel(state));
|
|
56
25
|
const bp = breakpoint(c.w);
|
|
57
26
|
// Live binding is the source of truth; the seeded demo view backs fixture/one-shot frames.
|
|
58
27
|
const view = (state.live?.ticket ? state.live.ticket.view() : state.ticket) ?? null;
|
|
59
|
-
|
|
60
|
-
const isLive = !!live;
|
|
61
|
-
// Always-on banner strip (never hidden, any state). PAPER = warn tint; LIVE = the signer's network.
|
|
28
|
+
// Always-on banner strip (never hidden, any state).
|
|
62
29
|
const bannerY = 2;
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
c.fill(0, bannerY, c.w, 1, ' ', { bg: mix(t.bg, bannerColor, mainnet ? 0.3 : 0.16) });
|
|
67
|
-
const banner = !isLive
|
|
68
|
-
? ' ◈ PAPER TRADING — simulated · no real orders · no keys · no signing '
|
|
69
|
-
: net === null
|
|
70
|
-
? ' ◉ LIVE — signer not reachable · nothing can be signed '
|
|
71
|
-
: mainnet
|
|
72
|
-
? ` ⚠ LIVE · MAINNET — REAL FUNDS · caps $${live?.signer?.caps.perTradeUsd ?? '?'}/trade $${live?.signer?.caps.dailyUsd ?? '?'}/day · Phantom signs · dexterm holds no key `
|
|
73
|
-
: ` ◉ LIVE · DEVNET — real signing via Phantom · devnet funds only · dexterm holds no key `;
|
|
74
|
-
c.text(2, bannerY, banner, { fg: bannerColor, bg: mix(t.bg, bannerColor, mainnet ? 0.3 : 0.16), b: true });
|
|
30
|
+
const bannerColor = t.warn;
|
|
31
|
+
c.fill(0, bannerY, c.w, 1, ' ', { bg: mix(t.bg, bannerColor, 0.16) });
|
|
32
|
+
c.text(2, bannerY, ' ◈ PAPER TRADING — simulated · no real orders · no keys · no signing ', { fg: bannerColor, bg: mix(t.bg, bannerColor, 0.16), b: true });
|
|
75
33
|
const linked = state.live?.linkedWallet;
|
|
76
34
|
if (linked)
|
|
77
|
-
c.textR(2, bannerY, c.w - 3, `linked: ${linked.publicKey.slice(0, 4)}…${linked.publicKey.slice(-4)} `, { fg: t.muted, bg: mix(t.bg, bannerColor,
|
|
35
|
+
c.textR(2, bannerY, c.w - 3, `linked: ${linked.publicKey.slice(0, 4)}…${linked.publicKey.slice(-4)} `, { fg: t.muted, bg: mix(t.bg, bannerColor, 0.16) });
|
|
78
36
|
c.noRain(0, bannerY, c.w, 1);
|
|
79
|
-
if (live && (live.signer?.panic || live.signer?.ledgerLocked)) {
|
|
80
|
-
c.fill(0, bannerY + 1, c.w, 1, ' ', { bg: mix(t.bg, t.down, 0.3) });
|
|
81
|
-
c.text(2, bannerY + 1, ' ⛔ PANIC — live signing is disabled · re-enable only from a shell: dexterm wallet resume ', { fg: t.down, bg: mix(t.bg, t.down, 0.3), b: true });
|
|
82
|
-
c.noRain(0, bannerY + 1, c.w, 1);
|
|
83
|
-
}
|
|
84
37
|
if (!view) {
|
|
85
|
-
c.text(2, 4, 'Open a trade ticket from a token screen: B buy · S sell
|
|
38
|
+
c.text(2, 4, 'Open a paper trade ticket from a token screen: B buy · S sell', { fg: t.muted, bg: t.bg });
|
|
86
39
|
footer(c, [['esc', 'back'], ['P', 'positions'], ['q', 'quit']], t.name, isCalm(state.vfx));
|
|
87
40
|
return;
|
|
88
41
|
}
|
|
89
42
|
const ts = view.ticket;
|
|
43
|
+
const mode = priceModeOf(state); // task-1537: fills and prices read as market caps by default
|
|
44
|
+
const sup = supplyForMint(state, ts.mint);
|
|
90
45
|
const buy = ts.side === 'buy';
|
|
91
46
|
const sideColor = buy ? t.up : t.down;
|
|
92
47
|
const top = 4;
|
|
93
48
|
const w = Math.min(bp === 'compact' ? c.w - 2 : 78, c.w - 2);
|
|
94
49
|
const x0 = 1;
|
|
95
50
|
const h = c.h - top - 1;
|
|
96
|
-
const title =
|
|
97
|
-
const caption =
|
|
51
|
+
const title = `◈ PAPER ${ts.side.toUpperCase()} TICKET`;
|
|
52
|
+
const caption = 'jupiter keyless quote · paper fill';
|
|
98
53
|
// task-1340: the ticket is PLAIN by construction — no heading (no chromatic split on its title) and every cell of
|
|
99
54
|
// its rect is shielded below, so no effect pass (rain, mosh, shake, scanlines, trade moments) can write a glyph, a
|
|
100
55
|
// colour or a background into it in any phase. The banner rows above it are shielded too.
|
|
101
|
-
const box = c.box(x0, top, w, h, { title, titleFg:
|
|
56
|
+
const box = c.box(x0, top, w, h, { title, titleFg: sideColor, caption, captionFg: t.dim, border: mix(t.border, sideColor, 0.5), plain: true });
|
|
102
57
|
c.shieldRect(x0, top, w, h);
|
|
103
58
|
c.shieldRect(0, bannerY, c.w, 2);
|
|
104
59
|
const bg = box.bg;
|
|
@@ -109,24 +64,18 @@ export function renderTicket(c, state) {
|
|
|
109
64
|
let x = c.text(ix, y, `$${ts.symbol}`, { fg: t.borderFocus, bg, b: true });
|
|
110
65
|
x = c.text(x + 1, y, `${ts.mint.slice(0, 4)}…${ts.mint.slice(-4)}`, { fg: t.dim, bg });
|
|
111
66
|
x = badge(c, x + 2, y, buy ? '▲ BUY' : '▼ SELL', sideColor, { on: bg, bold: true }) + 1;
|
|
112
|
-
x = badge(c, x + 1, y,
|
|
113
|
-
c.textR(ix, y, iw, ts.phase === 'editing' ? '← → flip side
|
|
67
|
+
x = badge(c, x + 1, y, 'PAPER', t.warn, { on: bg, bold: true }) + 1;
|
|
68
|
+
c.textR(ix, y, iw, ts.phase === 'editing' ? '← → flip side' : '', { fg: t.dim, bg });
|
|
114
69
|
y += 2;
|
|
115
70
|
// size field
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (showPlan && live?.plan) {
|
|
125
|
-
y = renderPlan(c, ix, y, iw, bg, live, ts.decimals, ts.symbol, buy, state.now.getTime());
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
// quote block (paper warm quote; LIVE editing shows the same keyless quote as a preview)
|
|
129
|
-
c.text(ix, y, isLive ? 'PREVIEW QUOTE (keyless; the signer re-quotes on ⏎)' : 'QUOTE', { fg: t.dim, bg });
|
|
71
|
+
const sizeUnit = buy ? (ts.sizeUnit === 'sol' ? 'SOL' : '% of balance') : '% of position';
|
|
72
|
+
field(c, ix, y, iw, bg, 'Size', `${ts.sizeInput || '—'} ${sizeUnit}`, ts.field === 'size' && ts.phase === 'editing', t);
|
|
73
|
+
y += 1;
|
|
74
|
+
field(c, ix, y, iw, bg, 'Slippage', `${slippageBps(ts)} bps`, ts.field === 'slippage' && ts.phase === 'editing', t);
|
|
75
|
+
y += 2;
|
|
76
|
+
{
|
|
77
|
+
// quote block (the paper warm quote)
|
|
78
|
+
c.text(ix, y, 'QUOTE', { fg: t.dim, bg });
|
|
130
79
|
c.textR(ix, y, iw, view.loading ? '· fetching…' : view.quote ? `· ${Math.max(0, Math.round((view.quoteAgeMs ?? 0) / 1000))}s ago` : view.error ? '· unavailable' : '', { fg: view.error ? t.down : t.dim, bg });
|
|
131
80
|
c.hline(box.x + 1, y + 1, box.w - 2, { fg: t.border, bg, soft: true });
|
|
132
81
|
y += 2;
|
|
@@ -139,51 +88,29 @@ export function renderTicket(c, state) {
|
|
|
139
88
|
const recv = buy ? tokenAmount(tokenAbs, ts.decimals, ts.symbol, decimalsKnown) : `${fmtSol(lamportsToSol(preview.solDelta))}`;
|
|
140
89
|
kv(c, ix, y++, iw, bg, 'You pay', spend, t, buy ? t.down : t.text);
|
|
141
90
|
kv(c, ix, y++, iw, bg, 'You receive', recv, t, buy && !decimalsKnown ? t.warn : t.up);
|
|
142
|
-
|
|
91
|
+
// task-1537: in the market-cap basis (default) the fill price reads as the cap it buys/sells at, the price beside it
|
|
92
|
+
const capAt = mode === 'mcap' && sup !== null && preview.priceUsd !== null ? fmtMcap(preview.priceUsd * sup) : null;
|
|
93
|
+
kv(c, ix, y++, iw, bg, capAt ? 'At mcap' : 'Price', decimalsKnown ? `${capAt ? `${capAt} · ` : ''}${fmtPriceBare(preview.priceSol)} SOL${preview.priceUsd !== null ? ` · ${fmtPrice(preview.priceUsd)}` : ''}` : 'per-token price needs the decimals', t, decimalsKnown ? t.text : t.warn);
|
|
143
94
|
const impact = preview.priceImpactPct;
|
|
144
95
|
kv(c, ix, y++, iw, bg, 'Price impact', impact === null ? '—' : fmtPct(impact, { sign: false }), t, impact !== null && impact > 5 ? t.down : impact !== null && impact > 1 ? t.warn : t.muted);
|
|
145
96
|
kv(c, ix, y++, iw, bg, 'Min received', buy ? tokenAmount(q.otherAmountThreshold, ts.decimals, ts.symbol, decimalsKnown) : fmtSol(lamportsToSol(q.otherAmountThreshold)), t, t.muted);
|
|
146
|
-
kv(c, ix, y++, iw, bg,
|
|
97
|
+
kv(c, ix, y++, iw, bg, 'Sim fee', fmtSol(lamportsToSol(preview.feeLamports), 6), t, t.muted);
|
|
147
98
|
kv(c, ix, y++, iw, bg, 'Route', q.route.length ? q.route.join(' → ') : 'direct', t, t.accent);
|
|
148
99
|
}
|
|
149
100
|
else if (view.error) {
|
|
150
101
|
c.text(ix, y++, `⚠ ${view.error}`, { fg: t.down, bg }, iw);
|
|
151
102
|
}
|
|
152
|
-
else if (live?.probe) {
|
|
153
|
-
c.text(ix, y++, 'wrap 0.001 SOL into your own WSOL account, sync, memo, close it back — fees only', { fg: t.dim, bg }, iw);
|
|
154
|
-
}
|
|
155
103
|
else {
|
|
156
104
|
c.text(ix, y++, view.loading ? 'fetching a live quote…' : 'enter a size to see a quote', { fg: t.dim, bg }, iw);
|
|
157
105
|
}
|
|
158
|
-
// task-1368 items b + c: BEFORE ⏎ on a LIVE ticket — the size in USD against the signer's caps (red when the
|
|
159
|
-
// signer would refuse it, with the size that fits), and the devnet-cannot-fill-mainnet-tokens line.
|
|
160
|
-
if (isLive && live && !live.probe && ts.phase === 'editing') {
|
|
161
|
-
const pf = live.preflight ?? null;
|
|
162
|
-
if (pf) {
|
|
163
|
-
const color = pf.over ? t.down : pf.sizeUsd === null && pf.sizeSol > 0 ? t.warn : t.muted;
|
|
164
|
-
for (const line of wrapLines(`${pf.over ? '✗ ' : ''}${pf.line}`, iw, 2))
|
|
165
|
-
c.text(ix, y++, line, { fg: color, bg, b: pf.over }, iw);
|
|
166
|
-
}
|
|
167
|
-
if (live.devnetWarning)
|
|
168
|
-
for (const line of wrapLines(`⚠ ${live.devnetWarning}`, iw, 2))
|
|
169
|
-
c.text(ix, y++, line, { fg: t.warn, bg, b: true }, iw);
|
|
170
|
-
}
|
|
171
106
|
y += 1;
|
|
172
107
|
}
|
|
173
108
|
// wallet line
|
|
174
109
|
c.hline(box.x + 1, y, box.w - 2, { fg: t.border, bg, soft: true });
|
|
175
110
|
y += 1;
|
|
176
|
-
|
|
177
|
-
kv(c, ix, y++, iw, bg, 'Signer', live?.signer ? `${live.signer.network.toUpperCase()} · ${live.signer.rpcHost} · pid ${live.signer.pid}` : (live?.error ?? 'not reachable'), t, live?.signer ? t.text : t.down);
|
|
178
|
-
if (live?.signer)
|
|
179
|
-
kv(c, ix, y++, iw, bg, 'Caps', `$${live.signer.caps.perTradeUsd}/trade · $${live.signer.caps.dailyUsd}/day · spent $${live.signer.spentTodayUsd.toFixed(2)} · impact ≤ ${live.signer.caps.maxPriceImpactPct}% · ≤ ${live.signer.caps.maxSolOut} SOL out`, t, t.muted);
|
|
180
|
-
kv(c, ix, y++, iw, bg, 'Wallet', live?.linked ? `${live.linked} (Phantom signs; dexterm holds no key)` : 'none linked', t, live?.linked ? t.text : t.down);
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
kv(c, ix, y++, iw, bg, 'Paper balance', fmtSol(view.balanceSol), t, t.text);
|
|
184
|
-
}
|
|
111
|
+
kv(c, ix, y++, iw, bg, 'Paper balance', fmtSol(view.balanceSol), t, t.text);
|
|
185
112
|
if (!buy || view.positionTokens > 0)
|
|
186
|
-
kv(c, ix, y++, iw, bg, `Position`, `${fmtAmount(view.positionTokens)} ${ts.symbol}
|
|
113
|
+
kv(c, ix, y++, iw, bg, `Position`, `${fmtAmount(view.positionTokens)} ${ts.symbol}`, t, t.muted);
|
|
187
114
|
y += 1;
|
|
188
115
|
// gate / receipt region
|
|
189
116
|
const gy = box.y + box.h - 3;
|
|
@@ -201,127 +128,33 @@ export function renderTicket(c, state) {
|
|
|
201
128
|
if (ts.message)
|
|
202
129
|
c.text(ix, gy + 1, ts.message, { fg: t.warn, bg: tint }, iw);
|
|
203
130
|
}
|
|
204
|
-
else if (ts.phase === 'planning' && live?.retryAt) {
|
|
205
|
-
// task-1368: rate limited by Jupiter — the plan is NOT dropped; countdown + r / esc.
|
|
206
|
-
const left = Math.max(0, Math.ceil((live.retryAt - state.now.getTime()) / 1000));
|
|
207
|
-
const what = (live.retryMessage ?? 'Jupiter is rate limiting this IP').replace(/; retry in \d+s$/, '');
|
|
208
|
-
c.fill(box.x + 1, gy, box.w - 2, 2, ' ', { bg: mix(bg, t.warn, 0.18) });
|
|
209
|
-
c.text(ix, gy, `⚠ ${what}, retrying in ${left}s`, { fg: t.warn, bg: mix(bg, t.warn, 0.18), b: true }, iw);
|
|
210
|
-
c.text(ix, gy + 1, 'r = retry now · esc = cancel · the plan is kept (nothing was built or signed)', { fg: t.muted, bg: mix(bg, t.warn, 0.18) }, iw);
|
|
211
|
-
}
|
|
212
|
-
else if (ts.phase === 'planning') {
|
|
213
|
-
c.text(ix, gy, 'signer: quote → build → decode → policy → simulate… (esc cancels)', { fg: t.ai, bg, b: true }, iw);
|
|
214
|
-
}
|
|
215
|
-
else if (ts.phase === 'plan' && live?.plan) {
|
|
216
|
-
const refused = !live.plan.policy.ok || !live.plan.precheck.ok;
|
|
217
|
-
c.fill(box.x + 1, gy, box.w - 2, 2, ' ', { bg: tint });
|
|
218
|
-
if (refused) {
|
|
219
|
-
const v = !live.plan.policy.ok ? live.plan.policy : live.plan.precheck;
|
|
220
|
-
c.text(ix, gy, `✗ the signer WILL REFUSE this plan: ${v.reason ?? ''} — ${v.message ?? ''}`, { fg: t.down, bg: tint, b: true }, iw);
|
|
221
|
-
c.text(ix, gy + 1, 'esc back to editing (Y asks anyway and gets the signer\'s refusal)', { fg: t.muted, bg: tint }, iw);
|
|
222
|
-
}
|
|
223
|
-
else if (ts.typebackRequired) {
|
|
224
|
-
c.text(ix, gy, `⚠ large order — type the size (${ts.sizeInput}) then press Y to sign in Phantom:`, { fg: t.warn, bg: tint, b: true }, iw);
|
|
225
|
-
c.text(ix, gy + 1, `▌ ${ts.typeback || ''}`, { fg: t.text, bg: tint, b: true });
|
|
226
|
-
}
|
|
227
|
-
else {
|
|
228
|
-
c.text(ix, gy, `${mainnet ? '⚠ REAL FUNDS · ' : ''}Y = sign this exact plan in Phantom (esc cancels · any other key cancels)`, { fg: mainnet ? t.down : sideColor, bg: tint, b: true }, iw);
|
|
229
|
-
c.text(ix, gy + 1, `the signer re-checks caps, verifies the signed bytes and re-simulates before it submits`, { fg: t.muted, bg: tint }, iw);
|
|
230
|
-
}
|
|
231
|
-
if (ts.message)
|
|
232
|
-
c.text(ix, gy + 1, ts.message, { fg: t.warn, bg: tint }, iw);
|
|
233
|
-
}
|
|
234
|
-
else if (ts.phase === 'signing') {
|
|
235
|
-
c.text(ix, gy, 'approve in Phantom (browser) — the signer verifies, re-simulates and submits…', { fg: t.ai, bg, b: true }, iw);
|
|
236
|
-
c.text(ix, gy + 1, 'nothing is sent until the signed bytes match the plan', { fg: t.muted, bg }, iw);
|
|
237
|
-
}
|
|
238
131
|
else if (ts.phase === 'filling') {
|
|
239
132
|
const line = view.rateLimited
|
|
240
133
|
? '⚠ rate limited by Jupiter — retrying… (esc cancels)'
|
|
241
134
|
: 'booking paper fill from a fresh quote… (esc cancels)';
|
|
242
135
|
c.text(ix, gy, line, { fg: view.rateLimited ? t.warn : t.ai, bg, b: true }, iw);
|
|
243
136
|
}
|
|
244
|
-
else if (ts.phase === 'filled' && isLive && live?.outcome?.kind === 'filled') {
|
|
245
|
-
const o = live.outcome;
|
|
246
|
-
const got = live.probe ? `wrap-and-unwrap confirmed · fee ${fmtSol(lamportsToSol(BigInt(o.fill.feeLamports)), 6)}` : `${fmtAmount(rawToTokens(o.fill.side === 'buy' ? BigInt(o.fill.tokenDelta) : -BigInt(o.fill.tokenDelta), o.fill.decimals))} ${o.fill.symbol} @ ${fmtPriceBare(o.fill.priceSol)} SOL`;
|
|
247
|
-
c.text(ix, gy, `✓ LIVE ${o.network.toUpperCase()} ${live.probe ? 'PROBE' : o.fill.side.toUpperCase()} confirmed — ${got}${o.lighthouseTail ? ` · +${o.lighthouseTail} Lighthouse` : ''}`, { fg: t.up, bg, b: true }, iw);
|
|
248
|
-
c.text(ix, gy + 1, `sig ${o.signature.slice(0, 12)}…${o.signature.slice(-6)} · esc=back · P=positions`, { fg: t.muted, bg }, iw);
|
|
249
|
-
}
|
|
250
137
|
else if (ts.phase === 'filled' && view.receipt) {
|
|
251
138
|
const r = view.receipt;
|
|
252
139
|
const got = r.side === 'buy' ? `${fmtAmount(rawToTokens(r.tokenDelta, r.decimals))} ${r.symbol}` : fmtSol(lamportsToSol(r.solDelta));
|
|
253
|
-
|
|
140
|
+
const at = mode === 'mcap' && sup !== null && r.priceUsd !== null ? `${fmtMcap(r.priceUsd * sup)} mcap (${fmtPriceBare(r.priceSol)} SOL)` : `${fmtPriceBare(r.priceSol)} SOL`; // task-1537
|
|
141
|
+
c.text(ix, gy, `✓ PAPER ${r.side.toUpperCase()} filled — ${got} @ ${at}`, { fg: t.up, bg, b: true }, iw);
|
|
254
142
|
const extra = r.side === 'sell' ? `realized ${r.realizedLamports >= 0n ? '+' : ''}${fmtSol(lamportsToSol(r.realizedLamports))}` : 'cost booked to position';
|
|
255
143
|
c.text(ix, gy + 1, `${extra} · esc=back to token · P=positions`, { fg: t.muted, bg }, iw);
|
|
256
144
|
}
|
|
257
|
-
else if (ts.phase === 'refused') {
|
|
258
|
-
c.text(ix, gy, `✗ REFUSED by the signer — ${ts.message ?? 'refused'}`, { fg: t.down, bg, b: true }, iw);
|
|
259
|
-
c.text(ix, gy + 1, 'nothing was signed or sent · esc=back · any key = new ticket', { fg: t.muted, bg }, iw);
|
|
260
|
-
}
|
|
261
145
|
else if (ts.phase === 'error') {
|
|
262
|
-
const unknown = live?.outcome?.kind === 'send-unknown';
|
|
263
146
|
c.text(ix, gy, `⚠ ${ts.message ?? 'order failed'}`, { fg: t.down, bg, b: true }, iw);
|
|
264
|
-
c.text(ix, gy + 1,
|
|
147
|
+
c.text(ix, gy + 1, 'esc=back to token · P=positions', { fg: t.muted, bg }, iw);
|
|
265
148
|
}
|
|
266
149
|
else {
|
|
267
|
-
c.text(ix, gy,
|
|
150
|
+
c.text(ix, gy, `⏎ review → Y confirm · gate ${ts.gateOn ? 'ON' : 'off'} (keypress required)`, { fg: t.muted, bg }, iw);
|
|
268
151
|
if (ts.message)
|
|
269
152
|
c.text(ix, gy + 1, ts.message, { fg: t.warn, bg }, iw);
|
|
270
153
|
}
|
|
271
|
-
const keys = [['⏎',
|
|
272
|
-
if (isLive && buy && ts.phase === 'editing' && !live?.probe)
|
|
273
|
-
keys.push(['f', 'fit cap']);
|
|
274
|
-
if (ts.phase === 'planning' && live?.retryAt)
|
|
275
|
-
keys.push(['r', 'retry now']);
|
|
154
|
+
const keys = [['⏎', 'review'], ['Y', 'confirm'], ['tab', 'field'], ['←→', 'side'], ['u', 'unit']];
|
|
276
155
|
keys.push(['esc', 'cancel'], ['P', 'positions']);
|
|
277
156
|
footer(c, keys, t.name, isCalm(state.vfx));
|
|
278
157
|
}
|
|
279
|
-
/** The PLAN block: everything the signer will sign, from the signer's own view. */
|
|
280
|
-
function renderPlan(c, ix, y, iw, bg, live, decimals, symbol, buy, now) {
|
|
281
|
-
const t = c.theme;
|
|
282
|
-
const p = live.plan;
|
|
283
|
-
const left = Math.max(0, Math.round((p.expiresAt - now) / 1000));
|
|
284
|
-
c.text(ix, y, `PLAN · ${p.network.toUpperCase()} · ${p.kind === 'probe' ? 'devnet probe' : 'jupiter swap'}`, { fg: p.network === 'mainnet' ? t.down : t.up, bg, b: true });
|
|
285
|
-
c.textR(ix, y, iw, `expires in ${left}s · ${p.hash.slice(0, 8)}`, { fg: left < 15 ? t.warn : t.dim, bg });
|
|
286
|
-
c.hline(ix - 1, y + 1, iw + 2, { fg: t.border, bg, soft: true });
|
|
287
|
-
y += 2;
|
|
288
|
-
const inRaw = BigInt(p.amountInRaw), outRaw = BigInt(p.amountOutRaw), minRaw = BigInt(p.minOutRaw);
|
|
289
|
-
if (p.kind === 'probe') {
|
|
290
|
-
kv(c, ix, y++, iw, bg, 'Wraps', `${fmtSol(lamportsToSol(inRaw))} → your own WSOL account → back to you`, t, t.text);
|
|
291
|
-
}
|
|
292
|
-
else {
|
|
293
|
-
// The plan's decimals are the ones the order was built with (the signer echoes them back).
|
|
294
|
-
const pay = buy ? fmtSol(lamportsToSol(inRaw)) : `${fmtAmount(rawToTokens(inRaw, p.decimals ?? decimals))} ${symbol}`;
|
|
295
|
-
const recv = buy ? `${fmtAmount(rawToTokens(outRaw, p.decimals ?? decimals))} ${symbol}` : fmtSol(lamportsToSol(outRaw));
|
|
296
|
-
const min = buy ? `${fmtAmount(rawToTokens(minRaw, p.decimals ?? decimals))} ${symbol}` : fmtSol(lamportsToSol(minRaw));
|
|
297
|
-
kv(c, ix, y++, iw, bg, 'You pay', pay, t, buy ? t.down : t.text);
|
|
298
|
-
kv(c, ix, y++, iw, bg, 'You receive', recv, t, t.up);
|
|
299
|
-
kv(c, ix, y++, iw, bg, 'Min received', `${min} (${p.slippageBps} bps slippage)`, t, t.muted);
|
|
300
|
-
const impact = p.priceImpactPct;
|
|
301
|
-
kv(c, ix, y++, iw, bg, 'Price impact', impact === null ? 'unknown' : fmtPct(impact, { sign: false }), t, impact !== null && impact > 3 ? t.down : impact !== null && impact > 1 ? t.warn : t.muted);
|
|
302
|
-
kv(c, ix, y++, iw, bg, 'Route', p.route.length ? p.route.join(' → ') : 'direct', t, t.accent);
|
|
303
|
-
}
|
|
304
|
-
kv(c, ix, y++, iw, bg, 'Fee', `${fmtSol(lamportsToSol(BigInt(p.feeLamports)), 6)}${p.prioritizationFeeLamports ? ` (incl. ${p.prioritizationFeeLamports} lamports priority)` : ''}`, t, t.muted);
|
|
305
|
-
kv(c, ix, y++, iw, bg, 'Notional', p.notionalUsd !== null ? `$${p.notionalUsd.toFixed(2)} (SOL $${p.solUsd.price?.toFixed(2) ?? '?'} via ${p.solUsd.sources?.join('+') ?? '?'})` : (p.network === 'mainnet' ? `unpriced — ${p.solUsd.reason ?? ''}` : 'devnet (no USD value)'), t, p.notionalUsd === null && p.network === 'mainnet' ? t.down : t.muted);
|
|
306
|
-
if (!p.sim.ran || p.sim.ok) {
|
|
307
|
-
kv(c, ix, y++, iw, bg, 'Simulation', !p.sim.ran ? 'not run' : `ok · ${p.sim.solOutLamports !== null ? `${fmtSol(lamportsToSol(BigInt(p.sim.solOutLamports)), 6)} leaves the wallet` : 'wallet delta unknown'}`, t, p.sim.ok ? t.up : t.down);
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
// task-1368 item f: the FULL RPC error, wrapped (it used to be cut to `invalid transaction: Tr…`), then the hint.
|
|
311
|
-
kv(c, ix, y++, iw, bg, 'Simulation', 'FAILED', t, t.down);
|
|
312
|
-
for (const line of wrapLines(p.sim.error ?? 'unknown error', iw - 2, 3))
|
|
313
|
-
c.text(ix + 2, y++, line, { fg: t.down, bg }, iw - 2);
|
|
314
|
-
const hint = simFailureHint(p, live.signer ? { perTradeUsd: live.signer.caps.perTradeUsd, dailyUsd: live.signer.caps.dailyUsd } : undefined);
|
|
315
|
-
if (hint)
|
|
316
|
-
for (const line of wrapLines(`↳ ${hint}`, iw - 2, 4))
|
|
317
|
-
c.text(ix + 2, y++, line, { fg: t.warn, bg }, iw - 2);
|
|
318
|
-
}
|
|
319
|
-
const ins = p.instructions.map((i) => `${i.program}${i.op ? `:${i.op}` : ''}`).join(' · ');
|
|
320
|
-
kv(c, ix, y++, iw, bg, 'Will sign', ins || '—', t, t.text);
|
|
321
|
-
kv(c, ix, y++, iw, bg, 'Policy', p.policy.ok ? 'swap shape ok · route bound to this plan · no fee account' : `REFUSE ${p.policy.reason}: ${p.policy.message}`, t, p.policy.ok ? t.up : t.down);
|
|
322
|
-
kv(c, ix, y++, iw, bg, 'Caps', p.precheck.ok ? 'within caps' : `REFUSE ${p.precheck.reason}: ${p.precheck.message}`, t, p.precheck.ok ? t.up : t.down);
|
|
323
|
-
return y + 1;
|
|
324
|
-
}
|
|
325
158
|
function field(c, x, y, w, bg, label, value, active, t) {
|
|
326
159
|
const lblW = 10;
|
|
327
160
|
c.text(x, y, label, { fg: t.dim, bg });
|
|
@@ -10,7 +10,7 @@ import { renderAnalystSession } from "./analyst-session.js";
|
|
|
10
10
|
import { renderSocialPanel } from "./social-panel.js";
|
|
11
11
|
import { brainFor, factsFromFixture, renderBrainPanel } from "./brain.js";
|
|
12
12
|
import { layoutFor } from "../custom.js";
|
|
13
|
-
import { chartMode, chartTitle, chartAxisOf, priceModeOf } from "../display.js";
|
|
13
|
+
import { chartMode, chartTitle, chartAxisOf, priceModeOf, levelCell, supplyRatio } from "../display.js";
|
|
14
14
|
export function renderToken(c, state) {
|
|
15
15
|
if (state.live?.token && state.screener.source !== 'fixtures')
|
|
16
16
|
return renderTokenLive(c, state, state.live.token.view); // task-1298: live data path
|
|
@@ -52,7 +52,7 @@ export function renderToken(c, state) {
|
|
|
52
52
|
const pm = chartMode(priceModeOf(state), tk.price, tk.mcap);
|
|
53
53
|
if (pm.kind === 'mcap') {
|
|
54
54
|
x = c.text(1, y, fmtMcap(tk.mcap), { fg: pumping ? t.rainPump[3] : t.text, bg: priceBg, b: true });
|
|
55
|
-
x = c.text(x, y, ` (${fmtPrice(tk.price)})`, { fg: t.dim, bg: priceBg });
|
|
55
|
+
x = c.text(x, y, ` (${fmtPrice(tk.price)})`, { fg: priceBg === t.bg ? t.dim : t.text, bg: priceBg }); // task-1537: readable on the pump / dump band
|
|
56
56
|
}
|
|
57
57
|
else
|
|
58
58
|
x = c.text(1, y, fmtPrice(tk.price), { fg: pm.label ? t.warn : pumping ? t.rainPump[3] : t.text, bg: priceBg, b: true });
|
|
@@ -162,7 +162,7 @@ export function renderToken(c, state) {
|
|
|
162
162
|
let cx = c.text(hb.x + 1, hy, fmtAgeSec(tr.ago).padStart(4), { fg: t.dim, bg: hb.bg });
|
|
163
163
|
cx = c.text(cx + 1, hy, tr.side === 'buy' ? '▲BUY ' : '▼SELL', { fg: color, bg: hb.bg, b: true });
|
|
164
164
|
cx = c.textR(cx + 1, hy, 8, fmtUsd(tr.usd), { fg: t.text, bg: hb.bg });
|
|
165
|
-
cx = c.text(cx + 2, hy,
|
|
165
|
+
cx = c.text(cx + 2, hy, levelCell(priceModeOf(state), supplyRatio(tk.price, tk.mcap), tr.price), { fg: t.muted, bg: hb.bg }); // task-1537
|
|
166
166
|
cx = c.text(cx + 2, hy, shortAddr(tr.addr, 3), { fg: t.dim, bg: hb.bg });
|
|
167
167
|
if (tr.tag)
|
|
168
168
|
badge(c, cx + 1, hy, tr.tag, tr.tag === 'smart' ? t.accent : t.warn, { on: hb.bg });
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// dexterm — app state consumed by the screens. Screens are pure render(canvas, state) functions;
|
|
2
2
|
// renderFrame() draws the screen, the toast, then runs the effects post-pass (VISUAL-V2 §3).
|
|
3
|
-
import { Canvas, THEMES, applyFx, toast, makeVfx, setSources, marketActivity, candleActivity, isCalm, breakpoint, } from '../../tui/src/index.js';
|
|
3
|
+
import { Canvas, THEMES, applyFx, toast, makeVfx, setSources, marketActivity, candleActivity, isCalm, breakpoint, fmtMcap, } from '../../tui/src/index.js';
|
|
4
4
|
import { makeFixtures } from "./fixtures.js";
|
|
5
5
|
import { fromFixture } from "./screener/rows.js";
|
|
6
6
|
import { makeScreenerState, screenerView } from "./screener/view.js";
|
|
7
7
|
import { renderScreener } from "./screens/screener.js";
|
|
8
8
|
import { renderToken } from "./screens/token.js";
|
|
9
9
|
import { agentBrainActive } from "./screens/brain.js";
|
|
10
|
-
import { pnlChipVM, renderPnlChip } from "./screens/pnl-chip.js";
|
|
10
|
+
import { pnlChipVM, renderPnlChip, CHIP_PRICE_LEVEL } from "./screens/pnl-chip.js";
|
|
11
11
|
import { renderNewPairs } from "./screens/newpairs.js";
|
|
12
12
|
import { renderWatchlist } from "./screens/watchlist.js";
|
|
13
13
|
import { renderAnalyst } from "./screens/analyst.js";
|
|
@@ -22,6 +22,7 @@ import { renderNarrative } from "./screens/narrative.js";
|
|
|
22
22
|
import { renderPlans } from "./screens/plans.js";
|
|
23
23
|
import { renderFollows } from "./screens/follows.js";
|
|
24
24
|
import { renderRules } from "./screens/rules.js";
|
|
25
|
+
import { renderAutotrade } from "./screens/autotrade-screen.js";
|
|
25
26
|
import { CopyLive } from "./live/copy.js";
|
|
26
27
|
import { CopyAuto, defaultCopyJournalPath, leaderSoldSince } from '../../data/src/trade/copy/index.js';
|
|
27
28
|
import { computeBoard, loadDefaultLexicon, recentNarrativeRows } from '../../packs/src/index.js';
|
|
@@ -32,7 +33,7 @@ import { renderScanTicker, scanIndicator } from "./scan/ui.js";
|
|
|
32
33
|
import { renderVoiceHud } from "./voice-hud.js";
|
|
33
34
|
import { composeHud, DOCK_ROWS, HUD_MIN_H } from "./screens/agent-hud.js";
|
|
34
35
|
import { workspaceBadge } from "./custom.js";
|
|
35
|
-
import { chartAxisOf, supplyRatio } from "./display.js";
|
|
36
|
+
import { chartAxisOf, supplyRatio, priceModeOf, supplyForMint } from "./display.js";
|
|
36
37
|
/** Map key for the Analyst-tab's own conversation (not tied to a single token). */
|
|
37
38
|
export const ANALYST_TAB_KEY = '__analyst_tab__';
|
|
38
39
|
/**
|
|
@@ -101,7 +102,7 @@ export function computeNarrativeView(state, window, now = Date.now()) {
|
|
|
101
102
|
return { board: null, window, computedAt: now, source: 'none', selected: 0, error: e instanceof Error ? e.message : String(e) };
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
|
-
export function newPlansUi() { return { tab: 'plans', selected: 0, notice: null, arming: null, riskModal: false
|
|
105
|
+
export function newPlansUi() { return { tab: 'plans', selected: 0, notice: null, arming: null, riskModal: false }; }
|
|
105
106
|
/**
|
|
106
107
|
* task-1363: how old a board price may be and still fire a plan. The terminal feeds the plan engine from its
|
|
107
108
|
* screener/watchlist refresh (about every 10 s) and the token screen, so the engine's 3 s default would never
|
|
@@ -179,6 +180,7 @@ export const RENDERERS = {
|
|
|
179
180
|
plans: renderPlans,
|
|
180
181
|
follows: renderFollows,
|
|
181
182
|
rules: renderRules,
|
|
183
|
+
autotrade: renderAutotrade,
|
|
182
184
|
};
|
|
183
185
|
export const SCREEN_NAMES = Object.keys(RENDERERS);
|
|
184
186
|
export function isScreenKey(s) {
|
|
@@ -206,6 +208,9 @@ export function isDemoScreen(s) {
|
|
|
206
208
|
// task-1360: the follows screen shows the user's own list + the tracker's real state (unavailable when keyless).
|
|
207
209
|
if (s.screen === 'follows')
|
|
208
210
|
return false;
|
|
211
|
+
// task-1508: the autotrade screen reads the user's own strategy files and the runner's status file (PAPER badge).
|
|
212
|
+
if (s.screen === 'autotrade')
|
|
213
|
+
return false;
|
|
209
214
|
// analyst screen: a live Claude session (even mid-run or failed) is real output, not demo data
|
|
210
215
|
return !s.analyst;
|
|
211
216
|
}
|
|
@@ -236,13 +241,10 @@ export function headerModel(s) {
|
|
|
236
241
|
feedLabel = 'jupiter · gecko · boosts · coingecko · rss · keyless';
|
|
237
242
|
if (s.screen === 'kol')
|
|
238
243
|
feedLabel = 'kol lists · sqlite';
|
|
239
|
-
// task-1355: the plans screen
|
|
240
|
-
// task-1363: once the fire path is LIVE (devnet fast wallet, keypress opt-in) the header says so; anything not
|
|
241
|
-
// provably paper renders LIVE (fail-safe).
|
|
244
|
+
// task-1355: the plans screen fires on PAPER only (task-1571: there is no live fire path) and says so.
|
|
242
245
|
if (s.screen === 'plans') {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
feedLabel = paper ? 'order plans · standing mandates · hash-chained journal' : 'order plans · signer process · fast wallet · devnet';
|
|
246
|
+
status = '◈ PAPER · plans journal';
|
|
247
|
+
feedLabel = 'order plans · standing mandates · hash-chained journal';
|
|
246
248
|
}
|
|
247
249
|
// task-1360: the follows screen reads public history for the user's own list; it never trades.
|
|
248
250
|
if (s.screen === 'follows')
|
|
@@ -250,14 +252,13 @@ export function headerModel(s) {
|
|
|
250
252
|
// task-1358: the rules screen evaluates the screener rows locally; rules only alert or PROPOSE.
|
|
251
253
|
if (s.screen === 'rules')
|
|
252
254
|
feedLabel = 'rules · config.json · alerts + proposals only · nothing arms';
|
|
255
|
+
// task-1508: autotrade is paper only; the screen edits strategy files and reads recorded history.
|
|
256
|
+
if (s.screen === 'autotrade') {
|
|
257
|
+
status = '◈ PAPER · autotrade';
|
|
258
|
+
feedLabel = 'strategies · recorded history · paper runner status';
|
|
259
|
+
}
|
|
253
260
|
if (s.screen === 'bubbles')
|
|
254
261
|
feedLabel = `${s.live?.rpc.provider === 'helius' ? 'helius history · ' : ''}rpc holders · rules · sqlite`;
|
|
255
|
-
// task-1328: a LIVE ticket says so in the header, with the SIGNER's network (never a UI flag).
|
|
256
|
-
if (s.screen === 'ticket' && s.live?.ticket?.ticket.mode === 'live') {
|
|
257
|
-
const net = s.live.ticket.view().live?.signer?.network ?? null;
|
|
258
|
-
status = net === 'mainnet' ? '⚠ LIVE · MAINNET · real funds' : net === 'devnet' ? '◉ LIVE · DEVNET' : '◉ LIVE · signer unreachable';
|
|
259
|
-
feedLabel = 'signer process · jupiter · phantom';
|
|
260
|
-
}
|
|
261
262
|
// task-1324: while AI scan mode is on the header ALWAYS says so (state + the scan's analyst meter +
|
|
262
263
|
// any Helius credit warning), on every screen — the running indicator wins over every other status.
|
|
263
264
|
let scanStatus = null;
|
|
@@ -302,6 +303,8 @@ export function makeFixtureState(opts = {}) {
|
|
|
302
303
|
larpByMint: new Map(),
|
|
303
304
|
colorDepth: opts.colorDepth ?? 'truecolor',
|
|
304
305
|
};
|
|
306
|
+
if (opts.priceMode)
|
|
307
|
+
state.priceMode = opts.priceMode;
|
|
305
308
|
refreshVfx(state);
|
|
306
309
|
if (screen === 'ticket' || screen === 'positions')
|
|
307
310
|
seedDemoTrade(state);
|
|
@@ -447,7 +450,7 @@ export function renderFrame(state, w, h) {
|
|
|
447
450
|
return composeHud(new Canvas(w, h, state.theme), screen, view, {
|
|
448
451
|
now, reduced: !!hud.reduced || isCalm(state.vfx), depth: state.colorDepth, dataLabel: hud.dataLabel ?? null, screen: state.screen, brain,
|
|
449
452
|
chip: pnlChipFor(state, now, view),
|
|
450
|
-
mcapScale:
|
|
453
|
+
mcapScale: priceModeOf(state) === 'mcap' ? (mint) => hudMcapScale(state, mint) : undefined, // task-1472; task-1537: the HUD's text follows the price basis (the charts keep A)
|
|
451
454
|
});
|
|
452
455
|
}
|
|
453
456
|
/** task-1472: the supply ratio for the HUD's position card: the open token's (live, else fixture), else its screener row. */
|
|
@@ -468,13 +471,16 @@ function hudMcapScale(state, mint) {
|
|
|
468
471
|
*/
|
|
469
472
|
export function pnlChipFor(state, now, view) {
|
|
470
473
|
const hud = state.agentHud;
|
|
474
|
+
// task-1537: entry / mark / TP read as market caps by default (the coin's known supply), else prices
|
|
475
|
+
const mode = priceModeOf(state);
|
|
476
|
+
const lvl = (u, mint) => { const sup = mode === 'mcap' ? supplyForMint(state, mint) : null; return sup !== null ? fmtMcap(u * sup) : CHIP_PRICE_LEVEL(u, mint); };
|
|
471
477
|
if (hud) {
|
|
472
|
-
const m = pnlChipVM(view ?? hud.story.view(now), now);
|
|
478
|
+
const m = pnlChipVM(view ?? hud.story.view(now), now, lvl);
|
|
473
479
|
if (m)
|
|
474
480
|
return m;
|
|
475
481
|
}
|
|
476
482
|
if (state.scan?.engine.on && state.ownPnl)
|
|
477
|
-
return state.ownPnl.vm(now);
|
|
483
|
+
return state.ownPnl.vm(now, lvl);
|
|
478
484
|
return null;
|
|
479
485
|
}
|
|
480
486
|
function renderScreenFrame(state, w, h, bandChip = false) {
|