mirror of
https://github.com/0xrsydn/idx-cli.git
synced 2026-11-07 09:45:36 +00:00
feat(stockbit): one browser sign-in in idx-core for the CLI and MCP
`stockbit::signin` is now the single sign-in flow. `idx stockbit login` waits on it in the foreground; the `stockbit_login` MCP tool runs it on a thread and `stockbit_status` reports `sign_in.state`, so an agent knows when to stop polling. Auto uses a browser unless the shell is over SSH or has no display, and falls back to the local page only when the browser cannot start. The browser way opens Stockbit's sign-in page in a profile only idx uses and reads the session cookie over DevTools. What a real sign-in showed: - The cookie is host-only on stockbit.com, so deleting by the assumed .stockbit.com removed nothing and left live tokens in the profile. It is now deleted by its own domain and path, with every other tab closed first, and read back to confirm. - A signed-out page writes the cookie without tokens; it no longer counts. - A profile belongs to one browser, so it records the executable that made it. - On macOS the config directory depends on XDG_CONFIG_HOME, so a shell and an app started from the Dock disagreed; both default locations are now checked. - A thread does not outlive main, so idx-mcp closes a waiting browser when stdin closes or on SIGTERM or Ctrl-C. Progress goes to stderr, which keeps `-o json` to one document on stdout. Google refused its own sign-in in this window on 2026-10-31, most likely over the debugging flag; password sign-in works, and the docs and roadmap say so. Claude-Session: https://claude.ai/code/session_01RqPPVaoFxLToGAXXBEoCtH
This commit is contained in:
parent
cb532b670b
commit
ca4d3d09c2
21 changed files with 2799 additions and 212 deletions
|
|
@ -1550,12 +1550,12 @@ Options:
|
|||
## `idx stockbit`
|
||||
|
||||
```text
|
||||
Your own Stockbit session, for `stocks orderbook`, live `--provider stockbit` quotes and Stockbit daily history. Opt-in and personal: idx uses your account's tokens, stored in the config directory with owner-only permissions, and never logs them. Stockbit rotates the refresh token on every refresh, so a browser sharing the session is logged out once idx refreshes: log in through a separate browser profile for idx. Stockbit's terms allow personal, non-commercial use.
|
||||
Your own Stockbit session, for `stocks orderbook`, live `--provider stockbit` quotes and Stockbit daily history. Opt-in and personal: idx uses your account's tokens, stored in the config directory with owner-only permissions, and never logs them. Stockbit rotates the refresh token on every refresh, so one session has one owner: `login` signs in through a browser profile only idx uses. Stockbit's terms allow personal, non-commercial use.
|
||||
|
||||
Usage: idx stockbit [OPTIONS] <COMMAND>
|
||||
|
||||
Commands:
|
||||
login Connect a session in your browser, or from stdin
|
||||
login Sign in through your browser, or from stdin
|
||||
status Show whether a session is stored and when its tokens expire
|
||||
logout Delete the stored session
|
||||
help Print this message or the help of the given subcommand(s)
|
||||
|
|
@ -1590,8 +1590,9 @@ Options:
|
|||
Print help (see a summary with '-h')
|
||||
|
||||
Examples:
|
||||
idx stockbit login # paste the credentialStorage cookie
|
||||
pbpaste | idx stockbit login
|
||||
idx stockbit login # sign in through a browser
|
||||
idx stockbit login --no-browser # local page: bookmarklet or paste
|
||||
pbpaste | idx stockbit login # the credentialStorage cookie on stdin
|
||||
idx stockbit status
|
||||
idx stockbit logout
|
||||
```
|
||||
|
|
@ -1599,13 +1600,13 @@ Examples:
|
|||
### `idx stockbit login`
|
||||
|
||||
```text
|
||||
In a terminal, opens a local page on 127.0.0.1 with two one-click ways to hand idx your Stockbit session: a bookmarklet that reads stockbit.com's cookie in your own browser, or a read-the-clipboard button. Without a browser (or with --no-browser), the page URL is printed instead. With stdin piped, it reads the value of stockbit.com's `credentialStorage` cookie (DevTools, Application, Cookies) or a refresh token from stdin, as before. Either way idx checks the session with one request. Servers can set IDX_STOCKBIT_REFRESH_TOKEN instead.
|
||||
In a terminal, idx opens Chrome (or Chromium, Edge, Brave, Helium) on Stockbit's sign-in page with a profile only idx uses. Sign in there: idx reads the session cookie over the DevTools protocol, checks it with one request, takes it out of that profile, and closes the window. Your password, one-time codes and any reCAPTCHA stay in the browser. A stored session that still works means nothing to do: idx exits at once. Over SSH, without a display, without such a browser, or with --no-browser, idx serves a local page on 127.0.0.1 instead, with a bookmarklet that reads the cookie in your own browser and a clipboard button. With stdin piped, it reads the value of stockbit.com's `credentialStorage` cookie (DevTools, Application, Cookies) or a refresh token from stdin. Servers can set IDX_STOCKBIT_REFRESH_TOKEN instead; IDX_STOCKBIT_BROWSER picks the browser.
|
||||
|
||||
Usage: idx stockbit login [OPTIONS]
|
||||
|
||||
Options:
|
||||
--no-browser
|
||||
Print the page URL instead of opening a browser
|
||||
Use the local page instead of a browser sign-in
|
||||
|
||||
-o, --output <OUTPUT>
|
||||
Output format [default: auto = table on a terminal, json when piped]
|
||||
|
|
@ -1616,7 +1617,7 @@ Options:
|
|||
Disable colored output
|
||||
|
||||
--port <PORT>
|
||||
Fixed port for the local page (for `ssh -L`); default: any free one
|
||||
Port for the local page (for `ssh -L`); default 7878, or any free one
|
||||
|
||||
-q, --quiet
|
||||
Suppress non-essential output
|
||||
|
|
|
|||
|
|
@ -80,44 +80,114 @@ idx --provider stockbit stocks history BBCA --period 1y # Stockbit's daily
|
|||
idx stockbit logout
|
||||
```
|
||||
|
||||
**Logging in.** `idx stockbit login` opens a small page on your own machine
|
||||
(127.0.0.1, a fresh port each run). With stockbit.com open and logged in,
|
||||
click the page's **Send my Stockbit session** bookmarklet: it reads
|
||||
Stockbit's `credentialStorage` cookie in your browser and hands it to the
|
||||
page, which checks it with one request and says "Connected". If bookmarklets
|
||||
are blocked, click **Paste from clipboard** after copying the cookie, or
|
||||
paste it into the box. Without a browser, `--no-browser` prints the page URL
|
||||
instead, and `--port 7878` pins the port for `ssh -L 7878:127.0.0.1:7878`.
|
||||
Piping the value in still works (`pbpaste | idx stockbit login`), as does a
|
||||
refresh token on its own. On a server, set `IDX_STOCKBIT_REFRESH_TOKEN`.
|
||||
**Logging in.** `idx stockbit login` opens Chrome (or Chromium, Edge, Brave,
|
||||
Helium) on Stockbit's own sign-in page, in a browser profile only idx uses. Sign in
|
||||
there as usual, including any one-time code: idx reads the
|
||||
session cookie over the DevTools protocol, checks it with one request, and
|
||||
closes the window. Your password never reaches idx. The profile sits beside
|
||||
`config.toml`; idx takes the session cookie out of it once the session is
|
||||
stored, so the profile keeps only Stockbit's device cookies. The profile
|
||||
stays with the browser that made it: idx opens the same one next time, unless
|
||||
`IDX_STOCKBIT_BROWSER` names another. Choose your browser that way on the
|
||||
first sign-in if you have several.
|
||||
|
||||
Use your Stockbit password in that window. Google can refuse to sign in there
|
||||
with "This browser or app may not be secure", most likely because idx starts
|
||||
the browser with remote debugging on. If you only sign in with Google, use the
|
||||
local page below: sign in from a private window, paste the cookie, then close
|
||||
that window.
|
||||
|
||||
Run `login` again while the session is still good and there is nothing to
|
||||
do: idx checks it with one request and exits without opening a browser. The
|
||||
window it does open waits 15 minutes, and closes at once if you close it
|
||||
yourself.
|
||||
|
||||
**How long a session lasts.** Stockbit's refresh token is good for about a
|
||||
week, and idx spends it on every refresh, which extends the session. Use idx
|
||||
at least once a week and you stay signed in. A longer gap, a `logout`, or
|
||||
another tool spending the same token means one more sign-in.
|
||||
|
||||
Over SSH, on a machine with no display, without such a browser, or with
|
||||
`--no-browser`, idx serves a small page on your own machine (127.0.0.1, port
|
||||
7878 when it is free) instead. With
|
||||
stockbit.com open and logged in, click the page's **Send my Stockbit
|
||||
session** bookmarklet: it reads Stockbit's `credentialStorage` cookie in your
|
||||
browser and hands it to the page, which checks it with one request and says
|
||||
"Connected". If bookmarklets are blocked, click **Paste from clipboard**
|
||||
after copying the cookie, or paste it into the box. `--port` picks another
|
||||
port. Piping the value in still works
|
||||
(`pbpaste | idx stockbit login`), as does a refresh token on its own. On a
|
||||
server, set `IDX_STOCKBIT_REFRESH_TOKEN`. Set `IDX_STOCKBIT_BROWSER` to use a
|
||||
browser idx does not find on its own.
|
||||
|
||||
The session lands in `~/.config/idx/stockbit-session.json`, readable only by
|
||||
you. Tokens never appear in output, logs or errors. The page takes only the
|
||||
you. On macOS without `XDG_CONFIG_HOME` that is
|
||||
`~/Library/Application Support/idx/` instead; idx finds a session in either
|
||||
one, so the CLI and an MCP client started from the Dock share it. Tokens never appear in output, logs or errors. The page takes only the
|
||||
session value, keeps it in memory, and closes when it is done (or after five
|
||||
minutes). A session Stockbit refuses leaves a previously stored one in place.
|
||||
|
||||
The page listens on this machine's loopback interface only, so the browser
|
||||
must run on the same machine: from another host over SSH, or from a browser
|
||||
outside a container or WSL distro, `127.0.0.1` is a different machine and the
|
||||
page will not load. idx notices an SSH session (`SSH_CONNECTION`) and prints
|
||||
the exact command to run on the machine with the browser, on port 7878:
|
||||
## Remote and headless
|
||||
|
||||
The page listens on this machine's loopback interface only, and the browser
|
||||
handoff needs a browser on this machine too. On a server, in a container, or
|
||||
in a WSL distro, `127.0.0.1` is a different machine and neither will load.
|
||||
Three ways around that, in order of how little they ask of you.
|
||||
|
||||
**Pipe the cookie over SSH.** No tunnel, one command. Copy the
|
||||
`credentialStorage` value on the machine with the browser (DevTools,
|
||||
Application, Cookies), then:
|
||||
|
||||
```bash
|
||||
ssh -L 7878:127.0.0.1:7878 <this-host> # run where the browser is, keep it open
|
||||
pbpaste | ssh <host> "idx stockbit login"
|
||||
```
|
||||
|
||||
Elsewhere, pin the port yourself and forward it the same way:
|
||||
idx reads stdin, verifies the session, and stores it on the server. The value
|
||||
never reaches a shell history or a file.
|
||||
|
||||
**Forward the page.** Run the page on the server and forward its port from the
|
||||
machine with the browser:
|
||||
|
||||
```bash
|
||||
idx stockbit login --no-browser --port 7878
|
||||
idx stockbit login # on the server: over SSH, it serves the page
|
||||
ssh -L 7878:127.0.0.1:7878 <host> # where the browser is, keep it open
|
||||
```
|
||||
|
||||
Then open the printed URL there and click the bookmarklet. Over SSH, idx
|
||||
notices `SSH_CONNECTION`, skips the browser, and prints the exact forward
|
||||
itself.
|
||||
|
||||
**Seed a token.** For anything unattended, keep the refresh token in a secret
|
||||
store and pass it at run time:
|
||||
|
||||
```bash
|
||||
op run --env-file=stockbit.env -- idx stocks orderbook BBCA
|
||||
```
|
||||
|
||||
where the file holds `IDX_STOCKBIT_REFRESH_TOKEN=op://Private/stockbit/refresh`.
|
||||
Only the refresh token is needed; idx mints its own access token.
|
||||
|
||||
**Agents.** Over MCP, an agent calls `stockbit_login`, which answers at once
|
||||
and does the same as `idx stockbit login`. Where idx-mcp runs on your desktop,
|
||||
a browser window opens on Stockbit's sign-in page (`"method": "browser"`) and
|
||||
you sign in there. Over SSH or without a display, the answer carries the page
|
||||
URL and its `ssh -L` forward (`"method": "page"`) for the agent to hand you.
|
||||
The agent then polls `stockbit_status` until `sign_in.state` is `signed_in`
|
||||
or `failed`. A session that already works answers `signed_in` without opening
|
||||
anything, a second call while one is waiting returns it again, and
|
||||
`{"method": "page"}` or `{"method": "browser"}` picks the way. If the server
|
||||
stops while the window waits, the window closes with it.
|
||||
|
||||
One rule for all three: only one machine may own a session. Stockbit retires
|
||||
the refresh token on every refresh, so a token copied to two machines signs the
|
||||
other one out. Two machines need two sign-ins.
|
||||
|
||||
**One refresher per session.** Stockbit replaces the refresh token every time
|
||||
it is used. Once idx refreshes your session, a browser holding the same
|
||||
session has to log in again, and two tools sharing one session log each
|
||||
other out. Log in through a separate browser profile (or a private window
|
||||
you then close) for idx. idx processes on one machine take turns through a
|
||||
lock, so they never spend the token twice.
|
||||
other out. `idx stockbit login` keeps its own browser profile, so this only
|
||||
affects a browser you use yourself. idx processes on one machine take turns
|
||||
through a lock, so they never spend the token twice.
|
||||
|
||||
What the login adds:
|
||||
|
||||
|
|
@ -139,7 +209,8 @@ candles explicitly; windows it charts only weekly or hourly (`2y`, `5y`,
|
|||
|
||||
Stockbit's [terms](https://stockbit.com/terms) allow its content for personal,
|
||||
non-commercial use. They prohibit data mining, robots and redistribution
|
||||
without Stockbit's written consent. idx is not affiliated with or endorsed by
|
||||
without Stockbit's written consent, which includes serving the data to other
|
||||
people through `idx-mcp`. idx is not affiliated with or endorsed by
|
||||
Stockbit. Use this for looking at a stock now and then, not for crawling the
|
||||
market or republishing prices. With your login, automated use is tied to your
|
||||
account: keep it human-paced.
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ Every IDX holding (above 1%) of one investor, matched by name.
|
|||
|
||||
## `get_orderbook`
|
||||
|
||||
Order book of one IDX stock from the user's own Stockbit session: `bids` and `offers` (best price first) of {price, shares, orders}, the session's OHLC, volume (shares), value and frequency, and foreign buy/sell/net in IDR. `market_status` is Stockbit's state, verbatim; outside STATE_NAME_MARKET_OPEN the book is as the market left it. AUTHERROR means there is no session: call stockbit_status, and ask the user to run `idx stockbit login` in a terminal.
|
||||
Order book of one IDX stock from the user's own Stockbit session: `bids` and `offers` (best price first) of {price, shares, orders}, the session's OHLC, volume (shares), value and frequency, and foreign buy/sell/net in IDR. `market_status` is Stockbit's state, verbatim; outside STATE_NAME_MARKET_OPEN the book is as the market left it. AUTHERROR means there is no session: call stockbit_status, then stockbit_login for a URL the user can open.
|
||||
|
||||
| Input | Type | Required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
|
|
@ -172,8 +172,16 @@ Search investor names in the KSEI ownership database.
|
|||
| `limit` | integer | no | Maximum results (default 20, at most 100). |
|
||||
| `query` | string | yes | Full-text query over investor names. |
|
||||
|
||||
## `stockbit_login`
|
||||
|
||||
Start a Stockbit sign-in and return at once; this call does not wait for it. With method auto (the default), idx-mcp opens a browser window on Stockbit's own sign-in page when its machine has a display and is not reached over SSH (`method: "browser"` in the answer): the user signs in there and the window closes by itself. Otherwise it serves a page on 127.0.0.1 (`method: "page"`, with `url` and an `ssh -L` `forward` for a browser on another machine) that takes stockbit.com's session cookie from the user's own browser. Never ask the user for their password, and never type it. Then poll stockbit_status until `sign_in.state` is signed_in or failed. A session that already works answers state signed_in without opening anything; a second call while one is waiting returns it again (`already_open`).
|
||||
|
||||
| Input | Type | Required | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `method` | `auto` / `browser` / `page` | no | "auto" (default): a browser window when idx-mcp's machine has a display and no SSH, else the local page; "browser" or "page" picks one. |
|
||||
|
||||
## `stockbit_status`
|
||||
|
||||
Whether a Stockbit session is stored (or seeded by IDX_STOCKBIT_REFRESH_TOKEN) and when its tokens expire; never the tokens. Without one, get_orderbook fails and stockbit-provider quotes use Stockbit's delayed public page; the user adds one with `idx stockbit login` in a terminal.
|
||||
Whether a Stockbit session is stored (or seeded by IDX_STOCKBIT_REFRESH_TOKEN) and when its tokens expire; never the tokens. Without one, get_orderbook fails and stockbit-provider quotes use Stockbit's delayed public page; the user adds one with stockbit_login, or `idx stockbit login` in a terminal. After stockbit_login, `sign_in.state` says whether that sign-in is waiting, signed_in or failed (with `sign_in.error`).
|
||||
|
||||
No inputs.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue