- Whale app: read `lbtheme/<mode>` from UA on mount and override
`isDark` before the first sync, so initial render matches the app
shell's theme.
- VPLocalNav: pin to fixed position below AppNav and only reveal after
scrolling past `--vp-nav-height`; previously it sat at `top: 0` and was
occluded by AppNav, or scrolled with content.
Detect whale app via UA `lbcommitid`, then hide AppNav, VPLocalNav,
Footer, VPDocFooter; reset VPDoc.has-sidebar margin-top to 0; skip
loading the support-widget (not yet adapted for app). Also let
VPDocFooter row (Markdown / Edit / Last Updated) wrap naturally instead
of forcing space-between.
## Merge Verdict
**[APPROVE]** — Small, mechanical extension of the existing region
rewrite to cover a third root domain (`mcp.longbridge.com`).
> 3 files · +8 / -1 · `region.config.ts` `docs/.vitepress/`
---
## Summary
- `region.config.ts`: `RegionConfig` interface gains a new required
field `mcpHostname`; CN region sets it to `https://mcp.longbridge.cn`.
- `docs/.vitepress/region-utils.ts`: `buildRegionUrlReplacements()`
emits a third pair of rules (URL + bare-text) for the MCP hostname —
same shape as the existing `siteHostname` / `apiBaseUrl` blocks.
- `docs/.vitepress/config.mts`: `MCP_TOOLS_URL` (used by the
`fetch-mcp-tools` build-time plugin) now resolves to
`${regionCfg?.mcpHostname ||
'https://mcp.longbridge.com'}/mcp/tools.json` — CN builds source the
tool catalogue from the regional endpoint instead of `.com`.
---
## Risk Analysis
| Risk | Level | Mitigation |
|------|-------|-----------|
| `mcp.longbridge.cn/mcp/tools.json` endpoint not yet live | 🟡 |
Reviewer to confirm before merge — `fetch-mcp-tools` will hard-fail the
CN build if the URL 404s |
| Global build (`build:release`) regression | ✅ | Verified: with no
`VITE_REGION`, `regionCfg` is undefined → helper returns `[]` for MCP
rules; `MCP_TOOLS_URL` falls back to `mcp.longbridge.com`; `mcp.html`
keeps 7 `.com` + 1 `.cn` (original "China mainland" section) identical
to source |
| Order-dependent rewriting between `mcp` / `open` / `openapi` | ✅ | All
three hostnames are mutually non-substring (different 5th char or
different prefix), so the three protocol-prefixed + three bare-text
rules are independent regardless of order |
| Mainland users on global `.cn` site getting wrong fallback | ✅ | This
PR only adds a CN-only rule; nothing about the global path changes |
---
## Design Decisions
- **Add `mcpHostname` to `RegionConfig` rather than hardcoding inside
the helper** — keeps the regional URL list in one declarative file
(`region.config.ts`) instead of scattering string constants across
`region-utils.ts`. Matches the pattern already set by `siteHostname` /
`apiBaseUrl`.
- **Switch the build-time fetch source, not just the displayed URL** —
chosen so the CN build's `mcp-tools.json` actually reflects the
catalogue served by the CN MCP endpoint (potentially region-specific
tools), instead of CN docs displaying `.cn` while embedded data was
scraped from `.com`.
- **Field is required, not optional** — every region must declare its
MCP hostname explicitly; prevents silent fallback to `.com` when a new
region is added.
---
## Code Notes
1. **[Needs review]** Confirm `https://mcp.longbridge.cn/mcp/tools.json`
is live and returns the same JSON shape as the global endpoint before
merge. If not yet deployed, the CN build will fail at `fetch-mcp-tools`
`buildStart` with an HTTP error.
---
## Verification
- ✅ `bun run build:cn` succeeds; `rg -l
'(open|openapi|mcp)\.longbridge\.com' docs/.vitepress/dist` → zero
residual `.com` across HTML / MD / JS / install scripts /
`mcp-tools.json`.
- ✅ `bun run build:release` succeeds; `dist/docs/mcp.md` per-file domain
distribution (1× `mcp.longbridge.cn` + 7× `mcp.longbridge.com`) matches
source 1:1.
- ✅ Source `install.ps1` is byte-identical to global build output (no
accidental rewrite).
Co-authored-by: 袁昌瑞 <changrui.yuan@longbridge-inc.com>
## Merge Verdict
**[APPROVE]** — Mechanical URL swap from `open.longbridge.com` to
`assets.lbkrs.com` for terminal release lookup + download.
> 2 files · +4 / -4 · `docs/public/longbridge-terminal/`
---
## Summary
- `install` (POSIX) and `install.ps1` (PowerShell) both switched from
`https://open.longbridge.com/...` to
`https://assets.lbkrs.com/github/release/longbridge-terminal/...` for
the latest-version probe and the binary tarball/zip download.
- Path layout also realigned: previously `/{repo}/releases/latest` with
`repo=longbridge/longbridge-terminal`; now
`/github/release/longbridge-terminal/latest` — a fixed path no longer
parameterized by `$repo`.
- `$repo` variable is still declared in `install` but no longer used for
URL construction (only referenced in code comments / future use); kept
to minimize diff.
---
## Risk Analysis
| Risk | Level | Mitigation |
|------|-------|-----------|
| `assets.lbkrs.com/github/release/longbridge-terminal/latest` endpoint
not yet live | 🟡 | Reviewer to confirm the new CDN endpoint is published
before merging — script will fail at `get_latest_release` if the URL
404s |
| Existing users who already ran the old script | ✅ | They have
`longbridge` on PATH; this PR only affects new installs / reinstalls |
| Region build interaction | ✅ | The CN region rewrite plugin (added in
#1100) only rewrites `open.longbridge.com` / `openapi.longbridge.com`;
`assets.lbkrs.com` is intentionally untouched and CN builds will keep
the same CDN URL |
| `$repo` variable now unused | 🟢 | Cosmetic only — script still runs;
removing it is a follow-up cleanup if desired |
---
## Design Decisions
- **Use a fixed path instead of `$repo`-templated**: The new endpoint is
a dedicated CDN slot (`/github/release/longbridge-terminal/`) rather
than a GitHub-mirror-style route, so the `$repo` indirection is no
longer meaningful. Switching to a flat path matches the actual CDN
layout.
- **Source file stays `assets.lbkrs.com` for all regions**: Unlike
`open.longbridge.com`, the assets CDN is not region-split, so no region
rewrite is needed; the file is identical for global and CN builds.
---
## Code Notes
1. **[Needs review]** Endpoint readiness on
`assets.lbkrs.com/github/release/longbridge-terminal/latest`
Reviewer should verify the CDN endpoint serves the latest version tag
(and the per-version tarballs/zips) before merging; otherwise new
installations will fail at the first `curl --silent` call.
2. **[Info]** `$repo='longbridge/longbridge-terminal'` left declared but
unused in `install` (line 5)
Not a bug — script still runs cleanly. Can be removed in a follow-up if
the team prefers a tighter diff for future edits.
— Author note: intentionally kept for now; will clean up in a follow-up.
---
## Verification
- ✅ Both files contain only the URL constants — no logic changes, no
shell-substitution edge cases introduced.
- 📋 Manual check after merge: `curl -sSL
https://assets.lbkrs.com/github/release/longbridge-terminal/install |
sh` on Linux/macOS, and `iwr
https://assets.lbkrs.com/longbridge/longbridge-terminal/install.ps1 |
iex` on Windows.
- 📋 Confirm the CDN endpoint
`assets.lbkrs.com/github/release/longbridge-terminal/latest` returns a
version string with deploy ops.
Co-authored-by: 袁昌瑞 <changrui.yuan@longbridge-inc.com>
## Merge Verdict
**[APPROVE]** — Region URL rewriting is now complete across every
artifact channel; global build verified untouched.
> 6 files · +73 / -26 · `docs/.vitepress` `scripts/` `package.json`
---
## Summary
- Extract a shared `buildRegionUrlReplacements()` in `region-utils.ts`
that emits **four** rules per non-default hostname (protocol-prefixed +
bare-text for both `siteHostname` and `apiBaseUrl`), and route the four
pre-existing rewrite sites (`region-filter.ts`, `transformHtml`,
`buildEnd install`, plus the new ones) through it.
- Add a new Vite `region-source-url-rewrite` plugin (`enforce: 'pre'`)
that rewrites hardcoded hostnames inside `.vue/.ts/.json/.yaml` source
modules — this is the only channel that reaches Vite-compiled JS bundles
(install command strings in Vue components, `mcp-tools.json` connect
links, `openapi.yaml` error-message text).
- Bring `.md` copies + `llms.txt` into region rewriting:
`normalize_md.ts` (the real writer of `dist/**/*.md`) and
`generate-llms.ts` (the static `llms-intro.md` injection point) now
share the same helper.
- Fix root-cause env-leak: `build:cn` now also passes `VITE_REGION=cn`
to the `bun run build:llms` segment — previously `cross-env` only scoped
to the `vitepress build` process, so `normalize_md`/`generate-llms`
never knew it was a CN build and silently produced `.com` artifacts.
---
## Risk Analysis
| Risk | Level | Mitigation |
|------|-------|-----------|
| Global build (`build:release`) accidentally rewritten | ✅ | Shared
helper returns `[]` when `VITE_REGION` is unset → every call site is a
no-op. Verified: `dist/longbridge-terminal/install.ps1` is
byte-identical to source; `mcp.html` keeps all 9 `.com`; `llms-full.txt`
keeps all 112 `open.longbridge.com`. |
| Bare-rule replacement double-matches | ✅ | `open.longbridge.com` is
**not** a substring of `openapi.longbridge.com` (5th char `.` vs `a`),
so the four rules are mutually independent regardless of order. |
| Vite `transform` runs on every module — performance hit | 🟢 |
`buildRegionUrlReplacements()` is lightweight (one env read + small
array build). On global builds it short-circuits via
`replacements.length === 0`. |
| `enforce: 'pre'` ordering vs `yaml-transform` | ✅ | `'pre'` plugins
run before normal plugins, so this transform sees raw YAML text and
rewrites it before `yaml-transform` JSON-stringifies it. |
| Hardcoded global hostnames in helper | 🟡 | Helper compares against the
literal `'https://open.longbridge.com'` /
`'https://openapi.longbridge.com'`. If the global domain ever changes,
this file plus `region.config.ts` must be updated together. Same
constraint already existed before this PR. |
---
## Design Decisions
- **Centralize rules in `region-utils.ts`** instead of inlining at four
call sites — four sites already drifted (HTML had two rules but markdown
had only the URL form before the previous PR). One source of truth
prevents future drift.
- **Pre-stage Vite transform** rather than a post-build dist scan —
keeps source maps intact and lets the rewrite participate in dependency
invalidation. It also naturally covers `openapi.yaml` (huge but fine —
string `split/join` is O(n) and only runs once per module per build).
- **Bare-hostname rules alongside URL rules** — covers
`[open.longbridge.com/connect](https://...)` markdown patterns where
only the link target gets matched by URL rules; the display text needs
the bare-host rule.
- **Source `install` / `install.ps1` keep `.com`** — global build's
`buildEnd` already had a rewrite pass; making source `.com`-default lets
the existing rewrite mechanism do the work and avoids two
source-of-truth files.
---
## Code Notes
1. **[Info]** `region-utils.ts:25` comment "first so bare rules don't
double-match"
In practice both orderings are correct because after either rule runs
the other one's "from" string no longer exists in the result. The note
is defensive rather than load-bearing.
— Author note: deferred to next iteration.
2. **[Info]** `config.mts` Vite transform hook calls
`buildRegionUrlReplacements()` per module
The helper is cheap but is invoked once per source module on every
build. Could be hoisted to the closure top if profiling ever flags it;
not worth the structural change today.
— Author note: deferred to next iteration.
3. **[Info]** `package.json` build:cn duplicates `cross-env
VITE_REGION=cn` across two segments
Maintainable but easy to forget if a third stage is added later. Could
be solved with `cross-env-shell` wrapping the whole chain, but that's a
separate cleanup.
— Author note: deferred to next iteration.
4. **[Needs review]** Vite `transform` regex includes `.yaml`/`.yml`
This is intentional — `openapi.yaml` ships hardcoded
`https://open.longbridge.com/sdk` and error-message URLs that must be
rewritten for CN. Reviewer should confirm there's no other YAML in the
dependency graph whose `.com` strings must be preserved as global
references. None observed in the current tree.
---
## Verification
- ✅ `bun run build:cn` succeeds; `rg -l
'(open|openapi)\.longbridge\.com' docs/.vitepress/dist` → **zero
residual `.com`** across HTML/MD/JS/scripts.
- ✅ `bun run build:release` succeeds; `install.ps1` and `install` are
byte-identical to source; `mcp.html` keeps 9× `.com`; `llms-full.txt`
keeps 112× `open.longbridge.com`; CN endpoint mentions inside docs
(`getting-started.md` etc.) are preserved as intended.
- ✅ `openapi-quote.longbridge.cn` / `openapi-trade.longbridge.cn` counts
in `getting-started.html` match source 1:1 (no over-rewrite).
- 📋 Reviewer to confirm: CN site (`open.longbridge.cn`) renders `mcp.md`
/ `skill/install` pages with the new URLs after deploy.
Co-authored-by: 袁昌瑞 <changrui.yuan@longbridge-inc.com>
🤖 Auto-generated by Endless task
[#24](https://endless.longbridge-inc.com/projects/developers/tasks/24).
Initiated by: Huacnlee Li Huashun
## Background
The `longbridge/skills` repository recently added a Codex plugin
manifest (`.codex-plugin/plugin.json`), enabling OpenAI Codex users to
install Longbridge Skills via the native Codex plugin system — analogous
to the existing Claude Code plugin path.
The developer documentation site already documented how to install
Skills via the Claude Code plugin, npx/bunx, ZIP download, and OpenClaw.
However, there was no corresponding install block for Codex users who
want to use the plugin system. This left Codex users without a clear,
official install method in the docs.
## Summary
- Problem solved: Codex users had no documented plugin install path in
the Skill Installation Guide
- What was done: Added a "Via Codex plugin" block immediately after the
existing "Via Claude Code plugin" block in Step 2 of the Skill
Installation Guide, across all three locales (en, zh-CN, zh-HK)
- Why this approach: Mirrors the existing Claude Code plugin block in
structure and placement; uses the exact commands from
`code/skills/docs/install.md` Path D (`codex plugin marketplace add
longbridge/skills` + `codex plugin add longbridge@longbridge-skills`)
- How to verify: Open any of the three locale install pages
(`/skill/install`, `/zh-CN/skill/install`, `/zh-HK/skill/install`) and
confirm the new "Via Codex plugin" block appears between the Claude Code
plugin block and the npx/bunx block in Step 2
## Changes
| File | Change |
|---|---|
| `docs/en/skill/install/index.md` | Added "Via Codex plugin" install
block after the Claude Code plugin block in Step 2 |
| `docs/zh-CN/skill/install/index.md` | Added Simplified Chinese "通过
Codex 插件安装" block after the Claude Code plugin block in Step 2 |
| `docs/zh-HK/skill/install/index.md` | Added Traditional Chinese "通過
Codex 插件安裝" block after the Claude Code plugin block in Step 2 |
## Key Decisions
Placed the Codex plugin block immediately after Claude Code plugin
(before npx/bunx) because both are plugin-system install methods and
belong together; npx/bunx is a more general path that applies to all
tools regardless of plugin support.
---------
Co-authored-by: Huacnlee Li Huashun <huacnlee@longbridge-inc.com>
Co-authored-by: Jason Lee <huacnlee@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## What
Removes the **"100+"** skill-count claims from the homepage copy.
## Why
The skills repo was consolidated from 127 skills down to 13. The raw
count is no longer a selling point — quantity isn't the differentiator
anymore, capability and coverage are. So the copy shouldn't lead with a
number that is both outdated and off-message.
## Changes (all three locales: en / zh-CN / zh-HK)
- **`Skill.vue`** — catalog hero title: `100+ Skills, covering every
move…` → `Skills that cover every move in your trading day.`
- **`NewHomePage/index.vue`**
- AI Skill product-card `tags`: `['100+ Skills']` → `['Agent Skills']`
(4 occurrences)
- AI-section `eyebrow`: `AI Skill · 100+ packaged tools` → `AI Skill ·
packaged tools`
The CLI card's `130+ cmds` is a separate, still-valid metric and is left
untouched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
- The `Connect AI` button on the `/skill` page hard-coded
`href="/connect"`, so zh-CN / zh-HK visitors were sent to the English
connect page.
- Now uses the existing `localePfx` computed (same as the
`/skill/install` link), linking to `/zh-CN/connect` / `/zh-HK/connect` /
`/connect` per the current locale. All three paths verified live (200).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
- Add new **Agent Auth Code** doc page (en / zh-CN / zh-HK): generate a
one-time code at
[open.longbridge.com/connect](https://open.longbridge.com/connect),
redeem via CLI `auth login --auth-code` or the dedicated MCP endpoint
`https://mcp.longbridge.com/agent` (`authenticate` tool)
- CLI install docs: document the `--auth-code` fallback when no browser
is available (example code uses base58 format)
- MCP docs: add tip for clients with incomplete OAuth support or no
browser
- Skill references (`setup.md` / `mcp.md`): auth-code flow for headless
agents
- AppNav: add "Connect AI" entry to the avatar dropdown menu
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Summary
- Add **CLI v0.22.4** release notes: `constituent` now supports ETFs —
asset-allocation breakdown for ETF symbols, and full US ETF holdings
fetched from SEC EDGAR N-PORT filings
(longbridge/longbridge-terminal#229, longbridge/longbridge-terminal#231)
- Document the new ETF holdings behavior in the `constituent` command
page (usage examples, SEC N-PORT output sample, fallback chain,
data-timeliness notes)
- Backfill missing changelog entries for CLI v0.22.2 / v0.22.3, and add
v0.22.4
- All three locales (en / zh-CN / zh-HK) updated in sync; Chinese docs
formatted with `autocorrect --fix`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Inject the `google-one-tap.es.js` CDN bundle into every page <head> via
VitePress `head` config, so it loads in both `bun run dev` and built
output (works around `transformHtml` being build-only).
- Gated by `VITE_REGION !== 'cn'` (Google unavailable in China).
- `data-proxy` attribute driven by `process.env.PROXY`: `canary` for
`dev:canary` / `build:canary`, otherwise `production`. CI inherits via
the same npm scripts — no workflow edits required.
- No `data-region` passed: the bundle falls back to `app-id` / `region`
cookies with `sg` default, which is correct for this first-party
`.longbridge.com` site.
- On success the bundle writes session cookies on `.longbridge.com` and
reloads, so `longportInternal.isLogin()` picks it up.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
## Summary
- Add `docs/{en,zh-CN,zh-HK}/docs/legal/` directory with
`_category_.json` (position 8, collapsed)
- Add HK and SG versions of User Data Authorisation and Acknowledgement
in three languages (6 files total)
- Add links in `AppFooter.vue` Legal section pointing to the two new
pages
- Add i18n translation keys (`footer.dataAuthorisationHK` /
`footer.dataAuthorisationSG`) for all three locales
- Use `sidebar_label` for shorter sidebar display names
## Test plan
- [ ] Sidebar shows "Legal" section (collapsed) with "Data Authorisation
(HK)" and "Data Authorisation (SG)"
- [ ] Each page renders the full legal text correctly in all three
languages
- [ ] Footer Legal section shows two new links; clicking navigates to
the correct pages
- [ ] `localePath()` correctly prefixes `/zh-CN/` and `/zh-HK/` for
non-English locales
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
Two issues fixed in the DCA documentation (all 3 locales: zh-CN, zh-HK,
en):
1. **SDKLinks method names were wrong** — the `<SDKLinks>` components
referenced non-existent method names, causing broken SDK code links
2. **`delete_dca.md` removed** — the SDK has no `delete` method; the CLI
example on that page already used `dca stop`, so the page was redundant
with `stop_dca.md`
## SDKLinks fixes
| File | Before | After |
|------|--------|-------|
| `list_dca.md` | `method="list_dca"` | `method="list"` |
| `create_dca.md` | `method="create_dca"` | `method="create"` |
| `update_dca.md` | `method="update_dca"` | `method="update"` |
| `dca_history.md` | `method="dca_history"` | `method="history"` |
Already correct (no change): `pause`, `resume`, `stop`, `stats`,
`check_support`, `calc_date`, `set_reminder`
## Removed files (3 locales)
- `docs/{locale}/docs/account/dca/delete_dca.md` — SDK has no `delete`
method; functionality is covered by `stop_dca.md`
## Test plan
- [x] `autocorrect --lint docs/` — no issues ✅
- [x] Local dev server verified (`npm run dev`) ✅🤖 Generated with [Claude Code](https://claude.com/claude-code)
## Summary
- **AppNav**: Replace `localePath('/login')` with
`createLoginRedirectPath()` + `target="_self"` on the Get Started button
— bypasses VitePress SPA router interception so the browser navigates to
the server-side `/login` route with proper `redirect_to` params
- **AppFooter**: Replace placeholder `href="#"` on Terms / Privacy /
Risk Disclosure links with real Longbridge URLs, using locale-aware
`sgBaseUrl`
## Test plan
- [ ] Click "Get Started" in navbar → should navigate to login page (not
VitePress 404)
- [ ] After login, should redirect back to the originating page
- [ ] Footer legal links open correct Longbridge support pages in new
tab
- [ ] Locale switching (zh-CN / zh-HK) uses correct sgBaseUrl prefix for
footer links
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>