dexterm-cli 0.1.3 → 0.1.5
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/cli/assets/claude/analyst-system.md +2 -1
- package/dist/packages/cli/src/agent-paper.js +60 -0
- package/dist/packages/cli/src/analyst/backend.js +183 -0
- package/dist/packages/cli/src/analyst/codex.js +301 -0
- package/dist/packages/cli/src/analyst/session.js +9 -2
- package/dist/packages/cli/src/app-help-gen.js +18 -9
- package/dist/packages/cli/src/docs-kb-gen.js +228 -0
- package/dist/packages/cli/src/doctor.js +80 -9
- package/dist/packages/cli/src/index.js +1 -1
- package/dist/packages/cli/src/kb-skill-cmd.js +3 -0
- package/dist/packages/cli/src/larp-detected.js +209 -0
- package/dist/packages/cli/src/live/dev-history.js +99 -0
- package/dist/packages/cli/src/live/newpairs.js +12 -0
- package/dist/packages/cli/src/live/screens/token-live.js +11 -1
- package/dist/packages/cli/src/live/token.js +39 -1
- package/dist/packages/cli/src/main.js +260 -7
- package/dist/packages/cli/src/mcp-follow.js +255 -0
- package/dist/packages/cli/src/record-cmd.js +2 -0
- package/dist/packages/cli/src/rules.js +25 -2
- package/dist/packages/cli/src/screens/analyst-session.js +5 -3
- package/dist/packages/cli/src/screens/analyst.js +4 -3
- package/dist/packages/cli/src/spectate-cmd.js +14 -3
- package/dist/packages/cli/src/version.js +1 -1
- package/dist/packages/cli/src/x-cmd.js +11 -5
- package/dist/packages/custom/src/rules.js +2 -2
- package/dist/packages/custom/src/schema.js +5 -1
- package/dist/packages/data/src/fixtures.js +28 -6
- package/dist/packages/data/src/index.js +3 -0
- package/dist/packages/data/src/sources/jupiter.js +1 -0
- package/dist/packages/data/src/trade/agent/paper-desk.js +336 -0
- package/dist/packages/data/src/trade/agent/rendezvous.js +161 -0
- package/dist/packages/mcp/assets/kb/app-help/agent-paper-trade.md +38 -0
- package/dist/packages/mcp/assets/kb/app-help/ask-the-analyst.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/connect-an-agent.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/dev-history.md +32 -0
- package/dist/packages/mcp/assets/kb/app-help/paper-trade.md +1 -1
- package/dist/packages/mcp/assets/kb/app-help/screen-positions.md +4 -1
- package/dist/packages/mcp/assets/kb/app-help/screen-token.md +1 -0
- package/dist/packages/mcp/assets/kb/app-help/spectate-an-agent.md +4 -1
- package/dist/packages/mcp/assets/kb/app-help/use-codex-analyst.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-agent-paper-trading.md +50 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-capability-tiers-enforced-server-side.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-directory-metadata-prepared-not-submitted.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-install-in-one-command.md +51 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-per-agent-mandates.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-recipes.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-red-team-coverage.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-two-ways-to-connect.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-untrusted-by-default.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents-watch-an-agent-work-spectator-view.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-agents.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-answer-style.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-if-claude-is-missing.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-it-knows-the-app.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-mcp-tools.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-plain-language-filters.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-skills.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-starting-a-run.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-use-codex-instead-of-claude.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-can-change-three-tiers.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-it-sees.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst-what-the-analyst-can-never-do.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-analyst.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-1-start-dexterm.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-2-open-a-real-coin-by-contract-address.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-3-read-the-safety-panel.md +40 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-4-read-the-holder-panel.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-5-optionally-ask-the-analyst.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-6-export-or-share-what-you-see.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-7-quit-safely.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-before-any-experimental-trading.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-check-the-installation-with-doctor.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-choose-a-setup-path.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-common-mistakes-and-recovery.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-copy-and-paste-without-surprises.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-data-says-unavailable-stale-or-rate-limited.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-dexterm-says-command-not-found.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-optional-help-is-unavailable.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-paste-does-nothing-or-pastes-twice.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-the-screen-looks-broken.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-if-you-typed-the-wrong-thing.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-install-node-js-first.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-linux.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos-homebrew.md +46 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos-or-linux-npm.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-macos.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-open-the-terminal.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-reopen-dexterm-later.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-ten-minute-first-win.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-terminal-shell-prompt-command-output-and-path.md +40 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-where-to-go-next.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows-expectations.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows-powershell-experimental.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners-windows.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-beginners.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-dexterm-help.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-filter-grammar.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-flags.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-invocations.md +43 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-presets.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-scan-commands.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-sort-keys.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli-subcommands.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-cli.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-environment-variables.md +47 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-files-on-disk.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-headless-recorder-dexterm-record.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-history-recorder.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-packs.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-price-display-mode.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-push-alerts-and-dexterm-watch.md +45 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-rules-engine.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-the-analyst-s-launch.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-the-optional-free-rpc-key.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-themes-and-keymaps.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-themes-and-look.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-widgets.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration-workspaces.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-configuration.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-1-follow-a-wallet-see-what-it-does.md +51 -0
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-2-the-one-key-mirror-ticket-a-proposal.md +56 -0
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-stage-3-capped-auto-mirror-default-off-less.md +47 -0
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading-what-is-proven-what-is-not.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-copy-trading.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-cache.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-health-registry.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-rate-limits-and-pacing.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-request-budget-meter.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-sources.md +47 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources-the-helius-credit-meter.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-data-sources.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-dexterm-doctor.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-first-run.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-install.md +81 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-next.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-requirements.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-running-the-tests.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-supported-platforms.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started-updating.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-getting-started.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-keyboard-global-keys.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-keyboard-keys-handled-by-the-loop.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-keyboard-per-screen-keys.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-keyboard-what-shows.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-keyboard.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-measured-accuracy.md +53 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-open-link-keys.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-paste-a-coin-on-the-web.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-the-verdict.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-timestamped-follow-up-drafts.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp-what-it-looks-at.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-larp.md +24 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-degraded-states-you-will-see.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-free-vs-paid-x-api-tiers-your-bill-your-limits.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-kol-lists-and-the-per-handle-filter.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-tests.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-what-is-read-and-when.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-what-you-set-up-once.md +40 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x-where-the-tokens-live.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-login-with-x.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-a-live-ticket.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-before-you-press-size-vs-caps.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-devnet-signer-mainnet-token.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-jupiter-rate-limits.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-letting-an-agent-paper-trade-experimental.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-link-a-wallet.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-live-trading-devnet-first.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-mainnet.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-order-plans-and-standing-mandates.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-panic.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-pnl-cards.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-live-fire-path-devnet-the-fast-wallet.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-signer-process.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-ticket.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-the-wallet.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-trade-moments.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-what-the-live-path-keeps.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading-your-first-live-trade.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-paper-trading.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-bubble-map-popup.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-build-the-native-window.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-config-dexterm-popup-json.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-docking-macos.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-keys-in-the-popup.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-market-cap-axis.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-security-model.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-token-and-feeds-popups.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart-what-it-shows.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-popup-chart.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-cost-control.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-keys-flag-command.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-safety-four-layers.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-states.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-the-read.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan-triggers-and-score.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scan.md +24 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-frozen-canary.md +30 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-frozen-task-1401-evaluation.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-latest-skill-care-run.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-links-only-larp-baseline-where-it-is-weak.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-not-measured.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-rug-verdict-rules.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard-source-and-rebuild.md +31 -0
- package/dist/packages/mcp/assets/kb/docs/docs-scorecard.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-1-screener.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-2-new-pairs.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-3-watchlist.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-4-analyst-tab.md +28 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-bubble-map.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-coin-images.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-dev-history.md +44 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-how-well-it-predicts-measured-held-out.md +46 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-live-holder-and-rug-signals.md +51 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-order-plans.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-paper-ticket-and-positions.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-the-look.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-token-screen.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens-trending-social-and-kol-lists.md +34 -0
- package/dist/packages/mcp/assets/kb/docs/docs-screens.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-1-the-agent-activity-window-follow-mode.md +56 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-2-the-read-only-stream-spectate.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-3-save-and-replay-record-file-dexterm-spectate.md +41 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-follow-over-mcp-in-the-running-terminal.md +39 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-limits.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-quick-start.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-security-model.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-see-also.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-streaming-it.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-the-three-surfaces.md +37 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator-what-is-redacted.md +35 -0
- package/dist/packages/mcp/assets/kb/docs/docs-spectator.md +29 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-common-questions.md +33 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-doctor-lines.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-in-app-messages.md +42 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting-reporting-a-problem.md +25 -0
- package/dist/packages/mcp/assets/kb/docs/docs-troubleshooting.md +23 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-doctor.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-it-clarifies-it-never-guesses.md +36 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-latency.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-linux-and-windows.md +32 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-privacy.md +26 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-still-unverified.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-the-voice-neural-by-default.md +48 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-what-it-can-never-do.md +27 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice-what-you-can-say.md +38 -0
- package/dist/packages/mcp/assets/kb/docs/docs-voice.md +25 -0
- package/dist/packages/mcp/src/app-help.js +123 -0
- package/dist/packages/mcp/src/firewall.js +2 -2
- package/dist/packages/mcp/src/index.js +8 -4
- package/dist/packages/mcp/src/paper-agent.js +92 -0
- package/dist/packages/mcp/src/server.js +261 -29
- package/dist/packages/mcp/src/spectator-sink.js +146 -5
- package/dist/packages/mcp/src/user-content.js +1 -0
- package/dist/packages/recorder/src/dev-history.js +129 -0
- package/dist/packages/recorder/src/index.js +1 -0
- package/dist/packages/recorder/src/recorder.js +23 -0
- package/dist/packages/recorder/src/schema.js +11 -0
- package/dist/packages/voice/src/stt/whisper.js +4 -2
- package/package.json +6 -5
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Local-only LARP/high-risk follow-up draft pipeline (task-1433). History mode reads the recorder
|
|
2
|
+
// without network access, scores only the point-in-time t0 row, joins only later outcome labels, and
|
|
3
|
+
// writes drafts/cards for human review. Live mode performs one read-only enrichment for one mint.
|
|
4
|
+
// Nothing here has X credentials, opens a composer, schedules work, trades, arms, signs or posts.
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join, resolve } from 'node:path';
|
|
7
|
+
import { createDataLayer, defaultDbPath } from '../../data/src/index.js';
|
|
8
|
+
import { openHistoryReadOnly, exportRecorded } from '../../recorder/src/index.js';
|
|
9
|
+
import { h1Model, rugFeaturesFromRecord, rugFeaturesFromToken } from '../../packs/src/index.js';
|
|
10
|
+
import { Canvas, THEMES } from '../../tui/src/index.js';
|
|
11
|
+
import { writeExport, fmtAge } from "./export.js";
|
|
12
|
+
export const LARP_DRAFT_MIN_SAMPLE = 50;
|
|
13
|
+
export const LARP_DRAFT_HORIZON = 259_200;
|
|
14
|
+
export const LARP_DRAFT_THRESHOLD = 0.5;
|
|
15
|
+
const isoMinute = (t) => new Date(t).toISOString().replace(/:\d\d\.\d{3}Z$/, 'Z');
|
|
16
|
+
const shortMint = (mint) => `${mint.slice(0, 4)}...${mint.slice(-4)}`;
|
|
17
|
+
const pct = (n, d) => `${d ? ((n / d) * 100).toFixed(1) : '0.0'}%`;
|
|
18
|
+
/** One point-in-time flag per mint: earliest flagged t0 with an observed outcome at this horizon. */
|
|
19
|
+
export function buildFollowUpDataset(records, horizonSec = LARP_DRAFT_HORIZON, threshold = LARP_DRAFT_THRESHOLD) {
|
|
20
|
+
const model = h1Model();
|
|
21
|
+
const byMint = new Map();
|
|
22
|
+
for (const r of records) {
|
|
23
|
+
const outcome = r.outcomes[`${horizonSec}`];
|
|
24
|
+
if (!outcome || byMint.has(r.mint))
|
|
25
|
+
continue;
|
|
26
|
+
const score = model.score(rugFeaturesFromRecord(r.features));
|
|
27
|
+
if (score < threshold)
|
|
28
|
+
continue;
|
|
29
|
+
byMint.set(r.mint, { mint: r.mint, t0: r.t0, score, model: model.id, outcome });
|
|
30
|
+
}
|
|
31
|
+
const flagged = [...byMint.values()];
|
|
32
|
+
const collapsed = flagged.filter((r) => r.outcome.positive);
|
|
33
|
+
return { horizonSec, threshold, flagged, collapsed, didNotCollapse: flagged.length - collapsed.length };
|
|
34
|
+
}
|
|
35
|
+
function outcomeText(o) {
|
|
36
|
+
if (o.label === 'rug')
|
|
37
|
+
return 'recorder label: liquidity-pull condition';
|
|
38
|
+
if (o.label === 'dead')
|
|
39
|
+
return 'recorder label: inactive at follow-up';
|
|
40
|
+
return `recorder label: ${o.label}`;
|
|
41
|
+
}
|
|
42
|
+
function datasetLine(d) {
|
|
43
|
+
return `Same-dataset follow-up: ${d.collapsed.length}/${d.flagged.length} met the condition (${pct(d.collapsed.length, d.flagged.length)}); ${d.didNotCollapse}/${d.flagged.length} did not.`;
|
|
44
|
+
}
|
|
45
|
+
function cardCanvas(row, d, now) {
|
|
46
|
+
const c = new Canvas(92, 25, THEMES.cyberspace);
|
|
47
|
+
const t = c.theme;
|
|
48
|
+
c.fill(0, 0, c.w, c.h, ' ', { bg: t.bg });
|
|
49
|
+
c.fill(0, 0, c.w, 3, ' ', { bg: t.headBg });
|
|
50
|
+
c.text(3, 1, 'LARP DETECTED · RECORDED FOLLOW-UP', { fg: t.warn, bg: t.headBg, b: true });
|
|
51
|
+
c.textR(0, 1, c.w - 3, shortMint(row.mint), { fg: t.muted, bg: t.headBg });
|
|
52
|
+
c.text(4, 5, 'AT THE RECORDED MOMENT', { fg: t.muted, b: true });
|
|
53
|
+
c.text(4, 7, `HIGH RISK ${Math.round(row.score * 100)}/100`, { fg: t.down, b: true });
|
|
54
|
+
c.text(4, 9, `${row.model} heuristic · model output · risk flag, not a certificate`, { fg: t.text });
|
|
55
|
+
c.text(4, 10, `${isoMinute(row.t0)} · local recorder · t0 evidence age ${fmtAge((now - row.t0) / 1000)}`, { fg: t.muted });
|
|
56
|
+
c.text(4, 13, 'LATER OBSERVED', { fg: t.muted, b: true });
|
|
57
|
+
c.text(4, 15, outcomeText(row.outcome).toUpperCase(), { fg: t.warn, b: true });
|
|
58
|
+
c.text(4, 17, `${fmtAge(d.horizonSec)} follow-up · ${row.outcome.tier} · labeler evidence`, { fg: t.text });
|
|
59
|
+
c.text(4, 20, datasetLine(d), { fg: t.muted }, c.w - 8);
|
|
60
|
+
c.text(4, 22, 'Sources: local dexterm recorder · DexScreener + Jupiter · draft only', { fg: t.muted }, c.w - 8);
|
|
61
|
+
c.text(4, 23, 'Not financial advice.', { fg: t.muted });
|
|
62
|
+
return c;
|
|
63
|
+
}
|
|
64
|
+
function historyDraft(row, d, now) {
|
|
65
|
+
return [
|
|
66
|
+
'LARP DETECTED — recorded follow-up',
|
|
67
|
+
'',
|
|
68
|
+
`Here is what the data showed: graded HIGH RISK ${Math.round(row.score * 100)}/100 at ${isoMinute(row.t0)} by ${row.model} (heuristic model output); ${outcomeText(row.outcome)} at the ${fmtAge(d.horizonSec)} follow-up.`,
|
|
69
|
+
'',
|
|
70
|
+
datasetLine(d),
|
|
71
|
+
'',
|
|
72
|
+
`Evidence: local dexterm recorder; DexScreener + Jupiter; t0 data age ${fmtAge((now - row.t0) / 1000)} at export; ${row.outcome.tier}; coin ${shortMint(row.mint)}.`,
|
|
73
|
+
'',
|
|
74
|
+
'A risk flag is not a certificate. Draft only; a human decides whether to post. Not financial advice.',
|
|
75
|
+
].join('\n') + '\n';
|
|
76
|
+
}
|
|
77
|
+
export function renderHistoryDrafts(d, opts) {
|
|
78
|
+
const now = opts.now ?? Date.now();
|
|
79
|
+
const min = opts.minSample ?? LARP_DRAFT_MIN_SAMPLE;
|
|
80
|
+
if (d.flagged.length < min)
|
|
81
|
+
return { drafts: [], cards: [] };
|
|
82
|
+
mkdirSync(opts.outDir, { recursive: true, mode: 0o700 });
|
|
83
|
+
const rows = [...d.collapsed].sort((a, b) => b.t0 - a.t0).slice(0, opts.limit ?? 3);
|
|
84
|
+
const drafts = [], cards = [];
|
|
85
|
+
for (let i = 0; i < rows.length; i++) {
|
|
86
|
+
const row = rows[i];
|
|
87
|
+
const stem = `${String(i + 1).padStart(2, '0')}-${row.mint.slice(0, 4)}-${row.mint.slice(-4)}`;
|
|
88
|
+
const draft = join(opts.outDir, `${stem}.md`);
|
|
89
|
+
writeFileSync(draft, historyDraft(row, d, now), { mode: 0o600 });
|
|
90
|
+
drafts.push(draft);
|
|
91
|
+
const view = {
|
|
92
|
+
kind: 'larp-detected', title: `RECORDED FOLLOW-UP · ${shortMint(row.mint)}`, label: 'replay', canvas: cardCanvas(row, d, now),
|
|
93
|
+
ages: [
|
|
94
|
+
{ name: 't0 evidence', source: 'local recorder · DexScreener + Jupiter', ageSec: (now - row.t0) / 1000 },
|
|
95
|
+
{ name: 'follow-up', source: `${row.outcome.tier} recorder outcome`, ageSec: d.horizonSec },
|
|
96
|
+
],
|
|
97
|
+
report: historyDraft(row, d, now).trimEnd().split('\n'),
|
|
98
|
+
};
|
|
99
|
+
const saved = writeExport(view, { dir: opts.outDir, now: now + i, subject: stem });
|
|
100
|
+
cards.push(saved.png);
|
|
101
|
+
}
|
|
102
|
+
return { drafts, cards };
|
|
103
|
+
}
|
|
104
|
+
function parse(argv) {
|
|
105
|
+
const out = {};
|
|
106
|
+
for (let i = 0; i < argv.length; i++) {
|
|
107
|
+
const a = argv[i];
|
|
108
|
+
if (!a.startsWith('--'))
|
|
109
|
+
continue;
|
|
110
|
+
const value = argv[i + 1];
|
|
111
|
+
if (value !== undefined && !value.startsWith('--')) {
|
|
112
|
+
out[a.slice(2)] = value;
|
|
113
|
+
i++;
|
|
114
|
+
}
|
|
115
|
+
else
|
|
116
|
+
out[a.slice(2)] = true;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
export const LARP_DETECTED_HELP = `dexterm larp-detected: local draft/card pipeline; never posts or schedules
|
|
121
|
+
|
|
122
|
+
dexterm larp-detected --out DIR [--db PATH] [--horizon SEC] [--limit 3]
|
|
123
|
+
dexterm larp-detected --live MINT --out DIR
|
|
124
|
+
|
|
125
|
+
History mode is cron-ready and offline: it reads recorder t0 rows plus later labels, requires at least
|
|
126
|
+
${LARP_DRAFT_MIN_SAMPLE} unique flagged coins, and otherwise writes no drafts. Live mode performs one read-only
|
|
127
|
+
keyless lookup and writes a graded-now card. All output is for human review.`;
|
|
128
|
+
function liveFeatures(row) {
|
|
129
|
+
return rugFeaturesFromToken({
|
|
130
|
+
liquidity_usd: row.pair.liquidityUsd, mcap: row.mcap?.value ?? row.pair.mcap, age_sec: row.token.createdAt === null ? null : Math.max(0, (Date.now() - row.token.createdAt) / 1000),
|
|
131
|
+
top10_pct: row.audit?.top10Pct ?? null, dev_pct: row.audit?.devPct ?? null, organic_score: row.stats?.organicScore ?? null,
|
|
132
|
+
holder_count: row.stats?.holderCount ?? null, mint_authority: row.audit?.mintAuthority ?? null, freeze_authority: row.audit?.freezeAuthority ?? null,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
async function liveCard(mint, outDir, dbPath, io) {
|
|
136
|
+
if (!/^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(mint)) {
|
|
137
|
+
io.stderr.write('dexterm larp-detected: --live needs a Solana mint\n');
|
|
138
|
+
return 2;
|
|
139
|
+
}
|
|
140
|
+
const dl = createDataLayer({ dbPath });
|
|
141
|
+
try {
|
|
142
|
+
const result = await dl.store.enrich([mint]);
|
|
143
|
+
const row = result.rows[0];
|
|
144
|
+
if (!row) {
|
|
145
|
+
io.stderr.write('dexterm larp-detected: no current market record found for that mint\n');
|
|
146
|
+
return 2;
|
|
147
|
+
}
|
|
148
|
+
const now = Date.now(), model = h1Model(), score = model.score(liveFeatures(row));
|
|
149
|
+
const c = new Canvas(92, 20, THEMES.cyberspace), t = c.theme;
|
|
150
|
+
c.fill(0, 0, c.w, c.h, ' ', { bg: t.bg });
|
|
151
|
+
c.fill(0, 0, c.w, 3, ' ', { bg: t.headBg });
|
|
152
|
+
c.text(3, 1, 'LARP CHECK · GRADED NOW', { fg: t.warn, bg: t.headBg, b: true });
|
|
153
|
+
c.textR(0, 1, c.w - 3, shortMint(mint), { fg: t.muted, bg: t.headBg });
|
|
154
|
+
c.text(4, 6, `${score >= LARP_DRAFT_THRESHOLD ? 'HIGH RISK' : 'BELOW HIGH-RISK LINE'} ${Math.round(score * 100)}/100`, { fg: score >= LARP_DRAFT_THRESHOLD ? t.down : t.up, b: true });
|
|
155
|
+
c.text(4, 9, `${model.id} heuristic · model output · risk flag, not a certificate`, { fg: t.text });
|
|
156
|
+
c.text(4, 11, `${isoMinute(now)} · LIVE DATA · DexScreener + Jupiter`, { fg: t.muted });
|
|
157
|
+
c.text(4, 14, 'No later outcome yet. No person, project or wallet is identified.', { fg: t.text });
|
|
158
|
+
c.text(4, 17, 'Draft only · human review · not financial advice', { fg: t.muted });
|
|
159
|
+
const view = { kind: 'larp-now', title: `GRADED NOW · ${shortMint(mint)}`, label: 'live', canvas: c,
|
|
160
|
+
ages: [{ name: 'market', source: 'DexScreener + Jupiter', ageSec: Math.max(0, (now - Math.max(row.token.fetchedAt, row.pair.fetchedAt)) / 1000) }],
|
|
161
|
+
report: [`coin ${shortMint(mint)}`, `graded now ${Math.round(score * 100)}/100 · ${model.id} heuristic model output`, 'No later outcome yet. Risk flag, not a certificate. Draft only.'],
|
|
162
|
+
};
|
|
163
|
+
const saved = writeExport(view, { dir: outDir, now, subject: `${mint.slice(0, 4)}-${mint.slice(-4)}` });
|
|
164
|
+
io.stdout.write(`graded-now card: ${saved.png}\n`);
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
finally {
|
|
168
|
+
dl.close();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
export async function larpDetectedCommand(argv, io) {
|
|
172
|
+
const o = parse(argv);
|
|
173
|
+
if (o.help || o.h) {
|
|
174
|
+
io.stdout.write(LARP_DETECTED_HELP + '\n');
|
|
175
|
+
return 0;
|
|
176
|
+
}
|
|
177
|
+
const dbPath = typeof o.db === 'string' ? resolve(o.db) : (io.env.DEXTERM_DB_PATH || defaultDbPath(io.env));
|
|
178
|
+
const outDir = typeof o.out === 'string' ? resolve(o.out) : resolve('marketing', 'larp-detected', new Date().toISOString().slice(0, 10));
|
|
179
|
+
if (typeof o.live === 'string')
|
|
180
|
+
return liveCard(o.live, outDir, dbPath, io);
|
|
181
|
+
if (!existsSync(dbPath)) {
|
|
182
|
+
io.stderr.write(`dexterm larp-detected: no recorder history at ${dbPath}\n`);
|
|
183
|
+
return 2;
|
|
184
|
+
}
|
|
185
|
+
const horizon = typeof o.horizon === 'string' ? Number(o.horizon) : LARP_DRAFT_HORIZON;
|
|
186
|
+
if (!Number.isFinite(horizon) || horizon <= 0) {
|
|
187
|
+
io.stderr.write('dexterm larp-detected: --horizon must be positive seconds\n');
|
|
188
|
+
return 2;
|
|
189
|
+
}
|
|
190
|
+
const db = openHistoryReadOnly(dbPath);
|
|
191
|
+
if (!db) {
|
|
192
|
+
io.stderr.write('dexterm larp-detected: recorder database could not be opened read-only\n');
|
|
193
|
+
return 2;
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
const dataset = buildFollowUpDataset(exportRecorded(db, { labelledOnly: true }).records, horizon);
|
|
197
|
+
if (dataset.flagged.length < LARP_DRAFT_MIN_SAMPLE) {
|
|
198
|
+
io.stdout.write(`thin sample: ${dataset.flagged.length} unique flagged coins (< ${LARP_DRAFT_MIN_SAMPLE}); wrote no drafts\n`);
|
|
199
|
+
return 0;
|
|
200
|
+
}
|
|
201
|
+
const limit = typeof o.limit === 'string' ? Math.max(0, Math.floor(Number(o.limit))) : 3;
|
|
202
|
+
const saved = renderHistoryDrafts(dataset, { outDir, limit: Number.isFinite(limit) ? limit : 3 });
|
|
203
|
+
io.stdout.write(`${datasetLine(dataset)}\nwrote ${saved.drafts.length} draft(s) and ${saved.cards.length} card(s) to ${outDir}\n`);
|
|
204
|
+
return 0;
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
db.close();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { creatorOf, devHistoryLine, queryDevHistory } from '../../../recorder/src/index.js';
|
|
2
|
+
export const DEV_TTL_MS = 60_000;
|
|
3
|
+
/** Short creator/funder address for the panel (never a full address in a 40-column cell). */
|
|
4
|
+
export const shortAddr = (a) => (a ? `${a.slice(0, 4)}…${a.slice(-4)}` : '—');
|
|
5
|
+
export class DevHistoryBook {
|
|
6
|
+
cache = new Map();
|
|
7
|
+
db;
|
|
8
|
+
now;
|
|
9
|
+
ttlMs;
|
|
10
|
+
constructor(db, now = () => Date.now(), ttlMs = DEV_TTL_MS) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
this.now = now;
|
|
13
|
+
this.ttlMs = ttlMs;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The entry for `mint` (cached for `ttlMs`). `creatorHint` is the dev wallet a source named on screen (Jupiter
|
|
17
|
+
* `dev`) for a coin the recorder has not linked yet; `intel` is the coin's settled wallet-intel scan, if any.
|
|
18
|
+
*/
|
|
19
|
+
forMint(mint, creatorHint, intel) {
|
|
20
|
+
const now = this.now();
|
|
21
|
+
const hit = this.cache.get(mint);
|
|
22
|
+
if (hit && now - hit.at < this.ttlMs && (hit.creator || !creatorHint) && (hit.linked || !intel))
|
|
23
|
+
return hit;
|
|
24
|
+
const db = this.db() ?? null;
|
|
25
|
+
let creator = db ? creatorOf(db, mint) : null;
|
|
26
|
+
if (!creator && creatorHint && /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(creatorHint))
|
|
27
|
+
creator = { mint, creator: creatorHint, source: 'jupiter-tokens', firstT: now, createdAt: null };
|
|
28
|
+
let report = null;
|
|
29
|
+
let linked = null;
|
|
30
|
+
if (creator && db) {
|
|
31
|
+
try {
|
|
32
|
+
report = queryDevHistory(db, { creator: creator.creator, mint, asOf: now });
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
report = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (creator && intel)
|
|
39
|
+
linked = linkedFrom(intel, creator.creator, db);
|
|
40
|
+
const line = !db ? 'unknown: the history recorder is off (--no-recorder / DEXTERM_RECORDER=0)'
|
|
41
|
+
: !creator ? 'unknown: no source named the creator yet'
|
|
42
|
+
: report ? devHistoryLine(report) : 'unknown: dev history unreadable';
|
|
43
|
+
const e = { mint, creator, report, linked, line, at: now };
|
|
44
|
+
this.cache.set(mint, e);
|
|
45
|
+
if (this.cache.size > 2000)
|
|
46
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
47
|
+
return e;
|
|
48
|
+
}
|
|
49
|
+
/** The `devrugs` rule field: labelled prior rugs by this coin's creator; null = unknown (clauses on it are false). */
|
|
50
|
+
rugsFor(mint) {
|
|
51
|
+
const e = this.forMint(mint);
|
|
52
|
+
return e.report && e.report.labelled.n > 0 ? e.report.labelled.rug : null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Linked wallets from a settled wallet-intel scan: the creator's funder and any multi-wallet cluster it sits in. */
|
|
56
|
+
export function linkedFrom(a, creator, db) {
|
|
57
|
+
const h = a.holders.find((x) => x.owner === creator);
|
|
58
|
+
const fundedBy = h?.funder?.address ?? a.funding[creator]?.funder ?? null;
|
|
59
|
+
const c = a.clusters.find((x) => x.members.includes(creator) && x.members.length > 1) ?? null;
|
|
60
|
+
let linkedCreators = 0, linkedRugs = 0;
|
|
61
|
+
if (c && db) {
|
|
62
|
+
try {
|
|
63
|
+
const others = c.members.filter((m) => m !== creator).slice(0, 50);
|
|
64
|
+
const launched = db.prepare('SELECT COUNT(*) AS n FROM creators WHERE creator = ?');
|
|
65
|
+
for (const w of others) {
|
|
66
|
+
if (Number(launched.get(w).n) <= 0)
|
|
67
|
+
continue;
|
|
68
|
+
linkedCreators++;
|
|
69
|
+
linkedRugs += queryDevHistory(db, { creator: w, devExit: false }).labelled.rug;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch { /* an old DB without the table: nothing linked */ }
|
|
73
|
+
}
|
|
74
|
+
return { fundedBy, cluster: c ? { name: c.name, kind: c.kind, members: c.members.length, pct: c.pct } : null, linkedCreators, linkedRugs, source: h || c || a.funding[creator] ? 'wallet-intel scan' : null };
|
|
75
|
+
}
|
|
76
|
+
/** Rows for the token screen's DEV block: [label, value, level]. Every value names its source/sample/age or says unknown. */
|
|
77
|
+
export function devRows(e) {
|
|
78
|
+
const rows = [];
|
|
79
|
+
const r = e.report;
|
|
80
|
+
const rugLevel = () => !r || r.labelled.n === 0 ? 'na' : r.serialRugger ? 'bad' : r.labelled.rug > 0 || (r.badRate ?? 0) >= 0.5 ? 'warn' : 'ok';
|
|
81
|
+
rows.push(['Dev rugs (recorded)', r && r.labelled.n ? `${r.labelled.rug}/${r.labelled.n} · n=${r.labelled.n}` : 'unknown', rugLevel()]);
|
|
82
|
+
rows.push(['Dev launches seen', r && r.status === 'ok' ? `${r.launches.n} prior · ${e.creator?.source === 'jupiter-tokens' ? 'jup' : e.creator?.source ?? ''}` : 'unknown', 'na']);
|
|
83
|
+
if (r && r.devExit.n)
|
|
84
|
+
rows.push(['Dev sold its bag', `median ${Math.round(r.devExit.medianMin)}m · n=${r.devExit.n}`, r.devExit.medianMin <= 60 ? 'warn' : 'ok']);
|
|
85
|
+
const l = e.linked;
|
|
86
|
+
if (l && (l.fundedBy || l.cluster))
|
|
87
|
+
rows.push(['Dev linked', l.cluster ? `${l.cluster.kind} ${l.cluster.members}w${l.linkedCreators ? ` · ${l.linkedCreators} devs ${l.linkedRugs} rugs` : ''}` : `funded by ${shortAddr(l.fundedBy)}`, l.linkedRugs > 0 ? 'bad' : 'na']);
|
|
88
|
+
return rows;
|
|
89
|
+
}
|
|
90
|
+
/** The app's one book (created on first use), reading the live recorder's DB. Null when there is no recorder. */
|
|
91
|
+
export function devBookOf(state) {
|
|
92
|
+
if (!state.live?.recorder)
|
|
93
|
+
return null;
|
|
94
|
+
if (!state.devBook) {
|
|
95
|
+
const live = state.live;
|
|
96
|
+
state.devBook = new DevHistoryBook(() => live?.recorder?.database ?? null);
|
|
97
|
+
}
|
|
98
|
+
return state.devBook;
|
|
99
|
+
}
|
|
@@ -20,6 +20,8 @@ export class NewPairsLive {
|
|
|
20
20
|
dl;
|
|
21
21
|
now;
|
|
22
22
|
onChange;
|
|
23
|
+
/** 0.1.5 dev history: called once per row when its creator becomes known (the recorder stores the link). */
|
|
24
|
+
onCreator;
|
|
23
25
|
limit;
|
|
24
26
|
polls;
|
|
25
27
|
rows = new Map();
|
|
@@ -84,6 +86,12 @@ export class NewPairsLive {
|
|
|
84
86
|
this.mode = 'replay';
|
|
85
87
|
return this.client.replay(rec, speed);
|
|
86
88
|
}
|
|
89
|
+
tellCreator(mint, creator, source, createdAt) {
|
|
90
|
+
try {
|
|
91
|
+
this.onCreator?.(mint, creator, source, createdAt);
|
|
92
|
+
}
|
|
93
|
+
catch { /* the recorder must never break the feed */ }
|
|
94
|
+
}
|
|
87
95
|
addCreate(c) {
|
|
88
96
|
const rowAt = this.now();
|
|
89
97
|
const existing = this.rows.get(c.mint);
|
|
@@ -105,6 +113,8 @@ export class NewPairsLive {
|
|
|
105
113
|
}
|
|
106
114
|
else {
|
|
107
115
|
this.rows.set(c.mint, row);
|
|
116
|
+
if (row.creator)
|
|
117
|
+
this.tellCreator(c.mint, row.creator, c.creator ? 'pumpportal' : 'rugcheck', row.createdAt);
|
|
108
118
|
this.latencies.push(row.latencyMs);
|
|
109
119
|
if (this.latencies.length > 500)
|
|
110
120
|
this.latencies.shift();
|
|
@@ -227,6 +237,8 @@ export class NewPairsLive {
|
|
|
227
237
|
const row = this.rows.get(t.mint);
|
|
228
238
|
if (!row)
|
|
229
239
|
continue;
|
|
240
|
+
if (!row.creator && t.creator)
|
|
241
|
+
this.tellCreator(t.mint, t.creator, 'rugcheck', row.createdAt);
|
|
230
242
|
row.creator = row.creator ?? t.creator;
|
|
231
243
|
if (t.mintAuthority !== null)
|
|
232
244
|
row.mintAuth = t.mintAuthority;
|
|
@@ -15,6 +15,7 @@ import { drawCoin, imagesOn } from "../../screens/coin.js";
|
|
|
15
15
|
import { COIN_HERO_W, COIN_HERO_H } from '../../../../tui/src/index.js';
|
|
16
16
|
import { renderSocialPanel } from "../../screens/social-panel.js";
|
|
17
17
|
import { launchIntelCells, holderTags } from "../intel.js";
|
|
18
|
+
import { devBookOf, devRows } from "../dev-history.js";
|
|
18
19
|
import { EX_POOL_TAGS } from '../../../../data/src/index.js';
|
|
19
20
|
import { layoutFor } from "../../custom.js";
|
|
20
21
|
import { chartMode, priceModeOf, mcapAt, positionPriceCells } from "../../display.js";
|
|
@@ -178,6 +179,12 @@ export function renderTokenLive(c, state, v) {
|
|
|
178
179
|
const top10Rows = tags.top10
|
|
179
180
|
? [['Top 10 ex-pool', `${tags.top10.exPool.toFixed(1)}%`, t10lvl(tags.top10.exPool)], ['Top 10 raw', `${tags.top10.raw.toFixed(1)}%`, 'na']]
|
|
180
181
|
: [['Top 10 holders', ...(v.top10 === null ? na(v.panels.holders.state === 'needs-key' ? 'needs key' : dash) : [`${v.top10.toFixed(1)}%${v.panels.holders.state === 'ok' ? '' : ' (jup)'}`, t10lvl(v.top10)])]];
|
|
182
|
+
// 0.1.5 dev history (task-1425): the creator's recorded track record from the local recorder (keyless). The rugs
|
|
183
|
+
// row sits with the other rug signals; launches / bag-exit / linked wallets follow the safety list.
|
|
184
|
+
const book = devBookOf(state);
|
|
185
|
+
const devAll = book ? devRows(book.forMint(v.mint, v.devAddress ?? null, state.live?.intel?.analysis(v.mint) ?? null)) : [];
|
|
186
|
+
const devHead = devAll.slice(0, 1);
|
|
187
|
+
const devTail = devAll.slice(1);
|
|
181
188
|
const sniperRow = [cells.snipers.text, cells.snipers.level];
|
|
182
189
|
const bundleRow = [cells.bundle.text, cells.bundle.level];
|
|
183
190
|
const rows = [
|
|
@@ -189,8 +196,10 @@ export function renderTokenLive(c, state, v) {
|
|
|
189
196
|
['Mint authority', ...(v.mintAuth === null ? na(dash) : [v.mintAuth ? 'ENABLED' : 'revoked', v.mintAuth ? 'bad' : 'ok'])],
|
|
190
197
|
['Freeze authority', ...(v.freezeAuth === null ? na(dash) : [v.freezeAuth ? 'ENABLED' : 'revoked', v.freezeAuth ? 'bad' : 'ok'])],
|
|
191
198
|
['Dev history', ...(v.devMints === null ? needsHistory : [`${v.devMints} mints by dev (jup)`, v.devMints > 3 ? 'warn' : 'ok'])],
|
|
199
|
+
...devHead,
|
|
192
200
|
['RugCheck score', ...(v.rug === null || v.rug.score === null ? na(v.panels.rugcheck.state === 'error' ? `unavailable: ${v.panels.rugcheck.reason ?? ''}`.trim() : dash) : [`${Math.round(v.rug.score)}/100`, v.rug.score < 30 ? 'ok' : v.rug.score < 60 ? 'warn' : 'bad'])],
|
|
193
201
|
['GoPlus', ...goplusRow(v)],
|
|
202
|
+
...devTail,
|
|
194
203
|
];
|
|
195
204
|
for (const [label, val0, lvl] of rows) {
|
|
196
205
|
if (sy >= sb.y + sb.h)
|
|
@@ -435,7 +444,8 @@ function analystPlaceholder(c, x, y, w, h, v, state) {
|
|
|
435
444
|
// task-1311 (QA M5): the pre-run state. Opening a token no longer spends a paid dossier; this panel
|
|
436
445
|
// waits until you ask for one with `a` (dossier) or type a question with `i`. No fake verdicts.
|
|
437
446
|
const t = c.theme;
|
|
438
|
-
const
|
|
447
|
+
const eng = state.analystEngine ?? 'claude'; // 0.1.5: the user's own CLI that will answer
|
|
448
|
+
const box = c.box(x, y, w, h, { title: `✦ ANALYST · ${eng}`, titleFg: t.ai, caption: `read-only · local ${eng} · on demand`, captionFg: t.dim, border: mix(t.border, t.ai, 0.35) });
|
|
439
449
|
const bg = box.bg;
|
|
440
450
|
const inner = box.w - 2;
|
|
441
451
|
let cy = box.y;
|
|
@@ -266,6 +266,7 @@ export class TokenLive {
|
|
|
266
266
|
v.top10 = audit?.top10Pct ?? v.top10;
|
|
267
267
|
v.dev = audit?.devPct ?? null;
|
|
268
268
|
v.devMints = audit?.devMints ?? null;
|
|
269
|
+
v.devAddress = audit?.devAddress ?? v.devAddress ?? null;
|
|
269
270
|
v.sources = [...new Set([...v.sources, ...r.sources])];
|
|
270
271
|
const SHORT = { dexscreener: 'ds', 'jupiter-tokens': 'jup', 'jupiter-price': 'jup-price' };
|
|
271
272
|
this.ok('market', r.sources.map((x) => SHORT[x] ?? x).join('+'), pair.fetchedAt, r.stale);
|
|
@@ -473,6 +474,9 @@ export class CandlePrefetcher {
|
|
|
473
474
|
timer = null;
|
|
474
475
|
busy = false;
|
|
475
476
|
closed = false;
|
|
477
|
+
settledPromise = Promise.resolve();
|
|
478
|
+
resolveSettled = null;
|
|
479
|
+
waitingForSettled = false;
|
|
476
480
|
stamps = [];
|
|
477
481
|
/** Requests actually sent (granted by the limiter). */
|
|
478
482
|
requests = 0;
|
|
@@ -494,9 +498,25 @@ export class CandlePrefetcher {
|
|
|
494
498
|
return;
|
|
495
499
|
if (t && this.target && t.mint === this.target.mint && t.pair === this.target.pair)
|
|
496
500
|
return; // same row: keep waiting
|
|
501
|
+
this.finishSettled(); // a replaced target can no longer do useful work for its caller
|
|
497
502
|
this.target = t;
|
|
503
|
+
if (t?.pair)
|
|
504
|
+
this.settledPromise = new Promise((resolve) => { this.resolveSettled = resolve; });
|
|
498
505
|
this.schedule(this.opts.debounceMs);
|
|
499
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Resolve after the current hover pass has warmed every immediately available base, explicitly
|
|
509
|
+
* deferred the next attempt, failed a real request, been replaced, or been cancelled by close(). This
|
|
510
|
+
* is the completion contract for callers that need to observe the pass result; a debounce timer firing
|
|
511
|
+
* alone does not mean its sequential requests have finished.
|
|
512
|
+
*/
|
|
513
|
+
settled() {
|
|
514
|
+
if (this.resolveSettled) {
|
|
515
|
+
this.waitingForSettled = true;
|
|
516
|
+
this.timer?.ref?.();
|
|
517
|
+
}
|
|
518
|
+
return this.settledPromise;
|
|
519
|
+
}
|
|
500
520
|
/** Requests sent in the trailing 60 s. */
|
|
501
521
|
rate() {
|
|
502
522
|
const now = this.opts.now();
|
|
@@ -511,6 +531,7 @@ export class CandlePrefetcher {
|
|
|
511
531
|
clearTimeout(this.timer);
|
|
512
532
|
this.timer = null;
|
|
513
533
|
}
|
|
534
|
+
this.finishSettled();
|
|
514
535
|
}
|
|
515
536
|
schedule(ms) {
|
|
516
537
|
if (this.timer) {
|
|
@@ -521,7 +542,10 @@ export class CandlePrefetcher {
|
|
|
521
542
|
if (!t || !t.pair || this.closed)
|
|
522
543
|
return;
|
|
523
544
|
this.timer = setTimeout(() => { this.timer = null; void this.step(t); }, Math.max(0, ms));
|
|
524
|
-
this.
|
|
545
|
+
if (this.waitingForSettled)
|
|
546
|
+
this.timer.ref?.();
|
|
547
|
+
else
|
|
548
|
+
this.timer.unref?.();
|
|
525
549
|
}
|
|
526
550
|
bases() {
|
|
527
551
|
const iv = this.opts.interval();
|
|
@@ -541,6 +565,7 @@ export class CandlePrefetcher {
|
|
|
541
565
|
continue;
|
|
542
566
|
if (this.rate() >= this.opts.maxPerMin) {
|
|
543
567
|
this.schedule(this.stamps[0] + 60_000 - this.opts.now() + 50);
|
|
568
|
+
this.finishSettled(t);
|
|
544
569
|
return;
|
|
545
570
|
}
|
|
546
571
|
this.busy = true;
|
|
@@ -554,9 +579,11 @@ export class CandlePrefetcher {
|
|
|
554
579
|
// Try again when the bucket could be idle again (still only if the cursor stays here).
|
|
555
580
|
const wait = this.dl.limiter.bucket('geckoterminal').delayFor('idle', this.opts.now());
|
|
556
581
|
this.schedule(Number.isFinite(wait) ? Math.max(250, wait) : 60_000);
|
|
582
|
+
this.finishSettled(t);
|
|
557
583
|
return;
|
|
558
584
|
}
|
|
559
585
|
this.sent(); // a real request that failed (HTTP error) still counts against the budget
|
|
586
|
+
this.finishSettled(t);
|
|
560
587
|
return;
|
|
561
588
|
}
|
|
562
589
|
finally {
|
|
@@ -565,6 +592,17 @@ export class CandlePrefetcher {
|
|
|
565
592
|
if (this.closed || this.target !== t)
|
|
566
593
|
return; // the cursor moved on: its own debounce takes over
|
|
567
594
|
}
|
|
595
|
+
this.finishSettled(t);
|
|
596
|
+
}
|
|
597
|
+
finishSettled(t) {
|
|
598
|
+
if (t && this.target !== t)
|
|
599
|
+
return;
|
|
600
|
+
const resolve = this.resolveSettled;
|
|
601
|
+
this.resolveSettled = null;
|
|
602
|
+
if (this.waitingForSettled)
|
|
603
|
+
this.timer?.unref?.();
|
|
604
|
+
this.waitingForSettled = false;
|
|
605
|
+
resolve?.();
|
|
568
606
|
}
|
|
569
607
|
sent() {
|
|
570
608
|
this.requests++;
|