dexterm-cli 0.1.5 → 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/index.js +2 -0
- package/dist/packages/agents/src/schema.js +22 -1
- package/dist/packages/agents/src/spectator.js +54 -0
- package/dist/packages/agents/src/story.js +532 -0
- package/dist/packages/agents/src/tiers.js +28 -2
- package/dist/packages/agents/src/tools.js +31 -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/REGISTRY.json +1 -1
- package/dist/packages/cli/assets/claude/plugin/skills/larp-check/SKILL.md +15 -8
- package/dist/packages/cli/assets/claude/plugin/skills/token-dossier/SKILL.md +1 -1
- package/dist/packages/cli/src/agent-cmd.js +6 -4
- package/dist/packages/cli/src/agent-spectator.js +17 -1
- package/dist/packages/cli/src/ai-cmd.js +412 -0
- package/dist/packages/cli/src/analyst/backend.js +105 -15
- package/dist/packages/cli/src/analyst/codex.js +14 -9
- package/dist/packages/cli/src/analyst/larp-gauge.js +60 -0
- package/dist/packages/cli/src/analyst/ollama.js +263 -0
- package/dist/packages/cli/src/analyst/session.js +17 -3
- package/dist/packages/cli/src/app-help-gen.js +51 -15
- 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/backtest-cmd.js +13 -2
- package/dist/packages/cli/src/display.js +208 -23
- 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/dev-history.js +31 -15
- package/dist/packages/cli/src/live/index.js +28 -90
- package/dist/packages/cli/src/live/screens/newpairs-live.js +1 -1
- package/dist/packages/cli/src/live/screens/token-live.js +48 -15
- package/dist/packages/cli/src/live/screens/watchlist-live.js +1 -1
- package/dist/packages/cli/src/live/trade.js +30 -453
- package/dist/packages/cli/src/live/watchlist.js +1 -1
- package/dist/packages/cli/src/main.js +290 -199
- package/dist/packages/cli/src/mcp-cmd.js +7 -1
- package/dist/packages/cli/src/mcp-follow.js +103 -6
- package/dist/packages/cli/src/plan-cmd.js +15 -5
- 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 +38 -6
- package/dist/packages/cli/src/record-cmd.js +141 -20
- package/dist/packages/cli/src/scan/ui.js +7 -1
- package/dist/packages/cli/src/screens/agent-hud.js +773 -0
- package/dist/packages/cli/src/screens/analyst-session.js +11 -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 +634 -0
- package/dist/packages/cli/src/screens/newpairs.js +1 -1
- 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 +144 -0
- package/dist/packages/cli/src/screens/positions.js +6 -28
- package/dist/packages/cli/src/screens/screener.js +1 -0
- package/dist/packages/cli/src/screens/ticket.js +38 -205
- package/dist/packages/cli/src/screens/token.js +18 -9
- package/dist/packages/cli/src/screens/trending.js +1 -1
- package/dist/packages/cli/src/state.js +88 -18
- 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 +41 -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 +2 -14
- package/dist/packages/data/src/larp/score.js +220 -0
- package/dist/packages/data/src/larp/x-account.js +316 -0
- package/dist/packages/data/src/store.js +14 -5
- package/dist/packages/data/src/trade/agent/paper-desk.js +300 -23
- 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/engine.js +7 -0
- package/dist/packages/data/src/trade/plans/index.js +0 -1
- package/dist/packages/data/src/trade/plans/mandate.js +28 -15
- package/dist/packages/data/src/trade/plans/service.js +4 -28
- 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/dev-history.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/larp-check.md +5 -1
- 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/scan-mode.md +1 -1
- 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 +6 -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/spectate-an-agent.md +2 -1
- 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 +7 -3
- 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-starting-a-run.md +2 -0
- 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 +32 -0
- 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 +9 -7
- 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-running-the-tests.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-larp-measured-accuracy.md +1 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-the-larp-score.md +60 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-the-verdict.md +0 -2
- package/dist/packages/mcp/assets/kb/docs/docs-larp-what-it-looks-at.md +4 -1
- package/dist/packages/mcp/assets/kb/docs/docs-larp.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 +4 -13
- 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 +40 -0
- 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-market-cap-axis.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +3 -1
- package/dist/packages/mcp/assets/kb/docs/docs-scan-the-read.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-autotrade-paper.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-dev-history.md +10 -7
- 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-follow-over-mcp-in-the-running-terminal.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-limits.md +2 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-agent-hud-spectator-v2.md +58 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-brain-view-and-the-pnl-chip.md +46 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-three-surfaces.md +1 -1
- package/dist/packages/mcp/assets/kb/docs/docs-spectator.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 +5 -2
- package/dist/packages/mcp/src/server.js +285 -36
- package/dist/packages/mcp/src/spectator-sink.js +85 -0
- package/dist/packages/packs/src/backtest.js +3 -1
- package/dist/packages/packs/src/index.js +1 -0
- package/dist/packages/packs/src/larp-score-backtest.js +119 -0
- package/dist/packages/popup/src/pages/chart-lib.js +169 -35
- package/dist/packages/popup/src/pages/chart.css +18 -0
- package/dist/packages/popup/src/pages/chart.html +6 -1
- package/dist/packages/popup/src/pages/chart.js +136 -10
- package/dist/packages/popup/src/pages/spectator.css +45 -0
- package/dist/packages/popup/src/pages/spectator.html +1 -0
- package/dist/packages/popup/src/pages/spectator.js +69 -0
- package/dist/packages/popup/src/protocol.js +4 -0
- package/dist/packages/popup/src/server.js +9 -1
- package/dist/packages/recorder/src/dev-history.js +7 -3
- 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/canvas.js +7 -0
- package/dist/packages/tui/src/fmt.js +53 -0
- package/dist/packages/tui/src/index.js +1 -0
- package/dist/packages/tui/src/keymap.js +25 -1
- package/dist/packages/tui/src/markers.js +219 -0
- package/dist/packages/tui/src/widgets.js +158 -6
- 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,90 +1,26 @@
|
|
|
1
|
-
// dexterm
|
|
2
|
-
// links a Phantom wallet through the loopback bridge (
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* flag above the hard ceiling (e.g. `--max-usd 1000000`, `--daily-usd 1e12`) is REJECTED rather than
|
|
10
|
-
* silently accepted, so a fat-fingered cap can never arm a huge money path. Throws on an over-ceiling
|
|
11
|
-
* value; the caller surfaces it as a usage error. (defaultCaps also clamps as a second line of defence.)
|
|
12
|
-
*/
|
|
13
|
-
export function parseCapsFlags(argv) {
|
|
14
|
-
let mainnet = false;
|
|
15
|
-
let perTradeUsd;
|
|
16
|
-
let dailyUsd;
|
|
17
|
-
let maxSolOut;
|
|
18
|
-
let maxSlippageBps;
|
|
19
|
-
const fmt = (n, unit) => (unit === '$' ? `$${n}` : `${n} ${unit}`);
|
|
20
|
-
const take = (flag, raw, ceiling, unit = '$') => {
|
|
21
|
-
const n = Number(raw);
|
|
22
|
-
if (!Number.isFinite(n) || n <= 0)
|
|
23
|
-
return undefined; // ignore junk; defaults apply
|
|
24
|
-
if (n > ceiling)
|
|
25
|
-
throw new Error(`${flag} ${fmt(n, unit)} exceeds the hard ceiling of ${fmt(ceiling, unit)}`);
|
|
26
|
-
return n;
|
|
27
|
-
};
|
|
28
|
-
for (let i = 0; i < argv.length; i++) {
|
|
29
|
-
const k = argv[i];
|
|
30
|
-
if (k === '--mainnet')
|
|
31
|
-
mainnet = true;
|
|
32
|
-
else if (k === '--max-usd')
|
|
33
|
-
perTradeUsd = take('--max-usd', argv[++i], HARD_MAX_PER_TRADE_USD);
|
|
34
|
-
else if (k === '--daily-usd')
|
|
35
|
-
dailyUsd = take('--daily-usd', argv[++i], HARD_MAX_DAILY_USD);
|
|
36
|
-
else if (k === '--max-sol-out')
|
|
37
|
-
maxSolOut = take('--max-sol-out', argv[++i], HARD_MAX_SOL_OUT, 'SOL');
|
|
38
|
-
else if (k === '--max-slippage-bps')
|
|
39
|
-
maxSlippageBps = take('--max-slippage-bps', argv[++i], HARD_MAX_SLIPPAGE_BPS, 'bps');
|
|
40
|
-
}
|
|
41
|
-
// task-1328: without --mainnet the USD caps can only go DOWN from the defaults (what the signer applies).
|
|
42
|
-
return capsOnlyDownward(defaultCaps({ network: mainnet ? 'mainnet' : 'devnet', mainnetEnabled: mainnet, perTradeUsd, dailyUsd, maxSolOut, maxSlippageBps }));
|
|
43
|
-
}
|
|
44
|
-
function capsLine(caps) {
|
|
45
|
-
const net = caps.network === 'mainnet' ? 'MAINNET' : 'devnet';
|
|
46
|
-
return `mode: ${caps.network === 'mainnet' ? 'LIVE' : 'DRY-RUN'} · network: ${net} · per-trade $${caps.perTradeUsd} · daily $${caps.dailyUsd} · max impact ${caps.maxPriceImpactPct}% · max SOL out ${caps.maxSolOut} · max slippage ${caps.maxSlippageBps} bps`;
|
|
47
|
-
}
|
|
48
|
-
function panicLine(ks, ledger) {
|
|
1
|
+
// dexterm — `dexterm wallet <link|unlink|status|panic|resume>` (SPEC §6.5). A non-TUI one-shot that
|
|
2
|
+
// links a Phantom wallet through the loopback bridge (sign-a-message only: dexterm keeps the PUBLIC key,
|
|
3
|
+
// never a private key, and signs nothing), unlinks it, prints the link, or engages the PANIC switch (a
|
|
4
|
+
// kill-switch file every dexterm process re-reads: autotrade runs and the paper agent desk halt).
|
|
5
|
+
// `resume` needs a real TTY keypress; piped input cannot re-arm. task-1571: dexterm holds no key and has
|
|
6
|
+
// no trading wallet; live trading happens in the Telegram trading bot of the user's choice.
|
|
7
|
+
import { WalletBridge, WalletLinkStore, shortPubkey, KillSwitch, } from '../../data/src/index.js';
|
|
8
|
+
function panicLine(ks) {
|
|
49
9
|
const p = ks.engaged();
|
|
50
|
-
|
|
51
|
-
if (!p && !l)
|
|
10
|
+
if (!p)
|
|
52
11
|
return null;
|
|
53
|
-
|
|
54
|
-
if (p)
|
|
55
|
-
parts.push(`panic switch engaged${p.engagedAt ? ` at ${new Date(p.engagedAt).toISOString()}` : ''} (${p.reason})`);
|
|
56
|
-
if (l)
|
|
57
|
-
parts.push(`cap ledger locked (${l.reason})`);
|
|
58
|
-
return `⛔ LIVE TRADING DISABLED — ${parts.join('; ')}. Run \`dexterm wallet resume\` in a terminal to re-enable.`;
|
|
12
|
+
return `⛔ PANIC ENGAGED${p.engagedAt ? ` at ${new Date(p.engagedAt).toISOString()}` : ''} (${p.reason}): autotrade runs and the paper agent desk stay halted. Run \`dexterm wallet resume\` in a terminal to clear it.`;
|
|
59
13
|
}
|
|
60
|
-
function printStatus(io, store,
|
|
14
|
+
function printStatus(io, store, ks) {
|
|
61
15
|
const w = store.get();
|
|
62
16
|
if (w)
|
|
63
|
-
io.stdout.write(`linked: ${shortPubkey(w.publicKey)} (${w.publicKey})\n`);
|
|
17
|
+
io.stdout.write(`linked: ${shortPubkey(w.publicKey)} (${w.publicKey}) · public key only, read-only\n`);
|
|
64
18
|
else
|
|
65
19
|
io.stdout.write('linked: (none) — run `dexterm wallet link`\n');
|
|
66
|
-
|
|
67
|
-
const p = panicLine(ks, ledger);
|
|
20
|
+
const p = panicLine(ks);
|
|
68
21
|
if (p)
|
|
69
22
|
io.stdout.write(`${p}\n`);
|
|
70
|
-
|
|
71
|
-
io.stdout.write('⚠ --mainnet is on: real funds, within the caps above. Devnet is the default; drop --mainnet to stay safe.\n');
|
|
72
|
-
}
|
|
73
|
-
function liveLine(path) {
|
|
74
|
-
try {
|
|
75
|
-
const l = new LiveLedger({ path, readOnly: true });
|
|
76
|
-
try {
|
|
77
|
-
const fills = l.records(1000);
|
|
78
|
-
const open = l.positions().filter((p) => p.tokensRaw > 0n);
|
|
79
|
-
return `live ledger: ${fills.length} confirmed fill${fills.length === 1 ? '' : 's'} · ${open.length} open position${open.length === 1 ? '' : 's'}${open.length ? ` (${open.map((p) => `$${p.symbol}`).join(', ')})` : ''}`;
|
|
80
|
-
}
|
|
81
|
-
finally {
|
|
82
|
-
l.close();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
catch {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
23
|
+
io.stdout.write('dexterm holds no key and signs nothing. Live trading happens in the Telegram trading bot of your choice (dexterm telegram setup).\n');
|
|
88
24
|
}
|
|
89
25
|
/**
|
|
90
26
|
* Wait for ONE real keypress on a TTY. Resolves with the key, or null when stdin is not a TTY (piped
|
|
@@ -132,302 +68,65 @@ export async function ttyKeypress(stdin, timeoutMs) {
|
|
|
132
68
|
/** Run the wallet subcommand. Returns a process exit code. */
|
|
133
69
|
export async function runWallet(argv, io, over = {}) {
|
|
134
70
|
const sub = argv[0] ?? 'status';
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
caps = parseCapsFlags(argv.slice(1));
|
|
138
|
-
}
|
|
139
|
-
catch (e) {
|
|
140
|
-
io.stderr.write(`dexterm wallet: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
71
|
+
if (sub === 'trading' || sub === 'fast' || sub === 'probe') {
|
|
72
|
+
io.stderr.write(`dexterm wallet ${sub}: removed in 0.1.7. dexterm holds no key and has no trading wallet; live trading happens in the Telegram trading bot of your choice\n`);
|
|
141
73
|
return 2;
|
|
142
74
|
}
|
|
143
75
|
const store = over.store ?? new WalletLinkStore();
|
|
144
76
|
const ks = over.killSwitch ?? new KillSwitch();
|
|
145
|
-
const ledgerPath = over.ledgerPath ?? defaultCapLedgerPath();
|
|
146
|
-
const openLedger = () => { try {
|
|
147
|
-
return new CapLedger({ path: ledgerPath });
|
|
148
|
-
}
|
|
149
|
-
catch {
|
|
150
|
-
return null;
|
|
151
|
-
} };
|
|
152
77
|
if (sub === 'status') {
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
printStatus(io, store, caps, ks, ledger);
|
|
156
|
-
}
|
|
157
|
-
finally {
|
|
158
|
-
ledger?.close();
|
|
159
|
-
}
|
|
160
|
-
const ll = liveLine(over.liveLedgerPath ?? defaultLiveLedgerPath());
|
|
161
|
-
if (ll)
|
|
162
|
-
io.stdout.write(`${ll}\n`);
|
|
78
|
+
printStatus(io, store, ks);
|
|
163
79
|
return 0;
|
|
164
80
|
}
|
|
165
|
-
// PROBE (task-1328): the devnet plumbing test from a shell — the signer service runs in THIS process
|
|
166
|
-
// (same code the TUI's signer child runs), builds the wrap-and-unwrap plan for the linked wallet,
|
|
167
|
-
// prints it, waits for a real TTY keypress, then opens Phantom, verifies, re-simulates, submits and
|
|
168
|
-
// confirms. Devnet only: the service refuses a non-devnet RPC and --mainnet is not accepted here.
|
|
169
|
-
if (sub === 'probe') {
|
|
170
|
-
if (argv.includes('--mainnet')) {
|
|
171
|
-
io.stderr.write('dexterm wallet probe: devnet only (drop --mainnet)\n');
|
|
172
|
-
return 2;
|
|
173
|
-
}
|
|
174
|
-
if (!store.get()) {
|
|
175
|
-
io.stderr.write('dexterm wallet probe: no wallet linked; run `dexterm wallet link` first\n');
|
|
176
|
-
return 2;
|
|
177
|
-
}
|
|
178
|
-
let service;
|
|
179
|
-
try {
|
|
180
|
-
service = over.signerService ?? buildSignerService(parseSignerArgs(argv.slice(1).filter((a) => a !== '--no-browser'), io.env), (l) => io.stderr.write(`${l}\n`));
|
|
181
|
-
}
|
|
182
|
-
catch (e) {
|
|
183
|
-
io.stderr.write(`dexterm wallet probe: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
184
|
-
return 2;
|
|
185
|
-
}
|
|
186
|
-
const st = service.status();
|
|
187
|
-
if (st.network !== 'devnet') {
|
|
188
|
-
io.stderr.write(`dexterm wallet probe: the signer RPC is ${st.network}; the probe runs only on devnet\n`);
|
|
189
|
-
return 2;
|
|
190
|
-
}
|
|
191
|
-
if (st.panic || st.ledgerLocked) {
|
|
192
|
-
io.stderr.write(`${panicLine(ks, openLedger()) ?? 'panicked'}\n`);
|
|
193
|
-
return 2;
|
|
194
|
-
}
|
|
195
|
-
let plan;
|
|
196
|
-
try {
|
|
197
|
-
plan = await service.probe();
|
|
198
|
-
}
|
|
199
|
-
catch (e) {
|
|
200
|
-
io.stderr.write(`dexterm wallet probe: plan failed: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
201
|
-
return 1;
|
|
202
|
-
}
|
|
203
|
-
io.stdout.write(`DEVNET PROBE for ${shortPubkey(plan.userPublicKey)} via ${st.rpcHost}\n`);
|
|
204
|
-
io.stdout.write(` wraps ${lamportsToSol(BigInt(plan.amountInRaw)).toFixed(4)} SOL into your own WSOL account and closes it back · fee ≈ ${lamportsToSol(BigInt(plan.feeLamports)).toFixed(6)} SOL\n`);
|
|
205
|
-
io.stdout.write(` will sign: ${plan.instructions.map((i) => `${i.program}${i.op ? ':' + i.op : ''}`).join(' · ')}\n`);
|
|
206
|
-
io.stdout.write(` simulation: ${plan.sim.ran ? (plan.sim.ok ? `ok (${plan.sim.solOutLamports ?? '?'} lamports leave the wallet)` : `FAILED ${plan.sim.error ?? ''}`) : 'not run'} · policy: ${plan.policy.ok ? 'ok' : `REFUSE ${plan.policy.reason}`} · caps: ${plan.precheck.ok ? 'ok' : `REFUSE ${plan.precheck.reason}`}\n`);
|
|
207
|
-
if (!plan.policy.ok || !plan.precheck.ok || !plan.sim.ok) {
|
|
208
|
-
io.stderr.write('dexterm wallet probe: the signer would refuse this plan; nothing to sign\n');
|
|
209
|
-
return 1;
|
|
210
|
-
}
|
|
211
|
-
const stdin = io.stdin;
|
|
212
|
-
if (!stdin || stdin.isTTY !== true) {
|
|
213
|
-
io.stderr.write('dexterm wallet probe: needs a real terminal keypress (stdin is not a TTY). Refusing.\n');
|
|
214
|
-
return 2;
|
|
215
|
-
}
|
|
216
|
-
io.stdout.write('Press Y to sign this probe in Phantom (any other key aborts)… ');
|
|
217
|
-
const key = await ttyKeypress(stdin, over.keypressTimeoutMs ?? 60_000);
|
|
218
|
-
io.stdout.write('\n');
|
|
219
|
-
if (key !== 'y' && key !== 'Y') {
|
|
220
|
-
io.stdout.write('aborted; nothing signed.\n');
|
|
221
|
-
return 1;
|
|
222
|
-
}
|
|
223
|
-
const out = await service.confirm({ hash: plan.hash });
|
|
224
|
-
if (out.kind === 'filled') {
|
|
225
|
-
io.stdout.write(`✓ confirmed on devnet · signature ${out.signature}${out.lighthouseTail ? ` · Phantom appended ${out.lighthouseTail} Lighthouse instruction(s)` : ' · no Lighthouse tail'} · ${out.roundTripMs} ms\n`);
|
|
226
|
-
return 0;
|
|
227
|
-
}
|
|
228
|
-
if (out.kind === 'refused') {
|
|
229
|
-
io.stdout.write(`✗ refused by the signer: ${out.reason} — ${out.message}\n`);
|
|
230
|
-
return 1;
|
|
231
|
-
}
|
|
232
|
-
if (out.kind === 'send-unknown') {
|
|
233
|
-
io.stdout.write(`? send outcome unknown: ${out.error} · signature ${out.signature} · do NOT resend\n`);
|
|
234
|
-
return 1;
|
|
235
|
-
}
|
|
236
|
-
io.stdout.write(`✗ send failed: ${out.error}${out.signature ? ` · signature ${out.signature}` : ''}\n`);
|
|
237
|
-
return 1;
|
|
238
|
-
}
|
|
239
|
-
// FAST WALLET (task-1363): the one key dexterm holds, devnet only, for standing-mandate fills at machine speed.
|
|
240
|
-
// create a new devnet key at ~/.dexterm/fast-wallet.json (mode 600) after a real TTY keypress; never overwrites
|
|
241
|
-
// status public key, devnet balance, the per-fill ceiling
|
|
242
|
-
// airdrop devnet faucet into the fast wallet (--sol N, default 1)
|
|
243
|
-
// remove delete the key (TTY keypress; refused while it still holds SOL unless --force)
|
|
244
|
-
// There is no export, no import, no mainnet variant, and the signer process only ever READS this file.
|
|
245
|
-
if (sub === 'fast') {
|
|
246
|
-
if (argv.includes('--mainnet')) {
|
|
247
|
-
io.stderr.write('dexterm wallet fast: devnet only (there is no mainnet fast wallet; drop --mainnet)\n');
|
|
248
|
-
return 2;
|
|
249
|
-
}
|
|
250
|
-
const action = argv[1] ?? 'status';
|
|
251
|
-
const fastStore = new FastWalletStore(over.fastWalletPath ?? defaultFastWalletPath(io.env));
|
|
252
|
-
const rpc = () => {
|
|
253
|
-
if (over.fastRpc)
|
|
254
|
-
return over.fastRpc;
|
|
255
|
-
const dl = createDataLayer({ dbPath: ':memory:', rpcUrl: DEVNET_RPC, rpcFallbackUrl: null });
|
|
256
|
-
const r = new TradeRpc(dl.http, { url: DEVNET_RPC });
|
|
257
|
-
return { balance: (pk) => r.balance(pk), airdrop: (pk, l) => r.airdrop(pk, l), confirm: (sig) => r.confirm(sig, { timeoutMs: 45_000 }) };
|
|
258
|
-
};
|
|
259
|
-
const balanceLine = async (pk) => {
|
|
260
|
-
try {
|
|
261
|
-
const l = await rpc().balance(pk);
|
|
262
|
-
return { lamports: l, text: `${lamportsToSol(l).toFixed(4)} SOL (devnet)` };
|
|
263
|
-
}
|
|
264
|
-
catch (e) {
|
|
265
|
-
return { lamports: null, text: `balance unavailable (${e instanceof Error ? e.message : String(e)})` };
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
if (action === 'status') {
|
|
269
|
-
const rec = fastStore.get();
|
|
270
|
-
if (!rec) {
|
|
271
|
-
io.stdout.write(`fast wallet: (none) — create one with \`dexterm wallet fast create\` (devnet only)\n`);
|
|
272
|
-
return 0;
|
|
273
|
-
}
|
|
274
|
-
const b = await balanceLine(rec.publicKey);
|
|
275
|
-
io.stdout.write(`fast wallet: ${shortPubkey(rec.publicKey)} (${rec.publicKey}) · devnet · created ${new Date(rec.createdAt).toISOString()}\n`);
|
|
276
|
-
io.stdout.write(` balance: ${b.text} · per-fill ceiling ${FAST_MAX_SOL_PER_FILL} SOL · the signer's USD per-trade/daily caps apply on every fill\n`);
|
|
277
|
-
io.stdout.write(` file: ${fastStore.path} (mode 600; never exported, never printed)\n`);
|
|
278
|
-
return 0;
|
|
279
|
-
}
|
|
280
|
-
if (action === 'create') {
|
|
281
|
-
if (fastStore.exists()) {
|
|
282
|
-
io.stderr.write(`dexterm wallet fast create: a fast wallet already exists at ${fastStore.path} (remove it first, after draining)\n`);
|
|
283
|
-
return 2;
|
|
284
|
-
}
|
|
285
|
-
const stdin = io.stdin;
|
|
286
|
-
if (!stdin || stdin.isTTY !== true) {
|
|
287
|
-
io.stderr.write('dexterm wallet fast create: needs a real terminal keypress (stdin is not a TTY). Refusing.\n');
|
|
288
|
-
return 2;
|
|
289
|
-
}
|
|
290
|
-
io.stdout.write(`Create a DEVNET fast wallet at ${fastStore.path}?\n armed order plans inside a standing mandate fire from it at machine speed, within the signer's caps and a ${FAST_MAX_SOL_PER_FILL} SOL per-fill ceiling.\n devnet only — this key can never be used on mainnet. Press Y to create (any other key aborts)… `);
|
|
291
|
-
const key = await ttyKeypress(stdin, over.keypressTimeoutMs ?? 30_000);
|
|
292
|
-
io.stdout.write('\n');
|
|
293
|
-
if (key !== 'y' && key !== 'Y') {
|
|
294
|
-
io.stdout.write('aborted; nothing created.\n');
|
|
295
|
-
return 1;
|
|
296
|
-
}
|
|
297
|
-
const rec = fastStore.create({ network: 'devnet' });
|
|
298
|
-
io.stdout.write(`✓ fast wallet created: ${rec.publicKey} (devnet)\n fund it: dexterm wallet fast airdrop · then restart dexterm so the signer loads it\n`);
|
|
299
|
-
return 0;
|
|
300
|
-
}
|
|
301
|
-
if (action === 'airdrop') {
|
|
302
|
-
const rec = fastStore.get();
|
|
303
|
-
if (!rec) {
|
|
304
|
-
io.stderr.write('dexterm wallet fast airdrop: no fast wallet; `dexterm wallet fast create` first\n');
|
|
305
|
-
return 2;
|
|
306
|
-
}
|
|
307
|
-
const solIdx = argv.indexOf('--sol');
|
|
308
|
-
const sol = solIdx >= 0 ? Number(argv[solIdx + 1]) : 1;
|
|
309
|
-
if (!Number.isFinite(sol) || sol <= 0 || sol > 5) {
|
|
310
|
-
io.stderr.write('dexterm wallet fast airdrop: --sol must be in (0, 5]\n');
|
|
311
|
-
return 2;
|
|
312
|
-
}
|
|
313
|
-
try {
|
|
314
|
-
const sig = await rpc().airdrop(rec.publicKey, BigInt(Math.round(sol * 1e9)));
|
|
315
|
-
io.stdout.write(`airdrop requested: ${sol} SOL (devnet) → ${shortPubkey(rec.publicKey)} · signature ${sig}\n`);
|
|
316
|
-
const c = rpc().confirm ? await rpc().confirm(sig).catch(() => null) : null;
|
|
317
|
-
if (c)
|
|
318
|
-
io.stdout.write(c.confirmed ? '✓ confirmed\n' : `? not confirmed yet (${c.err ?? 'pending'})\n`);
|
|
319
|
-
const b = await balanceLine(rec.publicKey);
|
|
320
|
-
io.stdout.write(` balance: ${b.text}\n`);
|
|
321
|
-
return 0;
|
|
322
|
-
}
|
|
323
|
-
catch (e) {
|
|
324
|
-
io.stderr.write(`dexterm wallet fast airdrop failed: ${e instanceof Error ? e.message : String(e)} — the public devnet faucet is often dry; try https://faucet.solana.com with the address above\n`);
|
|
325
|
-
return 1;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
if (action === 'remove') {
|
|
329
|
-
const rec = fastStore.get();
|
|
330
|
-
if (!rec) {
|
|
331
|
-
io.stdout.write('no fast wallet to remove.\n');
|
|
332
|
-
return 0;
|
|
333
|
-
}
|
|
334
|
-
const b = await balanceLine(rec.publicKey);
|
|
335
|
-
if (b.lamports !== null && b.lamports > 0n && !argv.includes('--force')) {
|
|
336
|
-
io.stderr.write(`dexterm wallet fast remove: the fast wallet still holds ${b.text}; move it out first, or pass --force to delete the key anyway (devnet SOL only)\n`);
|
|
337
|
-
return 2;
|
|
338
|
-
}
|
|
339
|
-
const stdin = io.stdin;
|
|
340
|
-
if (!stdin || stdin.isTTY !== true) {
|
|
341
|
-
io.stderr.write('dexterm wallet fast remove: needs a real terminal keypress (stdin is not a TTY). Refusing.\n');
|
|
342
|
-
return 2;
|
|
343
|
-
}
|
|
344
|
-
io.stdout.write(`Delete the fast wallet ${shortPubkey(rec.publicKey)} (${b.text})? Press Y to delete (any other key aborts)… `);
|
|
345
|
-
const key = await ttyKeypress(stdin, over.keypressTimeoutMs ?? 30_000);
|
|
346
|
-
io.stdout.write('\n');
|
|
347
|
-
if (key !== 'y' && key !== 'Y') {
|
|
348
|
-
io.stdout.write('aborted; the fast wallet is kept.\n');
|
|
349
|
-
return 1;
|
|
350
|
-
}
|
|
351
|
-
fastStore.remove();
|
|
352
|
-
io.stdout.write('✓ fast wallet removed. Restart dexterm so the signer stops loading it.\n');
|
|
353
|
-
return 0;
|
|
354
|
-
}
|
|
355
|
-
io.stderr.write(`dexterm wallet fast: unknown action ${JSON.stringify(action)} (expected status | create | airdrop | remove)\n`);
|
|
356
|
-
return 2;
|
|
357
|
-
}
|
|
358
81
|
if (sub === 'unlink') {
|
|
359
82
|
const had = store.clear();
|
|
360
83
|
io.stdout.write(had ? 'unlinked.\n' : 'no wallet was linked.\n');
|
|
361
84
|
return 0;
|
|
362
85
|
}
|
|
363
86
|
// PANIC: instant, no confirmation, scriptable from anywhere (a second terminal, a hotkey, an agent).
|
|
364
|
-
// Engages the kill-switch file
|
|
365
|
-
// daily-cap ledger so no reservation can be taken even if the file were removed by hand.
|
|
87
|
+
// Engages the kill-switch file; every autotrade runner and the paper agent desk re-read it on each step.
|
|
366
88
|
if (sub === 'panic') {
|
|
367
89
|
const reasonIdx = argv.indexOf('--reason');
|
|
368
90
|
const reason = reasonIdx >= 0 && argv[reasonIdx + 1] ? argv[reasonIdx + 1] : 'manual panic';
|
|
369
91
|
const rec = ks.engage(reason);
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (ledger) {
|
|
373
|
-
try {
|
|
374
|
-
ledger.lock(reason);
|
|
375
|
-
lockNote = ' · cap ledger locked';
|
|
376
|
-
}
|
|
377
|
-
finally {
|
|
378
|
-
ledger.close();
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
else
|
|
382
|
-
lockNote = ' · (cap ledger could not be opened; the kill-switch file still disables trading)';
|
|
383
|
-
io.stdout.write(`⛔ PANIC: live trading disabled (${rec.reason})${lockNote}\n`);
|
|
384
|
-
io.stdout.write(`kill switch: ${ks.path}\nRe-enable only from a real terminal: dexterm wallet resume\n`);
|
|
92
|
+
io.stdout.write(`⛔ PANIC: autotrade and the paper agent desk halted (${rec.reason})\n`);
|
|
93
|
+
io.stdout.write(`kill switch: ${ks.path}\nClear it only from a real terminal: dexterm wallet resume\n`);
|
|
385
94
|
return 0;
|
|
386
95
|
}
|
|
387
96
|
// RESUME: the only way back. Requires a physical keypress on a TTY — not piped/scripted input — so a
|
|
388
|
-
// model
|
|
97
|
+
// model or a script cannot silently clear the panic switch.
|
|
389
98
|
if (sub === 'resume') {
|
|
390
99
|
const stdin = io.stdin;
|
|
391
100
|
if (!stdin || stdin.isTTY !== true) {
|
|
392
101
|
io.stderr.write('dexterm wallet resume: needs a real terminal keypress (stdin is not a TTY). Refusing.\n');
|
|
393
102
|
return 2;
|
|
394
103
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
try {
|
|
398
|
-
const l = ledger?.locked() ?? null;
|
|
399
|
-
if (!p && !l) {
|
|
400
|
-
io.stdout.write('live trading is not panicked; nothing to resume.\n');
|
|
401
|
-
return 0;
|
|
402
|
-
}
|
|
403
|
-
io.stdout.write(`${panicLine(ks, ledger) ?? ''}\nPress Y to re-enable live trading (any other key aborts)… `);
|
|
404
|
-
const key = await ttyKeypress(stdin, over.keypressTimeoutMs ?? 30_000);
|
|
405
|
-
io.stdout.write('\n');
|
|
406
|
-
if (key === null) {
|
|
407
|
-
io.stderr.write('dexterm wallet resume: no keypress; still panicked.\n');
|
|
408
|
-
return 2;
|
|
409
|
-
}
|
|
410
|
-
if (key !== 'y' && key !== 'Y') {
|
|
411
|
-
io.stdout.write('aborted; still panicked.\n');
|
|
412
|
-
return 1;
|
|
413
|
-
}
|
|
414
|
-
ks.release();
|
|
415
|
-
ledger?.unlock();
|
|
416
|
-
io.stdout.write('✓ live trading re-enabled (caps still apply).\n');
|
|
104
|
+
if (!ks.engaged()) {
|
|
105
|
+
io.stdout.write('the panic switch is not engaged; nothing to resume.\n');
|
|
417
106
|
return 0;
|
|
418
107
|
}
|
|
419
|
-
|
|
420
|
-
|
|
108
|
+
io.stdout.write(`${panicLine(ks) ?? ''}\nPress Y to clear the panic switch (any other key aborts)… `);
|
|
109
|
+
const key = await ttyKeypress(stdin, over.keypressTimeoutMs ?? 30_000);
|
|
110
|
+
io.stdout.write('\n');
|
|
111
|
+
if (key === null) {
|
|
112
|
+
io.stderr.write('dexterm wallet resume: no keypress; still panicked.\n');
|
|
113
|
+
return 2;
|
|
114
|
+
}
|
|
115
|
+
if (key !== 'y' && key !== 'Y') {
|
|
116
|
+
io.stdout.write('aborted; still panicked.\n');
|
|
117
|
+
return 1;
|
|
421
118
|
}
|
|
119
|
+
ks.release();
|
|
120
|
+
io.stdout.write('✓ panic switch cleared.\n');
|
|
121
|
+
return 0;
|
|
422
122
|
}
|
|
423
123
|
if (sub === 'link') {
|
|
424
124
|
const bridge = over.bridge ?? new WalletBridge(over.open ? { open: over.open } : {});
|
|
425
125
|
io.stdout.write('Opening your browser to link a Solana wallet (sign-a-message only; no transaction)…\n');
|
|
426
126
|
try {
|
|
427
127
|
const res = await bridge.link();
|
|
428
|
-
const rec = store.set(res.publicKey
|
|
429
|
-
io.stdout.write(`linked: ${shortPubkey(rec.publicKey)} (${rec.publicKey})\n`);
|
|
430
|
-
io.stdout.write(`${capsLine(caps)}\n`);
|
|
128
|
+
const rec = store.set(res.publicKey);
|
|
129
|
+
io.stdout.write(`linked: ${shortPubkey(rec.publicKey)} (${rec.publicKey}) · public key only; dexterm never signs with it\n`);
|
|
431
130
|
return 0;
|
|
432
131
|
}
|
|
433
132
|
catch (e) {
|
|
@@ -435,6 +134,6 @@ export async function runWallet(argv, io, over = {}) {
|
|
|
435
134
|
return 1;
|
|
436
135
|
}
|
|
437
136
|
}
|
|
438
|
-
io.stderr.write(`dexterm wallet: unknown subcommand ${JSON.stringify(sub)} (expected link | unlink | status | panic | resume
|
|
137
|
+
io.stderr.write(`dexterm wallet: unknown subcommand ${JSON.stringify(sub)} (expected link | unlink | status | panic | resume)\n`);
|
|
439
138
|
return 2;
|
|
440
139
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Parse a typed command: `/wallet` · `/wallet status` · `/wallet link` · `/wallet unlink` ·
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Parse a typed command: `/wallet` · `/wallet status` · `/wallet link` · `/wallet unlink` · `/wallet panic`.
|
|
3
|
+
* The leading slash is optional (the screener's `/` line ate it). Anything else — including a real filter —
|
|
4
|
+
* returns null. `resume` is deliberately NOT a command here: clearing the panic switch needs a real TTY
|
|
5
|
+
* keypress in `dexterm wallet resume`.
|
|
6
6
|
*/
|
|
7
7
|
export function parseWalletCommand(text) {
|
|
8
8
|
const m = /^\s*\/?wallet(?:\s+(\S+))?\s*$/i.exec(String(text ?? ''));
|
|
@@ -17,15 +17,12 @@ export function parseWalletCommand(text) {
|
|
|
17
17
|
return 'unlink';
|
|
18
18
|
if (arg === 'panic')
|
|
19
19
|
return 'panic';
|
|
20
|
-
if (arg === 'probe')
|
|
21
|
-
return 'probe';
|
|
22
20
|
if (arg === 'resume')
|
|
23
21
|
return { error: 'resume needs a real terminal keypress: run `dexterm wallet resume` in a shell' };
|
|
24
|
-
return { error: `unknown /wallet command "${arg.slice(0, 16)}" (status · link · unlink · panic
|
|
22
|
+
return { error: `unknown /wallet command "${arg.slice(0, 16)}" (status · link · unlink · panic)` };
|
|
25
23
|
}
|
|
26
|
-
export const WALLET_HELP = ` /wallet [status] linked wallet (
|
|
24
|
+
export const WALLET_HELP = ` /wallet [status] linked wallet (public key only, read-only) and the panic state
|
|
27
25
|
/wallet link open the browser to link a Phantom wallet (sign-a-message proof; no transaction)
|
|
28
26
|
/wallet unlink forget the linked public key
|
|
29
|
-
/wallet panic
|
|
30
|
-
|
|
31
|
-
dexterm wallet fast … the capped DEVNET fast wallet armed order plans fire from: create (TTY keypress) · status · airdrop · remove`;
|
|
27
|
+
/wallet panic halt autotrade runs and the paper agent desk at once (kill-switch file); resume needs \`dexterm wallet resume\`
|
|
28
|
+
dexterm never holds a key and never signs. Live trading happens in the Telegram trading bot of your choice.`;
|
|
@@ -109,18 +109,6 @@ export function widgetPositionsVM(state) {
|
|
|
109
109
|
rows.push({ symbol: p.symbol, mint: p.mint, side: 'long', tokens: p.tokens, valueSol: p.valueSol, unrealizedSol: p.unrealizedSol, unrealizedPct: p.unrealizedPct, book: 'paper' });
|
|
110
110
|
}
|
|
111
111
|
catch { /* no paper book on this run */ }
|
|
112
|
-
const lp = live.livePositions;
|
|
113
|
-
if (lp) {
|
|
114
|
-
try {
|
|
115
|
-
for (const p of lp.positions()) {
|
|
116
|
-
if (p.tokensRaw <= 0n)
|
|
117
|
-
continue;
|
|
118
|
-
const h = lp.held(p.mint);
|
|
119
|
-
rows.push({ symbol: p.symbol, mint: p.mint, side: 'long', tokens: h?.tokens ?? Number(p.tokensRaw) / 10 ** p.decimals, valueSol: null, unrealizedSol: null, unrealizedPct: null, book: 'live' });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
catch { /* ledger unreadable */ }
|
|
123
|
-
}
|
|
124
112
|
}
|
|
125
113
|
return { rows, updatedAt: state.now.getTime() };
|
|
126
114
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @dexterm/custom — the config loader (task-1358 Tier 1). ~/.dexterm/config.json is the canonical,
|
|
2
|
-
// machine-written config (0600, `version:
|
|
2
|
+
// machine-written config (0600, `version: 5`); workspaces are one JSON file each in ~/.dexterm/workspaces/,
|
|
3
3
|
// user themes in ~/.dexterm/themes/. THIS MODULE NEVER READS A KEY FILE: `<name>.key` files are the data
|
|
4
4
|
// layer's business, and the only thing the loader does with a key is move one OUT of an old config.
|
|
5
5
|
//
|
|
@@ -55,7 +55,7 @@ export function loadConfig(home) {
|
|
|
55
55
|
// older (or newer) config: migrate, back up, write the new one, write extracted keys to <name>.key (0600)
|
|
56
56
|
let m;
|
|
57
57
|
try {
|
|
58
|
-
m = migrate(raw);
|
|
58
|
+
m = migrate(raw, { journaledPriceMode: journaledPriceMode(home) });
|
|
59
59
|
}
|
|
60
60
|
catch (e) {
|
|
61
61
|
return { ...base, ok: false, errors: [`${path}: ${e.message}`] };
|
|
@@ -95,6 +95,24 @@ export function saveConfig(home, config) {
|
|
|
95
95
|
writeFileSync(tmp, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
96
96
|
renameSync(tmp, path);
|
|
97
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* task-1537: the `display.priceMode` value the journal last recorded (every applied / undone / redone op that set it,
|
|
100
|
+
* in order), or null when the journal never touched it. Lets the v4 → v5 migration tell a user's own `price` choice
|
|
101
|
+
* from the old default.
|
|
102
|
+
*/
|
|
103
|
+
export function journaledPriceMode(home) {
|
|
104
|
+
let v = null;
|
|
105
|
+
for (const e of readJournal(home)) {
|
|
106
|
+
for (const op of e.ops ?? []) {
|
|
107
|
+
const val = op.path === '/display/priceMode' ? op.value : op.path === '/display' && op.value && typeof op.value === 'object' ? op.value.priceMode : undefined;
|
|
108
|
+
if (op.op === 'remove' && (op.path === '/display/priceMode' || op.path === '/display'))
|
|
109
|
+
v = null;
|
|
110
|
+
else if (val === 'price' || val === 'mcap')
|
|
111
|
+
v = val;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return v;
|
|
115
|
+
}
|
|
98
116
|
export function readJournal(home) {
|
|
99
117
|
try {
|
|
100
118
|
return readFileSync(journalPath(home), 'utf8').split('\n').filter(Boolean).map((l) => JSON.parse(l));
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// "no runtime deps" rule. KEYS NEVER APPEAR IN THIS SCHEMA: there is no `keys` / `signer` / `trading`
|
|
6
6
|
// section at all (additional:false makes an attempt to add one a precise refusal), and the v1 migration
|
|
7
7
|
// demonstrates moving a key OUT of the config file into `~/.dexterm/<name>.key`.
|
|
8
|
-
export const CONFIG_VERSION =
|
|
8
|
+
export const CONFIG_VERSION = 5;
|
|
9
9
|
const FORBIDDEN_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
10
10
|
/** Validate `value` against a schema (a node or the name of one in `refs`); returns the error list. */
|
|
11
11
|
export function validate(schema, value, path = '', errors = [], refs = SCHEMAS) {
|
|
@@ -135,11 +135,25 @@ export const WIDGET_REF = '^[a-z][a-z0-9-]{0,39}/[a-z][a-z0-9-]{0,39}(/[a-z][a-z
|
|
|
135
135
|
export const WORKSPACE_SCREENS = ['screener', 'token', 'newpairs', 'watchlist', 'analyst', 'positions', 'narrative', 'plans', 'trending'];
|
|
136
136
|
export const LAYOUT_SCREENS = ['screener', 'token', 'newpairs', 'watchlist', 'analyst', 'positions'];
|
|
137
137
|
/**
|
|
138
|
-
* task-1366: how token prices are DISPLAYED. `
|
|
139
|
-
*
|
|
138
|
+
* task-1366: how token prices are DISPLAYED. `mcap` = market cap (price × a known supply); `price` = USD per token.
|
|
139
|
+
* task-1537: `display.priceMode` is THE price-basis key for the UI, the CLI text AND the agents' language, default
|
|
140
|
+
* `mcap` (the v4 → v5 migration moves a `price` that was only the old default). A display / wording mode only: the
|
|
141
|
+
* same data underneath, nothing that trades reads it. @dexterm/data/basis holds the resolver and formatters.
|
|
140
142
|
*/
|
|
141
143
|
export const PRICE_MODES = ['price', 'mcap'];
|
|
142
|
-
export const DEFAULT_PRICE_MODE = '
|
|
144
|
+
export const DEFAULT_PRICE_MODE = 'mcap';
|
|
145
|
+
/**
|
|
146
|
+
* task-1472: what the CHART Y axis shows (the terminal token chart and the chart popup), separate from the table/header
|
|
147
|
+
* price mode: `mcap` (default; absent = mcap, so existing configs get it too) or `price`. `A` / the popup control toggle it.
|
|
148
|
+
*/
|
|
149
|
+
export const CHART_AXES = ['mcap', 'price'];
|
|
150
|
+
export const DEFAULT_CHART_AXIS = 'mcap';
|
|
151
|
+
/**
|
|
152
|
+
* task-1483: whether both charts draw the BUY / SELL markers of the ledgers' fills (and the avg-entry line): `on`
|
|
153
|
+
* (default; absent = on) or `off`. The chart popup's MARKERS control and `dexterm display markers` set it. Display only.
|
|
154
|
+
*/
|
|
155
|
+
export const CHART_MARKERS = ['on', 'off'];
|
|
156
|
+
export const DEFAULT_CHART_MARKERS = 'on';
|
|
143
157
|
const tokenProps = () => Object.fromEntries([...THEME_TOKENS.map((t) => [t, 'hex']), ...THEME_RAMPS.map((t) => [t, 'ramp'])]);
|
|
144
158
|
export const SCHEMAS = {
|
|
145
159
|
hex: { type: 'string', pattern: HEX },
|
|
@@ -236,8 +250,8 @@ export const SCHEMAS = {
|
|
|
236
250
|
user: { type: 'object', values: 'userTheme' },
|
|
237
251
|
} },
|
|
238
252
|
fx: { type: 'object', additional: false, props: { intensity: { type: 'string', enum: ['off', 'normal', 'fever'] }, sound: { type: 'boolean' } } },
|
|
239
|
-
/** task-1366: display options. `priceMode` price | mcap (the `$` key toggles and persists it). */
|
|
240
|
-
display: { type: 'object', additional: false, props: { priceMode: { type: 'string', enum: PRICE_MODES } } },
|
|
253
|
+
/** task-1366: display options. `priceMode` price | mcap (the `$` key toggles and persists it). task-1472: `chartAxis` mcap | price (`A`; absent = mcap). task-1483: `chartMarkers` on | off (absent = on). */
|
|
254
|
+
display: { type: 'object', additional: false, props: { priceMode: { type: 'string', enum: PRICE_MODES }, chartAxis: { type: 'string', enum: CHART_AXES }, chartMarkers: { type: 'string', enum: CHART_MARKERS } } },
|
|
241
255
|
layout: { type: 'object', additional: false, props: {
|
|
242
256
|
workspace: { type: 'string', pattern: WS_NAME },
|
|
243
257
|
workspaces: { type: 'object', values: 'workspace' },
|
|
@@ -263,7 +277,7 @@ export const SCHEMAS = {
|
|
|
263
277
|
} },
|
|
264
278
|
/** 0.1.5: which of the user's own CLIs runs the analyst. `/analyst` is user-only (DENIED_FOR_MODELS): a model never picks its own engine. */
|
|
265
279
|
analyst: { type: 'object', additional: false, props: {
|
|
266
|
-
engine: { type: 'string', enum: ['auto', 'claude', 'codex'] },
|
|
280
|
+
engine: { type: 'string', enum: ['auto', 'claude', 'codex', 'ollama'] },
|
|
267
281
|
} },
|
|
268
282
|
/** task-1393: voice-out preferences. `/voice` is user-only (DENIED_FOR_MODELS), so only the keyboard sets it. */
|
|
269
283
|
voice: { type: 'object', additional: false, props: {
|
|
@@ -518,12 +532,29 @@ export const MIGRATIONS = {
|
|
|
518
532
|
3: (c, out) => {
|
|
519
533
|
const prior = (c.display && typeof c.display === 'object' ? c.display.priceMode : undefined);
|
|
520
534
|
const priceMode = PRICE_MODES.includes(prior) ? prior : DEFAULT_PRICE_MODE;
|
|
521
|
-
out.notes.push(`added display.priceMode = ${priceMode} (press $ in the app to
|
|
535
|
+
out.notes.push(`added display.priceMode = ${priceMode} (press $ in the app to switch market cap / USD price)`);
|
|
522
536
|
return { ...c, version: 4, display: { priceMode } };
|
|
523
537
|
},
|
|
538
|
+
// v4 → v5 (task-1537): market cap is the default price basis. Every saved config carried `priceMode: "price"`
|
|
539
|
+
// because that was the default written with the first save, so a `price` moves to `mcap` UNLESS the config
|
|
540
|
+
// journal shows the user chose price themselves (`$`, `dexterm display price`, an approved proposal): that stays.
|
|
541
|
+
4: (c, out) => {
|
|
542
|
+
const d = c.display && typeof c.display === 'object' ? { ...c.display } : {};
|
|
543
|
+
const kept = out.journaledPriceMode === 'price';
|
|
544
|
+
if (d.priceMode === 'price' && !kept) {
|
|
545
|
+
d.priceMode = 'mcap';
|
|
546
|
+
out.notes.push('display.priceMode: market cap is now the default basis (screens, CLI text and the assistant); press $ or run `dexterm display price` to go back to USD price');
|
|
547
|
+
}
|
|
548
|
+
else if (d.priceMode === 'price') {
|
|
549
|
+
out.notes.push('display.priceMode = price kept (you chose it); market cap is the new default, `dexterm display mcap` switches');
|
|
550
|
+
}
|
|
551
|
+
else if (!PRICE_MODES.includes(d.priceMode))
|
|
552
|
+
d.priceMode = DEFAULT_PRICE_MODE;
|
|
553
|
+
return { ...c, version: 5, display: d };
|
|
554
|
+
},
|
|
524
555
|
};
|
|
525
|
-
export function migrate(raw) {
|
|
526
|
-
const out = { notes: [], extractedKeys: {}, from: Number(raw?.version ?? 1), to: CONFIG_VERSION };
|
|
556
|
+
export function migrate(raw, hints = {}) {
|
|
557
|
+
const out = { notes: [], extractedKeys: {}, from: Number(raw?.version ?? 1), to: CONFIG_VERSION, journaledPriceMode: hints.journaledPriceMode ?? null };
|
|
527
558
|
let cur = raw && typeof raw === 'object' ? structuredClone(raw) : {};
|
|
528
559
|
let v = out.from;
|
|
529
560
|
if (!Number.isInteger(v) || v < 1)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// Workspaces hold NO keys, NO trading settings and NO code: the schema is additional:false and a pack or a
|
|
7
7
|
// Jarvis proposal that tries to smuggle anything else is refused by name (schema.ts). Switching a workspace
|
|
8
8
|
// is a UI action: it can navigate, re-theme and open read-only popups; it can never arm, sign or confirm.
|
|
9
|
-
import { validate, POPUP_KINDS, WORKSPACE_SCREENS } from "./schema.js";
|
|
9
|
+
import { validate, DEFAULT_PRICE_MODE, POPUP_KINDS, WORKSPACE_SCREENS } from "./schema.js";
|
|
10
10
|
import { breakpoint, solve, treeFor, widgetsIn, widgetSpec } from "./layout.js";
|
|
11
11
|
export const DEFAULT_WORKSPACE = 'default';
|
|
12
12
|
export const MORNING_HUD = 'morning-hud';
|
|
@@ -114,8 +114,8 @@ export function layoutNumbers(ws, w, h) {
|
|
|
114
114
|
export function captureWorkspace(name, snap) {
|
|
115
115
|
const start = WORKSPACE_SCREENS.includes(snap.screen) ? snap.screen : 'screener';
|
|
116
116
|
const ws = { name, description: `saved from the ${snap.screen} screen`, start, theme: snap.theme, intensity: snap.intensity };
|
|
117
|
-
if (snap.priceMode && snap.priceMode !==
|
|
118
|
-
ws.priceMode = snap.priceMode;
|
|
117
|
+
if (snap.priceMode && snap.priceMode !== DEFAULT_PRICE_MODE)
|
|
118
|
+
ws.priceMode = snap.priceMode; // task-1537: the default is mcap
|
|
119
119
|
if (snap.screens)
|
|
120
120
|
ws.screens = structuredClone(snap.screens);
|
|
121
121
|
const sc = {};
|