repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import { ClawdPerpsRuntime } from "./marketMaker.js"; |
| #2 | import { buildPerpsFrontendStatus } from "./frontend.js"; |
| #3 | |
| #4 | export interface TelegramPerpsCommand { |
| #5 | command: string; |
| #6 | description: string; |
| #7 | } |
| #8 | |
| #9 | export interface TelegramPerpsResponse { |
| #10 | ok: boolean; |
| #11 | text: string; |
| #12 | data?: unknown; |
| #13 | } |
| #14 | |
| #15 | export const TELEGRAM_PERPS_COMMANDS: TelegramPerpsCommand[] = [ |
| #16 | { command: "/perps", description: "Show runtime status and safety mode" }, |
| #17 | { command: "/perps_vulcan", description: "Show integrated Vulcan CLI and MCP status" }, |
| #18 | { command: "/perps_markets", description: "List tracked Phoenix perp markets" }, |
| #19 | { command: "/perps_positions", description: "Show current perp positions" }, |
| #20 | { command: "/perps_paper_long", description: "Preview a paper long route" }, |
| #21 | { command: "/perps_paper_short", description: "Preview a paper short route" }, |
| #22 | { command: "/perps_live_long", description: "Preview a blocked/allowed live long route" }, |
| #23 | { command: "/perps_live_short", description: "Preview a blocked/allowed live short route" }, |
| #24 | ]; |
| #25 | |
| #26 | function parseArgs(text: string): string[] { |
| #27 | return text |
| #28 | .trim() |
| #29 | .split(/\s+/) |
| #30 | .filter(Boolean); |
| #31 | } |
| #32 | |
| #33 | function readSymbol(args: string[], fallback = "SOL"): string { |
| #34 | return (args[1] ?? fallback).toUpperCase(); |
| #35 | } |
| #36 | |
| #37 | function readNotional(args: string[], fallback = 100): number { |
| #38 | const value = Number(args[2] ?? fallback); |
| #39 | return Number.isFinite(value) && value > 0 ? value : fallback; |
| #40 | } |
| #41 | |
| #42 | function joinLines(lines: string[]): string { |
| #43 | return lines.filter(Boolean).join("\n"); |
| #44 | } |
| #45 | |
| #46 | function formatBlocking(blocking: string[]): string { |
| #47 | return blocking.length > 0 ? blocking.join(" | ") : "no blocking conditions"; |
| #48 | } |
| #49 | |
| #50 | export async function handleTelegramPerpsCommand( |
| #51 | runtime: ClawdPerpsRuntime, |
| #52 | text: string, |
| #53 | ): Promise<TelegramPerpsResponse> { |
| #54 | const args = parseArgs(text); |
| #55 | const command = args[0] ?? "/perps"; |
| #56 | |
| #57 | switch (command) { |
| #58 | case "/perps": { |
| #59 | const [status, frontend] = await Promise.all([ |
| #60 | runtime.getRuntimeHealth(), |
| #61 | buildPerpsFrontendStatus(runtime), |
| #62 | ]); |
| #63 | return { |
| #64 | ok: true, |
| #65 | text: joinLines([ |
| #66 | `${frontend.modeLabel} | ${status.trackedMarkets} markets in view`, |
| #67 | frontend.headline, |
| #68 | frontend.subheadline, |
| #69 | `wallet=${status.walletConfigured ? "wired" : "missing"} | symbols=${status.allowedSymbols.join(", ")}`, |
| #70 | ]), |
| #71 | data: { ...status, frontend }, |
| #72 | }; |
| #73 | } |
| #74 | case "/perps_vulcan": { |
| #75 | const catalog = await runtime.getVulcanCatalogSummary(); |
| #76 | return { |
| #77 | ok: true, |
| #78 | text: joinLines([ |
| #79 | "Vulcan bridge is mounted and readable.", |
| #80 | `cli=${catalog.cliVersion} | groups=${catalog.groupCount} | commands=${catalog.commandCount}`, |
| #81 | `dangerous routes=${catalog.dangerousCommands} | MCP=${catalog.mcpServer ? "present" : "missing"}`, |
| #82 | ]), |
| #83 | data: catalog, |
| #84 | }; |
| #85 | } |
| #86 | case "/perps_markets": { |
| #87 | const markets = await runtime.listMarkets(); |
| #88 | return { |
| #89 | ok: true, |
| #90 | text: joinLines([ |
| #91 | "Market tape is live.", |
| #92 | `${markets.length} tracked symbols: ${markets.map((market) => market.symbol).join(", ")}`, |
| #93 | ]), |
| #94 | data: markets, |
| #95 | }; |
| #96 | } |
| #97 | case "/perps_positions": { |
| #98 | const positions = await runtime.getPositions(); |
| #99 | return { |
| #100 | ok: true, |
| #101 | text: joinLines([ |
| #102 | "Current position snapshot loaded.", |
| #103 | Array.isArray(positions) && positions.length > 0 |
| #104 | ? `${positions.length} position rows returned from the read plane.` |
| #105 | : "No active position rows returned.", |
| #106 | ]), |
| #107 | data: positions, |
| #108 | }; |
| #109 | } |
| #110 | case "/perps_paper_long": { |
| #111 | const preview = runtime.previewPaperTrade(readSymbol(args), "buy", readNotional(args)); |
| #112 | return { |
| #113 | ok: preview.preflight.ok, |
| #114 | text: preview.preflight.ok |
| #115 | ? joinLines([ |
| #116 | `Paper long route staged for ${preview.symbol}.`, |
| #117 | `${preview.notionalUsd} USDC notional | adapter=${preview.route.adapter} | execution=${preview.execution}`, |
| #118 | "This is rehearsal flow only. No real funds should move.", |
| #119 | ]) |
| #120 | : joinLines([ |
| #121 | `Paper long route blocked for ${preview.symbol}.`, |
| #122 | formatBlocking(preview.preflight.blocking), |
| #123 | ]), |
| #124 | data: preview, |
| #125 | }; |
| #126 | } |
| #127 | case "/perps_paper_short": { |
| #128 | const preview = runtime.previewPaperTrade(readSymbol(args), "sell", readNotional(args)); |
| #129 | return { |
| #130 | ok: preview.preflight.ok, |
| #131 | text: preview.preflight.ok |
| #132 | ? joinLines([ |
| #133 | `Paper short route staged for ${preview.symbol}.`, |
| #134 | `${preview.notionalUsd} USDC notional | adapter=${preview.route.adapter} | execution=${preview.execution}`, |
| #135 | "The engine can rehearse the move without opening live exposure.", |
| #136 | ]) |
| #137 | : joinLines([ |
| #138 | `Paper short route blocked for ${preview.symbol}.`, |
| #139 | formatBlocking(preview.preflight.blocking), |
| #140 | ]), |
| #141 | data: preview, |
| #142 | }; |
| #143 | } |
| #144 | case "/perps_live_long": { |
| #145 | const preview = runtime.previewLiveTrade(readSymbol(args), "buy", readNotional(args)); |
| #146 | return { |
| #147 | ok: preview.preflight.ok, |
| #148 | text: preview.preflight.ok |
| #149 | ? joinLines([ |
| #150 | `Live long preview is open for ${preview.symbol}.`, |
| #151 | `${preview.notionalUsd} USDC notional cleared the current gate set.`, |
| #152 | "This is still a preview path until signing and submission are wired.", |
| #153 | ]) |
| #154 | : joinLines([ |
| #155 | `Live long remains blocked for ${preview.symbol}.`, |
| #156 | formatBlocking(preview.preflight.blocking), |
| #157 | ]), |
| #158 | data: preview, |
| #159 | }; |
| #160 | } |
| #161 | case "/perps_live_short": { |
| #162 | const preview = runtime.previewLiveTrade(readSymbol(args), "sell", readNotional(args)); |
| #163 | return { |
| #164 | ok: preview.preflight.ok, |
| #165 | text: preview.preflight.ok |
| #166 | ? joinLines([ |
| #167 | `Live short preview is open for ${preview.symbol}.`, |
| #168 | `${preview.notionalUsd} USDC notional cleared the current gate set.`, |
| #169 | "Execution is described here, not blindly triggered here.", |
| #170 | ]) |
| #171 | : joinLines([ |
| #172 | `Live short remains blocked for ${preview.symbol}.`, |
| #173 | formatBlocking(preview.preflight.blocking), |
| #174 | ]), |
| #175 | data: preview, |
| #176 | }; |
| #177 | } |
| #178 | default: |
| #179 | return { |
| #180 | ok: false, |
| #181 | text: `Unknown command ${command}. Supported: ${TELEGRAM_PERPS_COMMANDS.map((item) => item.command).join(", ")}`, |
| #182 | }; |
| #183 | } |
| #184 | } |
| #185 |