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
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
// changed, otherwise just the last two bars ("tail"), so a live tick costs the page one `series.update`.
|
|
10
10
|
// When the coin is held (task-1323 PositionSource) the VM carries the position row + entry/stop/target levels
|
|
11
11
|
// and the fills of the current position from the paper ledger. Read-only: nothing here can trade.
|
|
12
|
-
import { createPopupManager, loadConfig, nativeShellAvailable, TerminalDock, CHART_INTERVALS } from '../../popup/src/index.js';
|
|
12
|
+
import { createPopupManager, loadConfig, nativeShellAvailable, TerminalDock, CHART_INTERVALS, CHART_MARKS_MAX } from '../../popup/src/index.js';
|
|
13
13
|
import { fmtPrice, fmtNum } from '../../tui/src/index.js';
|
|
14
14
|
import { positionRow } from "./live/trade.js";
|
|
15
15
|
import { signedUsd, signedPctOf, fmtUsdFine, sol as fmtSol, signedSol } from "./screens/positions.js";
|
|
16
|
-
import { supplyRatio, positionPriceCells } from "./display.js";
|
|
16
|
+
import { supplyRatio, positionPriceCells, levelCell } from "./display.js";
|
|
17
|
+
import { chipSegments } from "./screens/pnl-chip.js";
|
|
17
18
|
/** Map the app's active Theme to the popup protocol's theme-token subset. */
|
|
18
19
|
export function popupThemeFrom(t) {
|
|
19
20
|
return {
|
|
@@ -25,6 +26,11 @@ export function popupThemeFrom(t) {
|
|
|
25
26
|
/** Most bars one VM carries (the 1m base is 1000 bars; this only guards a future bigger base). */
|
|
26
27
|
export const CHART_MAX_BARS = 1500;
|
|
27
28
|
export const DEFAULT_CHART_PREFS = { style: 'candles', scale: 'auto', indicators: ['volume', 'tape', 'ema9', 'ema21'] };
|
|
29
|
+
/** task-1483: the VM's markers layer: the newest CHART_MARKS_MAX fills (oldest first), and how many older ones were left out. */
|
|
30
|
+
export function chartMarksFrom(on, fills) {
|
|
31
|
+
const keep = fills.length > CHART_MARKS_MAX ? fills.slice(-CHART_MARKS_MAX) : fills;
|
|
32
|
+
return { on, fills: keep.map((f) => ({ t: f.t, side: f.side, source: f.source, priceUsd: f.priceUsd, tokens: f.tokens, sol: f.sol })), truncated: fills.length - keep.length };
|
|
33
|
+
}
|
|
28
34
|
const finitePos = (n) => typeof n === 'number' && Number.isFinite(n) && n > 0;
|
|
29
35
|
/** Token amounts up to trillions (same rule as the terminal's position row). */
|
|
30
36
|
function fmtAmt(n) { return n >= 1e12 ? `${(n / 1e12).toFixed(2)}T` : fmtNum(n); }
|
|
@@ -56,9 +62,9 @@ export function positionCells(r, mode = 'price', supply = null) {
|
|
|
56
62
|
if (r.realizedSol !== 0)
|
|
57
63
|
cells.push({ label: 'REALIZED', value: usd && r.realizedUsd !== null ? signedUsd(r.realizedUsd) : `${signedSol(r.realizedSol)} SOL`, tone: tone(r.realizedSol) });
|
|
58
64
|
if (r.stopUsd !== null)
|
|
59
|
-
cells.push({ label: 'STOP', value: `${
|
|
65
|
+
cells.push({ label: 'STOP', value: `${levelCell(mode, supply, r.stopUsd)}${r.stopDistPct !== null ? ` ${signedPctOf(r.stopDistPct)}` : ''}`, tone: 'down' });
|
|
60
66
|
if (r.targetUsd !== null)
|
|
61
|
-
cells.push({ label: 'TARGET', value: `${
|
|
67
|
+
cells.push({ label: 'TARGET', value: `${levelCell(mode, supply, r.targetUsd)}${r.targetDistPct !== null ? ` ${signedPctOf(r.targetDistPct)}` : ''}`, tone: 'up' });
|
|
62
68
|
return cells;
|
|
63
69
|
}
|
|
64
70
|
/** The chart's position model from the shared task-1323 selector (PositionSource → positionRow). */
|
|
@@ -137,7 +143,7 @@ export function chartVMFromView(v, x = {}) {
|
|
|
137
143
|
vm.feed = x.feed ?? 'POLL';
|
|
138
144
|
vm.livePrice = x.feed === 'LIVE' && finitePos(x.livePrice) ? x.livePrice : null;
|
|
139
145
|
vm.trades = v.trades.map((t) => ({ t: t.t, side: t.side, usd: t.usd, price: t.price })); // no wallet addresses
|
|
140
|
-
const mode = x.priceMode === '
|
|
146
|
+
const mode = x.priceMode === 'price' ? 'price' : 'mcap'; // task-1537: market cap unless the host says price
|
|
141
147
|
const supply = mode === 'mcap' ? supplyRatio(v.price, v.mcap) : null;
|
|
142
148
|
vm.position = x.held ? chartPositionFrom(x.held, tick, x.solUsd ?? null, x.positionKind ?? 'paper', x.fills ?? [], mode, supply) : null;
|
|
143
149
|
vm.prefs = x.prefs ?? DEFAULT_CHART_PREFS;
|
|
@@ -146,6 +152,8 @@ export function chartVMFromView(v, x = {}) {
|
|
|
146
152
|
// task-1366: display only — the bars stay USD prices; the page formats the axis as price × supply in mcap mode
|
|
147
153
|
vm.priceMode = mode;
|
|
148
154
|
vm.supply = supply;
|
|
155
|
+
if (x.marks)
|
|
156
|
+
vm.marks = chartMarksFrom(x.marks.on, x.marks.fills); // task-1483
|
|
149
157
|
return vm;
|
|
150
158
|
}
|
|
151
159
|
/** Build the token-detail popup view model from the live TokenView (reused by the openPopup interface / Jarvis). */
|
|
@@ -160,6 +168,12 @@ export function tokenDetailVMFromView(v, intel = null) {
|
|
|
160
168
|
flags: v.flags.map((f) => String(f)), holdersSample: v.holdersSample, updatedAt: v.updatedAt,
|
|
161
169
|
};
|
|
162
170
|
}
|
|
171
|
+
/** task-1473 r2: the chip as the chart page draws it (same segments as the terminal). */
|
|
172
|
+
export function chartChipFrom(m) {
|
|
173
|
+
if (!m)
|
|
174
|
+
return null;
|
|
175
|
+
return { kind: m.kind, symbol: m.symbol, tone: m.pnlPct === null ? 'muted' : m.pnlPct >= 0 ? 'up' : 'down', newPeak: m.newPeak, segments: chipSegments(m) };
|
|
176
|
+
}
|
|
163
177
|
/** "docked right of Terminal" / "screen right (unknown terminal)" — for the TUI toast. */
|
|
164
178
|
export function describeDock(p) {
|
|
165
179
|
if (!p)
|
|
@@ -432,6 +446,22 @@ export class TokenPopups {
|
|
|
432
446
|
case 'chart.scale':
|
|
433
447
|
this.prefs = { ...this.prefs, scale: p.scale };
|
|
434
448
|
return;
|
|
449
|
+
case 'chart.axis': { // task-1472: a display preference the terminal saves; nothing else
|
|
450
|
+
if (p.axis !== 'mcap' && p.axis !== 'price')
|
|
451
|
+
return;
|
|
452
|
+
this.source?.setChartAxis?.(p.axis);
|
|
453
|
+
if (this.lastView)
|
|
454
|
+
this.push(this.lastView);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
case 'chart.markers': { // task-1483: a display preference the terminal saves; nothing else
|
|
458
|
+
if (typeof p.on !== 'boolean')
|
|
459
|
+
return;
|
|
460
|
+
this.source?.setChartMarkers?.(p.on);
|
|
461
|
+
if (this.lastView)
|
|
462
|
+
this.push(this.lastView);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
435
465
|
case 'chart.painted': {
|
|
436
466
|
const ms = Number(p.ms);
|
|
437
467
|
if (p.kind === 'first' && this.metrics.openedAt !== null && this.metrics.openToFirstPaintMs === null)
|
|
@@ -520,8 +550,10 @@ export class TokenPopups {
|
|
|
520
550
|
prefs: this.prefs,
|
|
521
551
|
now: this.now(),
|
|
522
552
|
image: src.imagePath?.(view) ?? null,
|
|
523
|
-
priceMode: src.priceMode?.() ?? '
|
|
553
|
+
priceMode: src.chartAxis?.() ?? src.priceMode?.() ?? 'mcap', // task-1472: the chart axis drives the popup
|
|
554
|
+
marks: src.markFills ? { on: src.chartMarkers?.() ?? true, fills: src.markFills(view.mint) } : null, // task-1483
|
|
524
555
|
});
|
|
556
|
+
vm.chip = chartChipFrom(src.pnlChip?.() ?? null); // task-1473 r2
|
|
525
557
|
const key = vm.seriesKey ?? null;
|
|
526
558
|
const n = vm.candles.length;
|
|
527
559
|
const canTail = !full && this.ready && key !== null && key === this.lastKey && this.lastLen > 0 && n >= this.lastLen && n <= this.lastLen + 1;
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
// (observe snapshots + feed membership, the 1 h/2 h/6 h/24 h/72 h outcome sweeps, labels, retention) with no
|
|
5
5
|
// TUI, to be driven by a user-level launchd LaunchAgent on the Mac mini.
|
|
6
6
|
//
|
|
7
|
-
// dexterm record [run] [--interval S] [--ticks N | --once] [--maintain S] [--max-db-mb N] [--
|
|
8
|
-
//
|
|
7
|
+
// dexterm record [run] [--interval S] [--ticks N | --once] [--maintain S] [--max-db-mb N] [--retention-mb N] [--retention-days D]
|
|
8
|
+
// [--focus-ticks] [--no-newpairs] [--db PATH] [--verbose]
|
|
9
|
+
// dexterm record install [--interval S] [--max-db-mb N] [--retention-mb N] [--retention-days D] [--focus-ticks] [--load] [--dry-run]
|
|
9
10
|
// dexterm record uninstall [--unload]
|
|
10
11
|
// dexterm record status [--db PATH]
|
|
11
12
|
//
|
|
@@ -15,13 +16,18 @@
|
|
|
15
16
|
// the data layer; only the provider name is ever logged). Modest CPU: one feed refresh per `--interval` (60 s
|
|
16
17
|
// default) and recorder maintenance at most every `--maintain` seconds. A soft disk cap pauses OBSERVATION
|
|
17
18
|
// (the growth source) above `--max-db-mb` while labels + retention keep running, so the DB cannot run away.
|
|
19
|
+
// task-1504 (AUTOTRADE-SPEC §3, §10 Q4), both opt-in so an installed collector behaves as before until it is
|
|
20
|
+
// re-installed with them: `--retention-mb N` replaces that pause with eviction of the oldest history (observation
|
|
21
|
+
// never pauses), `--retention-days D` is the age rule for snapshot rows, and `--focus-ticks` runs the autotrade
|
|
22
|
+
// tick lane (5–10 s DexScreener samples of watchlist / held / candidate / open coins, plus 1m candles).
|
|
18
23
|
import { mkdirSync, writeFileSync, existsSync, rmSync } from 'node:fs';
|
|
19
24
|
import { spawnSync } from 'node:child_process';
|
|
20
25
|
import { dirname, join, resolve } from 'node:path';
|
|
21
26
|
import { fileURLToPath } from 'node:url';
|
|
22
27
|
import { defaultDbPath, resolveRpcUrl, extraRpcUrls, redactSecrets } from '../../data/src/index.js';
|
|
23
28
|
import { PumpPortalClient } from '../../data/src/index.js';
|
|
24
|
-
import { Recorder, recorderEnabled } from '../../recorder/src/index.js';
|
|
29
|
+
import { Recorder, recorderEnabled, dbFocus, focusFilePath, readFocusFile, DEFAULT_TICKS } from '../../recorder/src/index.js';
|
|
30
|
+
import { dextermHome } from "./boot-state.js";
|
|
25
31
|
import { createLiveFeed } from "./feed.js";
|
|
26
32
|
import { NewPairsLive } from "./live/index.js";
|
|
27
33
|
/** The LaunchAgent label (reverse-DNS). One collector per user. */
|
|
@@ -41,7 +47,17 @@ export function buildLiveEngine(env, opts) {
|
|
|
41
47
|
dbPath: opts.dbPath, rpcUrl: rpc.url, rpcFallbackUrl: rpc.fallbackUrl, rpcPublicPool: true, rpcExtraUrls: extraRpcUrls(env),
|
|
42
48
|
onRequest: opts.verbose ? (req, meta, o) => opts.onLog?.(` ${meta.source.padEnd(14)} ${String(o.status ?? 'ERR').padStart(3)} ${String(o.latencyMs).padStart(5)}ms ${redactSecrets(req.url).slice(0, 110)}\n`) : undefined,
|
|
43
49
|
});
|
|
44
|
-
|
|
50
|
+
// Focus coins for the tick lane: the watchlist + paper positions in this DB, and whatever the autotrade runner /
|
|
51
|
+
// the app publish in the focus file. Read on every poll (two indexed reads + one small file).
|
|
52
|
+
const focusFile = focusFilePath(dextermHome(env));
|
|
53
|
+
const recorder = new Recorder({
|
|
54
|
+
path: opts.dbPath, onLog: opts.verbose ? opts.onLog : undefined,
|
|
55
|
+
// The cap reclaims the data layer's expired cache entries (its own rule: a day past their TTL) before it evicts
|
|
56
|
+
// any history; `feed` is built above, so the hook can reach it.
|
|
57
|
+
...(opts.retentionBytes ? { cap: { maxBytes: opts.retentionBytes, reclaim: () => feed.dl.cache.prune() } } : {}),
|
|
58
|
+
...(opts.retentionDays ? { retention: { columnsDays: opts.retentionDays } } : {}),
|
|
59
|
+
...(opts.focusTicks ? { ticks: { focus: () => [...dbFocus(recorder.database), ...readFocusFile(focusFile, Date.now())] } } : {}),
|
|
60
|
+
});
|
|
45
61
|
recorder.attach(feed.dl.store);
|
|
46
62
|
let newpairs = null;
|
|
47
63
|
if (!opts.noNewpairs) {
|
|
@@ -66,6 +82,8 @@ export function buildLiveEngine(env, opts) {
|
|
|
66
82
|
recorder.prune();
|
|
67
83
|
}
|
|
68
84
|
catch { /* logged inside; never fatal */ } },
|
|
85
|
+
enforceCap() { return recorder.enforceCap(); },
|
|
86
|
+
...(opts.focusTicks ? { pollTicks: () => recorder.pollTicks(dl) } : {}),
|
|
69
87
|
dbBytes() {
|
|
70
88
|
try {
|
|
71
89
|
const db = recorder.database;
|
|
@@ -101,7 +119,7 @@ export function buildLiveEngine(env, opts) {
|
|
|
101
119
|
* Never throws out of the loop: an engine error is logged and the loop continues to the next tick.
|
|
102
120
|
*/
|
|
103
121
|
export async function runCollectorLoop(engine, opts) {
|
|
104
|
-
const res = { ticks: 0, observePasses: 0, rowsWritten: 0, maintainPasses: 0, cappedTicks: 0 };
|
|
122
|
+
const res = { ticks: 0, observePasses: 0, rowsWritten: 0, maintainPasses: 0, cappedTicks: 0, evictions: 0 };
|
|
105
123
|
let lastMaintain = -Infinity;
|
|
106
124
|
for (let i = 0; i < opts.ticks && !opts.aborted(); i++) {
|
|
107
125
|
if (i > 0) {
|
|
@@ -111,7 +129,19 @@ export async function runCollectorLoop(engine, opts) {
|
|
|
111
129
|
}
|
|
112
130
|
res.ticks++;
|
|
113
131
|
let over = false;
|
|
114
|
-
if (opts.
|
|
132
|
+
if (opts.capMode === 'evict') {
|
|
133
|
+
try {
|
|
134
|
+
const c = engine.enforceCap?.() ?? null;
|
|
135
|
+
if (c?.evicted)
|
|
136
|
+
res.evictions++;
|
|
137
|
+
if (c?.over)
|
|
138
|
+
opts.onLog?.(`record: DB still at ${(c.usedAfter / 1e6).toFixed(0)} MB used after evicting all but the newest hour (other tables are large); observation continues\n`);
|
|
139
|
+
}
|
|
140
|
+
catch (e) {
|
|
141
|
+
opts.onLog?.(`record: retention failed: ${redactSecrets(e.message)}\n`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
else if (opts.maxDbBytes !== null) {
|
|
115
145
|
const b = engine.dbBytes();
|
|
116
146
|
if (b !== null && b >= opts.maxDbBytes) {
|
|
117
147
|
engine.prune();
|
|
@@ -146,6 +176,29 @@ export async function runCollectorLoop(engine, opts) {
|
|
|
146
176
|
}
|
|
147
177
|
return res;
|
|
148
178
|
}
|
|
179
|
+
/** task-1504: drive the tick lane every `everyMs` until aborted. Never throws (a failed poll is logged). */
|
|
180
|
+
export async function runTickLoop(engine, opts) {
|
|
181
|
+
const res = { polls: 0, calls: 0, written: 0 };
|
|
182
|
+
if (!engine.pollTicks)
|
|
183
|
+
return res;
|
|
184
|
+
while (!opts.aborted()) {
|
|
185
|
+
try {
|
|
186
|
+
const r = await engine.pollTicks();
|
|
187
|
+
res.polls++;
|
|
188
|
+
res.calls += r.calls;
|
|
189
|
+
res.written += r.written;
|
|
190
|
+
if (r.error)
|
|
191
|
+
opts.onLog?.(`record: tick poll failed: ${redactSecrets(r.error)}\n`);
|
|
192
|
+
}
|
|
193
|
+
catch (e) {
|
|
194
|
+
opts.onLog?.(`record: tick poll failed: ${redactSecrets(e.message)}\n`);
|
|
195
|
+
}
|
|
196
|
+
if (opts.aborted())
|
|
197
|
+
break;
|
|
198
|
+
await opts.sleep(opts.everyMs);
|
|
199
|
+
}
|
|
200
|
+
return res;
|
|
201
|
+
}
|
|
149
202
|
const esc = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
150
203
|
/**
|
|
151
204
|
* A user-level LaunchAgent (no sudo). KeepAlive so a crash or a reboot-after-login brings it back, RunAtLoad,
|
|
@@ -155,7 +208,7 @@ const esc = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g,
|
|
|
155
208
|
* collector to run; a true pre-login daemon would be a LaunchDaemon under sudo, which this task does not use.
|
|
156
209
|
*/
|
|
157
210
|
export function renderCollectorPlist(o) {
|
|
158
|
-
const args = [o.nodePath, o.binPath, 'record', 'run', '--interval', String(Math.round(o.intervalMs / 1000)), '--max-db-mb', String(o.maxDbMb)];
|
|
211
|
+
const args = [o.nodePath, o.binPath, 'record', 'run', '--interval', String(Math.round(o.intervalMs / 1000)), '--max-db-mb', String(o.maxDbMb), ...(o.extraArgs ?? [])];
|
|
159
212
|
const argXml = args.map((a) => ` <string>${esc(a)}</string>`).join('\n');
|
|
160
213
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
161
214
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -202,10 +255,37 @@ function dataDir(env, db) {
|
|
|
202
255
|
function sourceBin() {
|
|
203
256
|
return fileURLToPath(new URL('../bin/dexterm.mjs', import.meta.url));
|
|
204
257
|
}
|
|
258
|
+
/** task-1504: the shared `--retention-mb` / `--retention-days` / `--focus-ticks` parser (run + install). */
|
|
259
|
+
function parseRetention(t, next, a) {
|
|
260
|
+
if (t === '--focus-ticks') {
|
|
261
|
+
a.focusTicks = true;
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
if (t === '--retention-mb') {
|
|
265
|
+
const n = Number(next());
|
|
266
|
+
if (!Number.isFinite(n) || n < 1)
|
|
267
|
+
return '--retention-mb needs a number ≥ 1';
|
|
268
|
+
a.retentionBytes = Math.round(n * 1_000_000);
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
if (t === '--retention-days') {
|
|
272
|
+
const n = Number(next());
|
|
273
|
+
if (!Number.isFinite(n) || n < 1)
|
|
274
|
+
return '--retention-days needs a number of days ≥ 1';
|
|
275
|
+
a.retentionDays = n;
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
205
280
|
export function parseRun(argv) {
|
|
206
|
-
const a = { intervalMs: DEFAULT_INTERVAL_MS, ticks: Infinity, maintainMs: DEFAULT_MAINTAIN_MS, maxDbBytes: DEFAULT_MAX_DB_MB * 1_000_000, noNewpairs: false, db: null, verbose: false };
|
|
281
|
+
const a = { intervalMs: DEFAULT_INTERVAL_MS, ticks: Infinity, maintainMs: DEFAULT_MAINTAIN_MS, maxDbBytes: DEFAULT_MAX_DB_MB * 1_000_000, noNewpairs: false, db: null, verbose: false, retentionBytes: null, retentionDays: null, focusTicks: false };
|
|
207
282
|
for (let i = 0; i < argv.length; i++) {
|
|
208
283
|
const t = argv[i];
|
|
284
|
+
const r = parseRetention(t, () => argv[++i], a);
|
|
285
|
+
if (typeof r === 'string')
|
|
286
|
+
return { error: r };
|
|
287
|
+
if (r === null)
|
|
288
|
+
continue;
|
|
209
289
|
if (t === '--verbose' || t === '-v')
|
|
210
290
|
a.verbose = true;
|
|
211
291
|
else if (t === '--no-newpairs')
|
|
@@ -248,15 +328,20 @@ export function parseRun(argv) {
|
|
|
248
328
|
}
|
|
249
329
|
export const RECORD_USAGE = `dexterm record: keep the history recorder fed with no TUI open (task-1414).
|
|
250
330
|
|
|
251
|
-
dexterm record [run] [--interval S] [--ticks N | --once] [--maintain S] [--max-db-mb N] [--
|
|
252
|
-
|
|
331
|
+
dexterm record [run] [--interval S] [--ticks N | --once] [--maintain S] [--max-db-mb N] [--retention-mb N] [--retention-days D]
|
|
332
|
+
[--focus-ticks] [--no-newpairs] [--db PATH] [--verbose]
|
|
333
|
+
dexterm record install [--interval S] [--max-db-mb N] [--retention-mb N] [--retention-days D] [--focus-ticks] [--load] [--dry-run]
|
|
253
334
|
dexterm record uninstall [--unload]
|
|
254
335
|
dexterm record status [--db PATH]
|
|
255
336
|
|
|
256
337
|
run the collector loop: one keyless feed refresh per --interval (default 60 s) feeds the recorder
|
|
257
338
|
(snapshots + feed membership + new pairs), recorder maintenance (outcome sweeps, labels, retention)
|
|
258
339
|
every --maintain seconds. --max-db-mb is a soft cap (default 1024): above it observation pauses while
|
|
259
|
-
labels + retention keep running. --
|
|
340
|
+
labels + retention keep running. --retention-mb N replaces that pause: the oldest history is evicted
|
|
341
|
+
to stay under N MB and observation never pauses. --retention-days D drops snapshot rows (sweep rows
|
|
342
|
+
too) older than D days (default 90). --focus-ticks samples watchlist / held / candidate / open coins
|
|
343
|
+
every 5-10 s (DexScreener batches of 30, a daily call ceiling) with 1m candles; autotrade backtests
|
|
344
|
+
read them. --no-newpairs drops the PumpPortal stream. Ctrl-C stops cleanly
|
|
260
345
|
(labels whatever is due). Requests honour the data layer's rate limits, health gate and sweep budgets.
|
|
261
346
|
install write a user-level launchd LaunchAgent (no sudo) that runs \`record run\`; prints the launchctl
|
|
262
347
|
command. --load also runs launchctl (off by default). --dry-run prints the plist, writes nothing.
|
|
@@ -300,47 +385,77 @@ async function run(argv, io, deps) {
|
|
|
300
385
|
return 2;
|
|
301
386
|
}
|
|
302
387
|
// SIGINT/SIGTERM-aware cancellable sleeper (launchd sends SIGTERM to stop the agent).
|
|
388
|
+
// Several loops may sleep at once (the collector + the tick lane), so every sleeper is woken on abort.
|
|
303
389
|
const stop = (() => {
|
|
304
390
|
let aborted = false;
|
|
305
|
-
|
|
391
|
+
const wakes = new Set();
|
|
306
392
|
return {
|
|
307
393
|
get aborted() { return aborted; },
|
|
308
|
-
abort() { aborted = true;
|
|
309
|
-
|
|
394
|
+
abort() { aborted = true; for (const w of [...wakes])
|
|
395
|
+
w(); },
|
|
396
|
+
sleep(ms) {
|
|
397
|
+
return new Promise((r) => {
|
|
398
|
+
const done = () => { clearTimeout(t); wakes.delete(done); r(); };
|
|
399
|
+
const t = setTimeout(done, ms);
|
|
400
|
+
t.unref?.();
|
|
401
|
+
wakes.add(done);
|
|
402
|
+
});
|
|
403
|
+
},
|
|
310
404
|
};
|
|
311
405
|
})();
|
|
312
406
|
const log = (s) => io.stderr.write(s);
|
|
313
|
-
const engine = deps.engine ?? buildLiveEngine(io.env, { dbPath, noNewpairs: parsed.noNewpairs, verbose: parsed.verbose, onLog: log });
|
|
407
|
+
const engine = deps.engine ?? buildLiveEngine(io.env, { dbPath, noNewpairs: parsed.noNewpairs, verbose: parsed.verbose, onLog: log, retentionBytes: parsed.retentionBytes, retentionDays: parsed.retentionDays, focusTicks: parsed.focusTicks });
|
|
314
408
|
const own = !deps.engine;
|
|
315
409
|
const onSig = () => { io.stderr.write('\ndexterm record: stopping…\n'); stop.abort(); };
|
|
316
410
|
if (own) {
|
|
317
411
|
process.on('SIGINT', onSig);
|
|
318
412
|
process.on('SIGTERM', onSig);
|
|
319
413
|
}
|
|
414
|
+
// The sleeps are unref'd; without the PumpPortal socket (--no-newpairs) nothing else would keep the event loop
|
|
415
|
+
// alive between passes and node would exit mid-run (task-1504 smoke). Hold it open until the loops finish.
|
|
416
|
+
const hold = own ? setInterval(() => { }, 1 << 30) : null;
|
|
320
417
|
if (parsed.verbose || parsed.ticks !== Infinity)
|
|
321
|
-
io.stderr.write(`dexterm record: db ${dbPath} · interval ${Math.round(parsed.intervalMs / 1000)}s · maintain ${Math.round(parsed.maintainMs / 1000)}s · cap ${parsed.maxDbBytes === null ? 'off' : `${Math.round(parsed.maxDbBytes / 1e6)} MB`} · newpairs ${parsed.noNewpairs ? 'off' : 'on'}\n`);
|
|
418
|
+
io.stderr.write(`dexterm record: db ${dbPath} · interval ${Math.round(parsed.intervalMs / 1000)}s · maintain ${Math.round(parsed.maintainMs / 1000)}s · cap ${parsed.maxDbBytes === null ? 'off' : `${Math.round(parsed.maxDbBytes / 1e6)} MB`} · newpairs ${parsed.noNewpairs ? 'off' : 'on'}${parsed.retentionBytes !== null ? ` · retention ${Math.round(parsed.retentionBytes / 1e6)} MB (evict, never pause)` : ''}${parsed.retentionDays !== null ? ` · rows ${parsed.retentionDays} d` : ''} · focus ticks ${parsed.focusTicks ? 'on' : 'off'}\n`);
|
|
322
419
|
let result;
|
|
420
|
+
let tickRes = { polls: 0, calls: 0, written: 0 };
|
|
323
421
|
try {
|
|
324
|
-
|
|
422
|
+
let mainDone = false;
|
|
423
|
+
const main = runCollectorLoop(engine, {
|
|
325
424
|
intervalMs: parsed.intervalMs, ticks: parsed.ticks, maintainEveryMs: parsed.maintainMs, maxDbBytes: parsed.maxDbBytes,
|
|
425
|
+
capMode: parsed.retentionBytes !== null ? 'evict' : 'pause',
|
|
326
426
|
now, sleep: (ms) => stop.sleep(ms), aborted: () => stop.aborted, onLog: log,
|
|
327
|
-
});
|
|
427
|
+
}).finally(() => { mainDone = true; if (parsed.ticks !== Infinity)
|
|
428
|
+
stop.abort(); });
|
|
429
|
+
const lane = parsed.focusTicks && engine.pollTicks
|
|
430
|
+
? runTickLoop(engine, { everyMs: DEFAULT_TICKS.fastEveryMs, sleep: (ms) => stop.sleep(ms), aborted: () => stop.aborted || mainDone, onLog: log })
|
|
431
|
+
: Promise.resolve(tickRes);
|
|
432
|
+
[result, tickRes] = await Promise.all([main, lane]);
|
|
328
433
|
}
|
|
329
434
|
finally {
|
|
330
435
|
if (own) {
|
|
331
436
|
process.removeListener('SIGINT', onSig);
|
|
332
437
|
process.removeListener('SIGTERM', onSig);
|
|
333
438
|
}
|
|
439
|
+
if (hold)
|
|
440
|
+
clearInterval(hold);
|
|
334
441
|
engine.close();
|
|
335
442
|
}
|
|
336
443
|
if (parsed.verbose || parsed.ticks !== Infinity)
|
|
337
|
-
io.stdout.write(`record: ${result.observePasses} observe pass(es), ${result.rowsWritten} snapshot row(s), ${result.maintainPasses} maintenance pass(es)${result.cappedTicks ? `, ${result.cappedTicks} tick(s) paused at the disk cap` : ''}\n`);
|
|
444
|
+
io.stdout.write(`record: ${result.observePasses} observe pass(es), ${result.rowsWritten} snapshot row(s), ${result.maintainPasses} maintenance pass(es)${result.cappedTicks ? `, ${result.cappedTicks} tick(s) paused at the disk cap` : ''}${result.evictions ? `, ${result.evictions} retention eviction(s)` : ''}${tickRes.polls ? `, ${tickRes.polls} focus-tick poll(s) (${tickRes.calls} call(s), ${tickRes.written} tick row(s))` : ''}\n`);
|
|
338
445
|
return 0;
|
|
339
446
|
}
|
|
340
447
|
function install(argv, io) {
|
|
341
448
|
let intervalMs = DEFAULT_INTERVAL_MS, maxDbMb = DEFAULT_MAX_DB_MB, load = false, dry = false;
|
|
449
|
+
const ret = { retentionBytes: null, retentionDays: null, focusTicks: false };
|
|
342
450
|
for (let i = 0; i < argv.length; i++) {
|
|
343
451
|
const t = argv[i];
|
|
452
|
+
const r = parseRetention(t, () => argv[++i], ret);
|
|
453
|
+
if (typeof r === 'string') {
|
|
454
|
+
io.stderr.write(`dexterm record: ${r}\n`);
|
|
455
|
+
return 2;
|
|
456
|
+
}
|
|
457
|
+
if (r === null)
|
|
458
|
+
continue;
|
|
344
459
|
if (t === '--load')
|
|
345
460
|
load = true;
|
|
346
461
|
else if (t === '--dry-run')
|
|
@@ -369,7 +484,12 @@ function install(argv, io) {
|
|
|
369
484
|
const path = plistPath(io.env);
|
|
370
485
|
const logPath = join(dataDir(io.env), 'collector.log');
|
|
371
486
|
const bin = sourceBin();
|
|
372
|
-
const
|
|
487
|
+
const extraArgs = [
|
|
488
|
+
...(ret.retentionBytes !== null ? ['--retention-mb', String(Math.round(ret.retentionBytes / 1e6))] : []),
|
|
489
|
+
...(ret.retentionDays !== null ? ['--retention-days', String(ret.retentionDays)] : []),
|
|
490
|
+
...(ret.focusTicks ? ['--focus-ticks'] : []),
|
|
491
|
+
];
|
|
492
|
+
const plist = renderCollectorPlist({ label: COLLECTOR_LABEL, nodePath: process.execPath, binPath: bin, intervalMs, maxDbMb, extraArgs, logPath, workingDir: resolve(dirname(bin), '..', '..', '..') });
|
|
373
493
|
if (dry) {
|
|
374
494
|
io.stdout.write(plist);
|
|
375
495
|
io.stderr.write(`\ndexterm record: dry run — would write ${path}\n`);
|
|
@@ -427,6 +547,7 @@ function status(argv, io) {
|
|
|
427
547
|
`snapshots ${s.snapshots} (live ${s.live}, sweep ${s.sweep}, t0 anchors ${s.t0})`,
|
|
428
548
|
`outcomes ${s.outcomes}${s.outcomes ? ` (${Object.entries(s.outcomesByLabel).map(([k, v]) => `${k} ${v}`).join(', ')})` : ''}`,
|
|
429
549
|
`sweeps ${s.sweeps} runs · ${s.sweepCallsToday} DexScreener calls today`,
|
|
550
|
+
`focus ticks ${s.ticks} rows · ${s.candles} 1m candles · ${s.tickCallsToday} calls today`,
|
|
430
551
|
`span ${when(s.oldestT)} → ${when(s.newestT)}`,
|
|
431
552
|
].join('\n') + '\n');
|
|
432
553
|
}
|
|
@@ -11,8 +11,14 @@ export const SCAN_TICK_MS = 2_000;
|
|
|
11
11
|
export const SCAN_RECOMPUTE_MS = 10_000;
|
|
12
12
|
/** The analyst UI actions a scan session may request: NONE (observe-only). */
|
|
13
13
|
export const SCAN_ACTION_TYPES = Object.freeze([]);
|
|
14
|
+
/** task-1473: append one line to the scan's session log (the analyst panel's brain view shows it). */
|
|
15
|
+
export function scanLog(scan, t, kind, symbol, text) {
|
|
16
|
+
scan.log.push({ t, kind, symbol: cleanText(symbol, 12), text });
|
|
17
|
+
if (scan.log.length > 40)
|
|
18
|
+
scan.log.splice(0, scan.log.length - 40);
|
|
19
|
+
}
|
|
14
20
|
export function makeScanUi(cfg = {}) {
|
|
15
|
-
return { engine: new ScanEngine(cfg), sig: '', lastTickAt: 0, lastComputeAt: 0, session: null, blocked: [], returnTo: null };
|
|
21
|
+
return { engine: new ScanEngine(cfg), sig: '', lastTickAt: 0, lastComputeAt: 0, session: null, blocked: [], returnTo: null, log: [] };
|
|
16
22
|
}
|
|
17
23
|
export const MODE_LABEL = { off: 'OFF', scanning: 'SCANNING', locked: 'LOCKED', paused: 'PAUSED' };
|
|
18
24
|
const SHORT = { vol: 'vol', flow: 'flow', fresh: 'fresh', breakout: 'brk', liq: 'liq', holders: 'hold' };
|