@bluelamp/cli-token
v1.2.0
Published
BlueLamp CLI が保存するローカルトークンファイルの読み書きの単一実装
Readme
@bluelamp/cli-token
BlueLamp CLI がローカルに保存するトークンファイル(~/.musuhi/portal-token.enc)の
読み書きの単一実装。
以前はこの処理が配布パッケージごとに複製されており、変更するたびに全複製を同時に 書き換える必要があった(板#324)。複製をやめ、ここを唯一の import 元にする。
使い方
import { readCliTokenSync, tryReadCliToken } from '@bluelamp/cli-token';
// 読めなければ例外(再ログインを促したい呼び出し側向け)
const token = readCliTokenSync();
// 読めなければ null(「未設定」と同じに倒したい呼び出し側向け)
const maybe = tryReadCliToken();失敗時の返し方が 2 種類あるのは、既存の消費側で挙動が分かれていたため。 片方に寄せると呼び出し側の挙動が変わるので、両方を提供している。
API
| 種別 | 関数 |
|---|---|
| core(I/O なし) | encryptPayload / decryptPayload / extractToken / validateTokenFormat |
| shell(I/O あり) | getTokenFilePath / readCliTokenSync / tryReadCliToken / loadPortalToken / savePortalToken / deletePortalToken |
| 艦隊の資格の門(1.1.0・n=2607) | checkFleetGate / isAllowedForScope / getFleetEntitlementFilePath / getFleetGateLogPath / formatFleetGateLogLine / fleetGateRefusalMessage / parseFleetEntitlementCache / isFleetEntitlementFresh |
| 交換済み JWT の機体共有キャッシュ(1.2.0・n=2774) | getExchangedJwt / evictExchangedJwt / exchangedJwtCacheKey / getExchangedJwtCacheDir / parseCachedExchangedJwt / isCachedExchangedJwtUsable |
艦隊の資格の門(checkFleetGate)
席を立てる手元の起点(orchestrator の spawn・scheduler/routine の発火)が通る唯一の判定。
口は GET {BLUELAMP_PORTAL_API_BASE_URL}/cli/fleet-entitlement(X-CLI-Token)、答えは ~/.bluelamp/fleet-entitlement.json に 24 時間キャッシュ。
- 新しいキャッシュが在れば網に出ない。古い/無ければ 1 回だけ聞く(5 秒で打ち切り)
- 書くのは
active/cancelledだけ。網の不調・5xx・401・404・unknownは前回の答え、前回も無ければ通す(fail-open) - 止める(
allowed: false)のはcancelledだけ。返り{allowed, status, reason, from: "cache"|"network"|"stale"|"none"} - 網に出た回(from が cache 以外)だけ
~/.bluelamp/fleet-gate.logに 1 行追記({ts, caller, from, status, reason}・トークンと URL は載せない・1MB を超えたら新しい側の半分に詰める)。callerはorchestrator/scheduler/routine/server scope(既定"fleet"):fleet=cancelled なら止める(orchestrator・scheduler)。member=cancelled でも理由がno_seat・rank_below_minなら止めない(routine=初伝にも配る。席が丸ごと落ちた・退会・期限切れの時だけ止める)。キャッシュと口は 1 つのまま- throw しない。止めた時の文面は
fleetGateRefusalMessage(reason)(固定)
交換済み JWT の機体共有キャッシュ(getExchangedJwt)
艦隊の手足(monster-orchestrator・scheduler・routine)が POST {bluelamp}/auth/exchange で取る 10 分の JWT を、期限まで機体で共有する。
以前はプロセスのメモリにだけ持っていたので、発火のたびに立つ fire.js は毎回 exchange し、毎時 :00 に揃っていた(2026-10-09 実測 636 件・p50 6.3 秒)。
- 置き場
~/.bluelamp/jwt-cache/<鍵>.json(ファイル 600・ディレクトリ 700。BLUELAMP_JWT_CACHE_DIRで差し替え=消費側のテスト用)。自分だけが読めるファイルしか信じない - 鍵は「口・mcp_id・scope の組・CLI トークンの指紋」の sha256。JWT は
bl:mcp_idを持つので MCP をまたいで共有しない。CLI トークンはファイルに書かない - 取り直すのは期限の 60 秒前から。同時に切れた N プロセスは
<鍵>.json.lock(O_EXCL)を取った 1 本だけが撃ち、他はファイルを待つ(既定 5 秒・過ぎたら自分で撃つ)。30 秒より古いロックは持ち主が死んだと読んで払う - 受け手が 401 を返したら
evictExchangedJwt(key, 拒まれた JWT)→ もう一度getExchangedJwt(中身が同じ JWT のときだけ消す) - キャッシュの不調(読めない・書けない・ロックが取れない)は exchange に倒す。exchange の失敗だけは throw のまま返す
制約
- node 標準モジュール以外に依存しない(VSCode 拡張が webpack で bundle するため)。
- i18n / console 出力をしない。利用者への通知は呼び出し側の責務。
開発
pnpm --filter @bluelamp/cli-token build
pnpm --filter @bluelamp/cli-token testテストは、このパッケージが既存の配布済み実装と相互に読めることを対照に取る (自分で暗号化して自分で復号するだけでは、手順ごと取り違えていても緑になるため)。
