Files
alex 93176c0eb1 feat: 實作 bear CLI 骨架與 PAT 模式共用基礎(issue #6)
- 專案骨架:Elixir + Mix escript(單檔可執行 bear),HTTP 一律 Req
- 設定/憑證檔讀寫:0600、原子寫入(rename)、O_CREAT|O_EXCL 防 symlink
- PAT Bearer 呼叫 /userinfo;--json 輸出;規格化退出碼
- 補齊 main 規格承諾的 BEAR_TOKEN 環境變數(優先於憑證檔、不寫入)
- login 無效 PAT 退出碼 3(依 docs/commands.md §3.1);token --refresh 用法錯誤 2(§3.3)
- 35 個單元測試;mix precommit(compile --warnings-as-errors + format + test)全綠
- 沿用已關閉 PR #3 的實作(feat/pat-mode-mvp 分支),文件改依 main 現行版本更新

apps 管理指令待 #5 規格與 alterminal/bear#28 API 就緒後實作。
2026-09-07 22:59:05 +08:00

97 lines
2.4 KiB
Elixir
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
defmodule BearCli.Config do
@moduledoc """
設定檔與憑證檔的路徑及讀取。
設定優先序:CLI flag > 環境變數(`BEAR_ISSUER`)> 設定檔 > 內建預設。
"""
@default_issuer "https://alterminal.com"
@doc "內建預設 issuer。"
def default_issuer, do: @default_issuer
@doc """
設定檔路徑:`~/.config/bear/config.json`(可用 `BEAR_CONFIG` 覆寫)。
"""
def config_path do
System.get_env("BEAR_CONFIG") || Path.join(config_home(), "config.json")
end
@doc """
憑證檔路徑:`~/.local/state/bear/credentials.json`(可用 `BEAR_CREDENTIALS` 覆寫)。
"""
def credentials_path do
System.get_env("BEAR_CREDENTIALS") || Path.join(state_home(), "credentials.json")
end
defp config_home do
base =
System.get_env("XDG_CONFIG_HOME") ||
Path.join(System.user_home!(), ".config")
Path.join(base, "bear")
end
defp state_home do
base =
System.get_env("XDG_STATE_HOME") ||
Path.join(System.user_home!(), ".local/state")
Path.join(base, "bear")
end
@doc """
讀取設定檔,回傳 `{:ok, map}` 或 `:error`(檔案不存在/JSON 損毀)。
"""
def read_config(path \\ config_path()) do
case File.read(path) do
{:ok, content} -> Jason.decode(content)
{:error, _} -> :error
end
end
@doc """
解析最終 issuer,依序取第一個非空白值:
1. `cli_issuer`(`--issuer` flag)
2. `BEAR_ISSUER` 環境變數
3. 設定檔的 `issuer` 欄位(讀自 `config_path_override` 或預設路徑)
4. 內建預設 `https://alterminal.com`
"""
def resolve_issuer(cli_issuer, config_path_override \\ nil) do
path = config_path_override || config_path()
config =
case read_config(path) do
{:ok, map} when is_map(map) -> map
_ -> %{}
end
Enum.find(
[
cli_issuer,
System.get_env("BEAR_ISSUER"),
config["issuer"],
@default_issuer
],
&(not blank?(&1))
)
end
@doc """
`BEAR_TOKEN` 環境變數(一次性/CI 用的 PAT)。
提供後優先於本機憑證檔,但不寫入憑證檔。空值或純空白視為未提供。
"""
def env_token do
case System.get_env("BEAR_TOKEN") do
nil -> nil
token -> if blank?(String.trim(token)), do: nil, else: String.trim(token)
end
end
defp blank?(nil), do: true
defp blank?(""), do: true
defp blank?(_), do: false
end