mirror of
https://github.com/michaelshimeles/terminal.git
synced 2026-11-07 05:56:17 -10:00
master
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a12b5d14e4 |
feat(hl): built-in Turnkey wallets on testnet (#38)
* docs: design for Hyperliquid trading (crypto + HIP-3 stock perps) Design only, no feature code. Covers custody (client-side API wallet signing, recommended), agent approve/revoke flow, asset routing for core/spot/HIP-3, order ticket, user streams for POS/ORD/ACTV, safety rails, testnet-only test plan, phases, and open questions including the Hyperliquid ToS restriction on Ontario. * docs(hl-trading): plan the market key so HL perp rows reprice and trade Greptile: market_key() returns None for Future and live_price/row actions depend on it. Add Position.market and the portfolio_view work. * docs(hl-trading): keep testnet and mainnet quotes in separate maps Greptile: same market keys on both networks would let one overwrite the other in the shared quote map. Plan a network-aware live_price and mainnet-only gateway requests, with interleaved-update tests. * feat(hl): add tr-hl, a testnet-only Hyperliquid signing and trading crate tr-hl signs and sends Hyperliquid actions from the device. It covers L1 phantom-agent signing and user-signed approveAgent, the order, cancel, cancelByCloid, modify, updateLeverage, scheduleCancel and noop actions, asset ids read from perpDexs and meta, tick and lot rounding, info and exchange clients, a user-stream reducer and a nonce manager. Only testnet exists in this crate. The endpoints are the testnet hosts, the phantom agent source is always "b", hyperliquidChain is always "Testnet", and Network has one variant. A test greps the crate for mainnet hosts. The caps are constants and the trader enforces them before it signs. Orders are capped at $100 notional, leverage at 3x and market slippage at 1%. The builder field is never sent. Signatures match the Python SDK's published vectors, plus an approveAgent vector generated with SDK 0.24.0. The crate builds for wasm32. Co-Authored-By: Claude Opus 5.5 <[email protected]> * feat: Hyperliquid testnet trading in the app Hyperliquid joins LIVE next to SnapTrade, with its own opt-in in Settings > Trading > Hyperliquid and an amber TESTNET badge on the toolbar, the account, the ticket and every confirmation. - Connect an address read-only. The account's positions, orders, fills and funding then show in PORT, POS, ORD and ACTV, from Hyperliquid's websocket and never through Terminal's server. - Approve an agent on the desktop by pasting a throwaway testnet main key once. Terminal wipes it after signing and never stores it. In the browser the wallet signs instead (EIP-1193). The agent key lives in the macOS Keychain or the Linux Secret Service, and in browser memory or, by opt-in, IndexedDB under a non-extractable WebCrypto key. There is no file fallback. - The ticket's Hyperliquid variant covers market (IOC, 1% cap), limit (GTC, IOC, post-only), stop loss and take profit, reduce-only and "Set 3x" leverage. HIP-3 rows read "PERP · HL xyz (perpetual, not a share)". - Every order, cancel, cancel-all and leverage change asks for one confirmation. The worker re-reads the testnet mid and leverage and checks the caps again right before it signs. - KILL and a button in ORD cancel every open order and turn Hyperliquid orders off. The dead man's switch is opt-in. - Testnet rows price only from testnet mids. Position.market now carries the exact key, and live_price picks the map by network. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): mask addresses in Hyperliquid messages, toasts and logs Hyperliquid's errors name full addresses ("User or API Wallet 0x… does not exist", "Must deposit… User: 0x…"). mask_addresses turns each one into 0x1234…abcd. Exchange summaries, the worker's logs and every app message that shows a Hyperliquid error now go through it. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): keep Hyperliquid out of SnapTrade's settings sections The offscreen render showed the Hyperliquid account under SnapTrade's Brokerage access, with SnapTrade's "reconnect with trading access" advice. That section and the default-account picker now list SnapTrade accounts only. Hyperliquid has its own section. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs(hl-trading): record the v1 decisions and add screenshots and a wasm CI check Section 15 of the design now records Micky's twelve decisions as "Decided (2026-11-02)". The sections they change are updated: testnet only, Secret Service with no file fallback on Linux, a pasted throwaway key on the desktop for now, hard caps, an opt-in dead man's switch and the kill switch. A new section 16 lists what v1 builds and what is still missing. docs/img/hl-*.png holds the before (origin/master) and after screenshots. CI now builds and lints tr-hl for wasm32. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): read the agent key from the store once per account When the store had no key for the approved agent, the app asked again on every frame, which meant a Keychain or Secret Service read per frame. It now remembers the account it read and asks again only after a connect, an approval or a revoke. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): fix the kill switch, uncertain sends, approvals and cap valuation Fixes from Greptile's first review of #37: - Totals value a margined position (a perp) by its P&L, not its notional. Hyperliquid's cash is its collateral (equity less unrealised P&L), so a reprice moves equity only by the P&L change. - KILL reads the open orders fresh on every dex, cancels them, and reads again (three rounds at most) before it reports what is left. Signed actions now run one at a time, and an order confirmed before a KILL that hasn't been signed yet is refused. - An approval answer applies only to the account that asked for it, and Remove is disabled while one is in flight. The app also never signs with a key that isn't the approved agent's. - An uncertain send blocks new orders until orderStatus finds its cloid, or until its 30 s expiresAfter window has passed without it. - Every order needs a current mid before it is valued against the $100 cap. Prices that round to zero are refused, and rounding zero no longer overflows. - The keyring check runs in the worker, not on the UI thread. - A cancel-all skips a market the registry doesn't know instead of failing, and the pasted key field's undo history is wiped once the key has signed. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): keep the dead man's switch armed while an order is unresolved From Greptile's second review of #37: an order with no clear answer blocked new sends through the same guard the dead man's switch reads, so the switch cleared its scheduled cancel just when a possibly accepted order needed it. The guard is now split. Whether this device can sign arms the switch, and allows cancels and leverage changes. Only new orders and modifies also wait for an unresolved order. KILL always goes ahead. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(hl): size dollar amounts at the mid and let KILL skip stalled requests Fixes from Greptile's fourth review of #37 (at |
||
|
|
7d999a8e19 |
Rename the project from terminal-rs to terminal (#27)
* chore: rename the project from terminal-rs to terminal The crate and binary are now `terminal`, and user-facing text, docs, CI, scripts and repo URLs drop the -rs. Saved data follows the new name: - The desktop data folder moves from terminal-rs to terminal on first launch, and a link at the old path keeps older builds working. - The browser build copies localStorage keys from terminal-rs/ to terminal/ once and never overwrites newer keys. - SnapTrade credentials move from Keychain service terminal-rs to terminal the first time the app reads them. The bundle ID (dev.terminal-rs.app), the Sparkle signing key's keychain account and the notary profile keep the old name, because released copies and the release Mac depend on them. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: add screenshots for the rename PR (removed in the next commit) Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: drop the PR screenshots so they stay out of master The PR body links them at the previous commit. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(storage): keep fallback saves and the old-folder link working A browser tab that couldn't copy its keys keeps the old prefix. If another tab later finishes the copy, that tab's saves went to keys the next load skips. Its paths under terminal-rs/ now map to terminal/ as soon as the copy's marker exists. The link left at the old folder repeated `new` as given, so a relative HOME or XDG_DATA_HOME made it dangle. It now names its sibling. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
fa1b3c8886 |
fix(web): cache the app's wasm for good and serve /app/ without a redirect chain (#26)
* fix(web): cache the app's wasm for good and serve /app/ without a redirect chain scripts/build-web.sh now writes each build's JS and wasm to static/app/immutable/<hash>/, named after a hash of those files, and fills the paths into index.html. vercel.json caches /app/immutable/ for a year and answers a missing file there with a 404 marked no-store. index.html and the fonts keep Vercel's default of revalidating on every visit, so a deploy can't leave a page with one build's JS and another build's wasm. /app/ used to take two 308s through the SvelteKit function to reach the page (/app/ to ../app to /app/index.html). vercel.json now sends /app to /app/ with one 308 and serves /app/ from index.html, so the /app endpoint is gone. Relative URLs in the page still resolve under /app/. Both workflows move off the Node 20 majors: actions/checkout@v7, upload-artifact@v7, download-artifact@v8 and setup-node@v7 run on Node 24. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix(web): fall back to shasum where sha256sum is missing Older macOS releases ship shasum but not sha256sum, so build-web.sh stopped with exit 127 before writing index.html. Both commands give the same digest, so the folder names don't change. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
bf1dd94fd5 |
ci(web): deploy the site with the browser build from GitHub Actions (#24)
Vercel's build doesn't run Rust, so a deploy from Vercel's Git integration has no /app. The new deploy-site workflow runs scripts/build-web.sh, then vercel build and vercel deploy --prebuilt. Pushes to master deploy to production, and pull requests from this repository get a preview. site/vercel.json turns off Vercel's Git deployments so each commit deploys once. Co-authored-by: Claude Opus 5.5 <[email protected]> |
||
|
|
2ae060d2d0 |
fix(macos): ship as Terminal.dmg with the logo as its volume icon (#22)
* fix(macos): ship as Terminal.dmg with the logo as its volume icon Bumps to 0.1.1 so the next release replaces the v0.1.0 DMG, which predates the Terminal name and icon, and renames the remaining user-facing terminal-rs strings. Co-authored-by: Cursor <[email protected]> * fix(macos): detach the DMG's writable image if a release build fails while it's mounted Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
f69f864d78 |
feat(site): ask for an email before the download starts (#21)
* feat(site): ask for an email before the download starts The download buttons now open a dialog that asks for an email. It posts the address to `POST /download`, which adds it to an `emails` sorted set in Upstash Redis scored by when it was first given, then starts the download with `GET /download`. The browser remembers that it gave an email, so later downloads skip the dialog. A failed save still downloads, and direct `/download` links and visitors without JavaScript download without being asked. The Redis credentials are optional in `src/env.ts`, so the site builds and serves downloads before the Upstash integration is connected. Co-authored-by: Cursor <[email protected]> * fix(site): start the download if saving the email takes over 3 seconds The dialog waited for `POST /download` to settle before starting the download, so a hung Redis save left the button disabled with nothing downloading. Abort the save after 3 seconds and take the existing download-anyway path, without remembering the email as given. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
9dba5760d9 |
Rebuild the site around an animated demo with sound (#12)
* Rebuild the site around an animated demo with sound The page now opens with a 20-second demo of the app. AAPL is typed and loads a chart, 5 switches it to five-minute bars, NVDA OMON opens the option chain, and a Congress alert arrives. Captions follow each step. "Play with sound" replays it once with sounds synthesized in the browser, so there are no audio files. Six feature cards loop small animations of the chart, world markets, the command palette, the Congress feed, the portfolio and the themes, each only while it is on screen. The design follows the Terminal landing in Paper: dark only, SF fonts, glass controls and the new T icon, with no orange gradients. The page now hydrates because the demo needs JavaScript. With reduced motion the demo and cards show one still frame and nothing fades in on scroll. Co-authored-by: Cursor <[email protected]> * Use the candlestick logo Swap the T monogram for the three rising candlesticks from the Paper logo options, in the page logo and in assets-src/icon.svg, and regenerate the icons and share card. Co-authored-by: Cursor <[email protected]> * Move the theme switch into the nav as an icon button The button now switches the whole page, not just the demo. The page, the demo and the feature cards all have light styles, the choice is saved, and app.html applies it before the first paint. The demo captures are CSS backgrounds so only the current theme's image loads. Co-authored-by: Cursor <[email protected]> * Remove the build-from-source block from the Install section Co-authored-by: Cursor <[email protected]> * Show revealed sections when reduced motion turns on, and name the chapter buttons Turning on reduced motion reran the reveal attachment, which disconnected the observer and returned early, leaving unread sections at opacity 0. Teardown now marks the element shown. The chapter buttons lose their only text at 640px and below, so they get an aria-label. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
cdc4c585f6 |
Rename the site to Terminal and add full share metadata (#11)
* Rename the site to Terminal and fill in its share metadata The page still called the app terminal-rs and pointed its canonical URL, og:url and og:image at terminal-rs.vercel.app, while the site now lives at terminal.rasmic.xyz. Move SITE_URL to the custom domain, build every absolute URL from it, and show the name as Terminal in the title, alt text, Open Graph and Twitter tags and the share card. The tagline stays next to the name so it still reads as a market terminal, not Apple's Terminal. Fill the gaps link previews and crawlers look for: og:site_name, og:locale, og:image:type, twitter:image:alt, light and dark theme-color, a SoftwareApplication JSON-LD block, and a sitemap that robots.txt points to. The description is trimmed to 157 characters so search results don't cut it off. og.jpg is re-rendered from assets-src/og.html with scripts/build-images.sh; the other generated images came out byte-identical. The GitHub repo, DMG and package names keep -rs. Co-authored-by: Cursor <[email protected]> * Make theme-color follow the theme the page shows The two theme-color tags followed the system appearance through their media queries, but the toggle lets you pick and save the other theme, so choosing light on a dark Mac left the browser chrome dark, before and after a reload. Move the tag into app.html ahead of the theme script and let apply() set it with the page's data-theme. It now matches on first paint, after a saved choice is restored, on every toggle and when the system appearance changes. The page ships no framework JavaScript (csr = false), so nothing rewrites the tag later. Without JavaScript the page is always dark, and the tag's static value is the dark background too. Co-authored-by: Cursor <[email protected]> --------- Co-authored-by: Cursor <[email protected]> |
||
|
|
2289312ff9 |
Add the download page under site/ (#9)
* Add the download page under site/
A one-page SvelteKit site for Vercel with a /download route that
redirects to the latest release DMG. It is its own npm project, apart
from the Cargo workspace; deploy it with the Vercel Root Directory set
to site.
Co-authored-by: Cursor <[email protected]>
* Remove the amber glow behind the hero
The backdrop keeps its grid and fade. Drop the --glow colour too,
since nothing else used it.
Co-authored-by: Cursor <[email protected]>
* Document the site's Node minimum and find Chrome on Linux
SvelteKit needs Node 22.17 or later, and engine-strict makes npm
install stop on older versions, so declare it in engines and say so
in the README. build-images.sh now finds Chrome or Chromium on PATH
before falling back to the macOS app, and stops with a clear message
when neither is there.
Co-authored-by: Cursor <[email protected]>
* Let CHROME name a command on PATH
The executable check added in
|