@raingor/pi-web-switch 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,6 +27,7 @@ import {
27
27
  CloudDownload,
28
28
  RefreshCw,
29
29
  ZoomIn,
30
+ KeyRound,
30
31
  } from "lucide-react";
31
32
 
32
33
  type SettingsTab = "appearance" | "models" | "advanced";
@@ -116,6 +117,37 @@ export function SettingsPage() {
116
117
  const [updateError, setUpdateError] = useState(false);
117
118
  const [applying, setApplying] = useState(false);
118
119
  const [applyMessage, setApplyMessage] = useState<{ ok: number; failNames: string[] } | null>(null);
120
+ // GitHub Copilot usage API config (username + classic PAT).
121
+ const [copilotCfg, setCopilotCfg] = useState<{ username: string; token: string }>({ username: "", token: "" });
122
+ const [copilotSaving, setCopilotSaving] = useState(false);
123
+ const [copilotMsg, setCopilotMsg] = useState<{ ok: boolean; text: string } | null>(null);
124
+
125
+ useEffect(() => {
126
+ fetch("/api/pi/copilot-config")
127
+ .then((r) => r.json())
128
+ .then((cfg: { username?: string; token?: string }) =>
129
+ setCopilotCfg({ username: cfg.username ?? "", token: cfg.token ?? "" })
130
+ )
131
+ .catch(() => {});
132
+ }, []);
133
+
134
+ const handleSaveCopilot = async () => {
135
+ setCopilotSaving(true);
136
+ setCopilotMsg(null);
137
+ try {
138
+ const res = await fetch("/api/pi/copilot-config", {
139
+ method: "POST",
140
+ headers: { "Content-Type": "application/json" },
141
+ body: JSON.stringify(copilotCfg),
142
+ });
143
+ const { success } = (await res.json()) as { success: boolean };
144
+ setCopilotMsg({ ok: !!success, text: success ? t("settings.copilot_saved") : t("settings.copilot_save_failed") });
145
+ } catch {
146
+ setCopilotMsg({ ok: false, text: t("settings.copilot_save_failed") });
147
+ } finally {
148
+ setCopilotSaving(false);
149
+ }
150
+ };
119
151
 
120
152
  const handleCheckUpdates = async () => {
121
153
  setCheckingUpdates(true);
@@ -563,6 +595,46 @@ export function SettingsPage() {
563
595
  })()}
564
596
  </Card>
565
597
 
598
+ <Card icon={KeyRound} title={t("settings.copilot_title")} desc={t("settings.copilot_desc")}>
599
+ <div className="max-w-md space-y-3">
600
+ <div>
601
+ <label className="mb-1 block text-xs text-gray-500">{t("settings.copilot_username")}</label>
602
+ <input
603
+ type="text"
604
+ value={copilotCfg.username}
605
+ onChange={(e) => setCopilotCfg({ ...copilotCfg, username: e.target.value })}
606
+ placeholder="octocat"
607
+ className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-sm text-white placeholder-gray-600"
608
+ />
609
+ </div>
610
+ <div>
611
+ <label className="mb-1 block text-xs text-gray-500">{t("settings.copilot_token")}</label>
612
+ <input
613
+ type="password"
614
+ value={copilotCfg.token}
615
+ onChange={(e) => setCopilotCfg({ ...copilotCfg, token: e.target.value })}
616
+ placeholder="ghp_…"
617
+ className="w-full rounded-lg border border-gray-700 bg-gray-800 px-3 py-1.5 text-sm text-white placeholder-gray-600"
618
+ />
619
+ </div>
620
+ <div className="flex items-center gap-3">
621
+ <button
622
+ onClick={handleSaveCopilot}
623
+ disabled={copilotSaving}
624
+ className="flex items-center gap-1.5 rounded-lg border border-gray-700 bg-gray-800 px-4 py-1.5 text-sm text-gray-300 hover:bg-gray-700 disabled:opacity-60"
625
+ >
626
+ {copilotSaving ? t("settings.copilot_saving") : t("settings.copilot_save")}
627
+ </button>
628
+ {copilotMsg && (
629
+ <span className={cn("text-xs", copilotMsg.ok ? "text-emerald-400" : "text-red-400")}>
630
+ {copilotMsg.text}
631
+ </span>
632
+ )}
633
+ </div>
634
+ <p className="text-[11px] leading-relaxed text-gray-500">{t("settings.copilot_token_hint")}</p>
635
+ </div>
636
+ </Card>
637
+
566
638
  <Card icon={Package} title={t("settings.packages")}>
567
639
  {(settings?.packages ?? []).length > 0 && (
568
640
  <div className="mb-4 flex flex-wrap gap-1.5">
@@ -64,7 +64,6 @@ const en: Record<string, string> = {
64
64
 
65
65
  "nav.sessions": "Sessions",
66
66
  "nav.memory": "Memory",
67
- "nav.chat": "Chat",
68
67
  "nav.settings": "Settings",
69
68
  "app.subtitle": "Configuration Manager",
70
69
  "app.version": "pi-switch v0.1.0",
@@ -110,6 +109,10 @@ const en: Record<string, string> = {
110
109
  "dashboard.source_opencode": "OpenCode",
111
110
  "dashboard.source_gemini": "Gemini",
112
111
  "dashboard.source_grok": "Grok",
112
+ "dashboard.source_atomcode": "AtomCode",
113
+ "dashboard.source_copilot": "Copilot",
114
+ "dashboard.copilot_not_configured": "GitHub Copilot not configured — add username & token in Settings → Advanced",
115
+ "dashboard.copilot_api_error": "Failed to fetch Copilot usage from GitHub API — check token and billing platform",
113
116
  "dashboard.requests_count": "{0} requests · {1} total cost",
114
117
  "dashboard.range.today": "Today",
115
118
  "dashboard.range.7d": "7 Days",
@@ -200,6 +203,8 @@ const en: Record<string, string> = {
200
203
  "compat.desc": "Override default behavior for OpenAI-compatible providers that don't support certain features.",
201
204
  "compat.supports_developer_role": "Supports developer role",
202
205
  "compat.supports_developer_role_desc": "Send system prompt as 'developer' role (for reasoning models). Disable if the API only accepts 'system' role.",
206
+ "compat.supports_finish_reason": "Strict finish_reason check",
207
+ "compat.supports_finish_reason_desc": "Require streamed responses to include finish_reason, otherwise fail. Disable to infer the stop reason automatically when the upstream drops the stream (common with free models).",
203
208
  "compat.supports_reasoning_effort": "Supports reasoning_effort",
204
209
  "compat.supports_reasoning_effort_desc": "Send reasoning_effort parameter. Disable if the API does not support it.",
205
210
 
@@ -302,6 +307,15 @@ const en: Record<string, string> = {
302
307
  "settings.ui_zoom_desc": "Scale the entire interface by percentage (50%–200%)",
303
308
  "settings.ui_zoom_reset": "Reset",
304
309
  "settings.enabled_models_desc": "Click a tag to enable or disable a model",
310
+ "settings.copilot_title": "GitHub Copilot",
311
+ "settings.copilot_desc": "Track Copilot usage from the GitHub billing API (premium requests / AI credits)",
312
+ "settings.copilot_username": "GitHub username",
313
+ "settings.copilot_token": "Token (classic PAT)",
314
+ "settings.copilot_save": "Save",
315
+ "settings.copilot_saving": "Saving…",
316
+ "settings.copilot_saved": "Saved — usage will refresh on next dashboard load",
317
+ "settings.copilot_save_failed": "Save failed",
318
+ "settings.copilot_token_hint": "Create a classic personal access token at github.com/settings/tokens (fine-grained tokens are not supported by the billing usage endpoints). Copilot usage only appears for accounts on the enhanced billing platform.",
305
319
  "settings.updates_title": "Update Check",
306
320
  "settings.updates_desc": "Check npm for new versions of pi core and installed extensions.",
307
321
  "settings.check_updates": "Check for Updates",
@@ -350,63 +364,6 @@ const en: Record<string, string> = {
350
364
  "loading.error_title": "Failed to Load Configuration",
351
365
  "loading.retry": "Retry",
352
366
 
353
- // Chat
354
- "chat.sessions": "Sessions",
355
- "chat.new_session": "New session",
356
- "chat.loading": "Loading...",
357
- "chat.no_sessions": "No sessions yet. Click + to start a new chat.",
358
- "chat.welcome_title": "Welcome to Pi Chat",
359
- "chat.welcome_desc": "Select a session from the sidebar, or click + to start a new chat session in a project directory.",
360
- "chat.select_cwd": "Select Working Directory",
361
- "chat.cancel": "Cancel",
362
- "chat.start_chat": "Start Chat",
363
- "chat.delete_confirm": "Delete this session? This cannot be undone.",
364
- "chat.delete": "Delete",
365
- "chat.loading_session": "Loading session...",
366
- "chat.thinking": "Thinking...",
367
- "chat.running_tool": "Running tool...",
368
- "chat.running_command": "Running command...",
369
- "chat.send_message": "Send a message... (/ for commands, ! for bash)",
370
- "chat.type_to_steer": "Type to steer...",
371
- "chat.compacting": "Compacting context...",
372
- "chat.compaction_failed": "Compaction failed: {0}",
373
- "chat.retrying": "Retrying ({0}/{1}){2}",
374
- "chat.steering_queued": "{0} steering, {1} follow-up queued",
375
- "chat.recall": "Recall",
376
- "chat.default_tools": "Default tools",
377
- "chat.all_tools": "All tools",
378
- "chat.no_tools": "No tools",
379
- "chat.auto": "Auto",
380
- "chat.no_model": "No model",
381
- "chat.no_models_available": "No models available. Check your model configuration.",
382
- "chat.search_models": "Search models...",
383
- "chat.no_models_found": "No models found",
384
- "chat.models_count": "{0} models",
385
- "chat.models_filtered": "{0} of {1} models",
386
- "chat.attach_image": "Attach image",
387
- "chat.tool_preset": "Tool preset",
388
- "chat.compact_context": "Compact context",
389
- "chat.stop": "Stop",
390
- "chat.send": "Send",
391
- "chat.fork_from_here": "Fork from here",
392
- "chat.show_less": "Show less",
393
- "chat.show_more": "Show {0} more characters",
394
- "chat.tool_call": "tool call",
395
- "chat.thinking_collapsed": "Thinking (collapsed)",
396
- "chat.thinking_label": "Thinking",
397
- "chat.result": "result",
398
- "chat.error_label": "(error)",
399
- "chat.exit_code": "exit",
400
- "chat.msg_count": "{0} msg",
401
- "chat.untitled": "Untitled",
402
- "chat.just_now": "just now",
403
- "chat.min_ago": "{0}m ago",
404
- "chat.hr_ago": "{0}h ago",
405
- "chat.day_ago": "{0}d ago",
406
- "chat.invalid_directory": "Invalid directory",
407
- "chat.expand_all": "Expand all",
408
- "chat.collapse_all": "Collapse all",
409
-
410
367
  // Language Switcher
411
368
  "language.label": "Language",
412
369
  "language.en": "English",
@@ -62,7 +62,6 @@ const ja: Record<string, string> = {
62
62
 
63
63
  "nav.sessions": "セッション",
64
64
  "nav.memory": "メモリ",
65
- "nav.chat": "チャット",
66
65
  "nav.settings": "設定",
67
66
  "app.subtitle": "設定マネージャー",
68
67
  "app.version": "pi-switch v0.1.0",
@@ -107,6 +106,10 @@ const ja: Record<string, string> = {
107
106
  "dashboard.source_opencode": "OpenCode",
108
107
  "dashboard.source_gemini": "Gemini",
109
108
  "dashboard.source_grok": "Grok",
109
+ "dashboard.source_atomcode": "AtomCode",
110
+ "dashboard.source_copilot": "Copilot",
111
+ "dashboard.copilot_not_configured": "GitHub Copilot 未設定 — 設定 → 詳細設定 でユーザー名とトークンを入力してください",
112
+ "dashboard.copilot_api_error": "GitHub API から Copilot 使用量を取得できませんでした — トークンと請求プラットフォームを確認してください",
110
113
  "dashboard.requests_count": "{0} リクエスト · 総コスト {1}",
111
114
  "dashboard.range.today": "今日",
112
115
  "dashboard.range.7d": "7日",
@@ -196,6 +199,8 @@ const ja: Record<string, string> = {
196
199
  "compat.desc": "OpenAI 互換 API が一部の機能をサポートしていない場合の動作を上書きします。",
197
200
  "compat.supports_developer_role": "developer ロールをサポート",
198
201
  "compat.supports_developer_role_desc": "システムプロンプトを 'developer' ロールで送信(推論モデル)。API が 'system' ロールのみ受け付ける場合は無効にしてください。",
202
+ "compat.supports_finish_reason": "finish_reason の厳格な検証",
203
+ "compat.supports_finish_reason_desc": "ストリーム応答に finish_reason の含有を必須にし、無ければエラーにします。上流がストリームを途中で切断する場合(無料モデルに多い)は無効にして終了理由の自動判定に切り替えてください。",
199
204
  "compat.supports_reasoning_effort": "reasoning_effort をサポート",
200
205
  "compat.supports_reasoning_effort_desc": "reasoning_effort パラメータを送信します。API がサポートしていない場合は無効にしてください。",
201
206
 
@@ -294,6 +299,15 @@ const ja: Record<string, string> = {
294
299
  "settings.ui_zoom_desc": "インターフェース全体をパーセントで拡大縮小(50%–200%)",
295
300
  "settings.ui_zoom_reset": "リセット",
296
301
  "settings.enabled_models_desc": "タグをクリックしてモデルを切り替え",
302
+ "settings.copilot_title": "GitHub Copilot",
303
+ "settings.copilot_desc": "GitHub 課金 API から Copilot の使用量を取得(premium requests / AI credits)",
304
+ "settings.copilot_username": "GitHub ユーザー名",
305
+ "settings.copilot_token": "Token(classic PAT)",
306
+ "settings.copilot_save": "保存",
307
+ "settings.copilot_saving": "保存中…",
308
+ "settings.copilot_saved": "保存しました — 次回ダッシュボード読み込み時に反映されます",
309
+ "settings.copilot_save_failed": "保存に失敗しました",
310
+ "settings.copilot_token_hint": "github.com/settings/tokens で classic personal access token を作成してください(課金 usage エンドポイントは fine-grained 非対応)。Copilot 使用量は拡張課金プラットフォームのアカウントのみ表示されます。",
297
311
  "settings.updates_title": "アップデート確認",
298
312
  "settings.updates_desc": "pi 本体と拡張に npm 上の新バージョンがあるか確認します。",
299
313
  "settings.check_updates": "更新を確認",
@@ -341,63 +355,6 @@ const ja: Record<string, string> = {
341
355
  "loading.error_title": "設定の読み込みに失敗しました",
342
356
  "loading.retry": "再試行",
343
357
 
344
- // Chat
345
- "chat.sessions": "セッション",
346
- "chat.new_session": "新規セッション",
347
- "chat.loading": "読み込み中...",
348
- "chat.no_sessions": "セッションがありません。+ をクリックして新しいチャットを開始してください。",
349
- "chat.welcome_title": "Pi Chat へようこそ",
350
- "chat.welcome_desc": "サイドバーからセッションを選択するか、+ をクリックしてプロジェクトディレクトリで新しいチャットを開始します。",
351
- "chat.select_cwd": "作業ディレクトリを選択",
352
- "chat.cancel": "キャンセル",
353
- "chat.start_chat": "チャット開始",
354
- "chat.delete_confirm": "このセッションを削除しますか?この操作は元に戻せません。",
355
- "chat.delete": "削除",
356
- "chat.loading_session": "セッションを読み込み中...",
357
- "chat.thinking": "考え中...",
358
- "chat.running_tool": "ツールを実行中...",
359
- "chat.running_command": "コマンドを実行中...",
360
- "chat.send_message": "メッセージを送信...(/ でコマンド、! で bash)",
361
- "chat.type_to_steer": "入力して誘導...",
362
- "chat.compacting": "コンテキストを圧縮中...",
363
- "chat.compaction_failed": "圧縮失敗:{0}",
364
- "chat.retrying": "再試行中 ({0}/{1}){2}",
365
- "chat.steering_queued": "{0} 件の誘導、{1} 件のフォローアップがキューにあります",
366
- "chat.recall": "取り消す",
367
- "chat.default_tools": "デフォルトツール",
368
- "chat.all_tools": "すべてのツール",
369
- "chat.no_tools": "ツールなし",
370
- "chat.auto": "自動",
371
- "chat.no_model": "モデルなし",
372
- "chat.no_models_available": "利用可能なモデルがありません。モデル設定を確認してください。",
373
- "chat.search_models": "モデルを検索...",
374
- "chat.no_models_found": "モデルが見つかりません",
375
- "chat.models_count": "{0} モデル",
376
- "chat.models_filtered": "{0} / {1} モデル",
377
- "chat.attach_image": "画像を添付",
378
- "chat.tool_preset": "ツールプリセット",
379
- "chat.compact_context": "コンテキストを圧縮",
380
- "chat.stop": "停止",
381
- "chat.send": "送信",
382
- "chat.fork_from_here": "ここから分岐",
383
- "chat.show_less": "折りたたむ",
384
- "chat.show_more": "残り {0} 文字を表示",
385
- "chat.tool_call": "ツール呼び出し",
386
- "chat.thinking_collapsed": "思考(折りたたみ)",
387
- "chat.thinking_label": "思考",
388
- "chat.result": "結果",
389
- "chat.error_label": "(エラー)",
390
- "chat.exit_code": "終了コード",
391
- "chat.msg_count": "{0} 件",
392
- "chat.untitled": "無題",
393
- "chat.just_now": "たった今",
394
- "chat.min_ago": "{0} 分前",
395
- "chat.hr_ago": "{0} 時間前",
396
- "chat.day_ago": "{0} 日前",
397
- "chat.invalid_directory": "無効なディレクトリ",
398
- "chat.expand_all": "すべて展開",
399
- "chat.collapse_all": "すべて折りたたむ",
400
-
401
358
  "language.label": "言語",
402
359
  "language.en": "English",
403
360
  "language.zh-CN": "简体中文",
@@ -62,7 +62,6 @@ const zhCN: Record<string, string> = {
62
62
 
63
63
  "nav.sessions": "会话",
64
64
  "nav.memory": "记忆",
65
- "nav.chat": "聊天",
66
65
  "nav.settings": "设置",
67
66
  "app.subtitle": "配置管理器",
68
67
  "app.version": "pi-switch v0.1.0",
@@ -107,6 +106,10 @@ const zhCN: Record<string, string> = {
107
106
  "dashboard.source_opencode": "OpenCode",
108
107
  "dashboard.source_gemini": "Gemini",
109
108
  "dashboard.source_grok": "Grok",
109
+ "dashboard.source_atomcode": "AtomCode",
110
+ "dashboard.source_copilot": "Copilot",
111
+ "dashboard.copilot_not_configured": "GitHub Copilot 未配置 — 请在 设置 → 高级 中填写用户名与 Token",
112
+ "dashboard.copilot_api_error": "从 GitHub API 获取 Copilot 用量失败 — 请检查 Token 与计费平台",
110
113
  "dashboard.requests_count": "{0} 次请求 · 总成本 {1}",
111
114
  "dashboard.range.today": "当天",
112
115
  "dashboard.range.7d": "7天",
@@ -196,6 +199,8 @@ const zhCN: Record<string, string> = {
196
199
  "compat.desc": "当 OpenAI 兼容 API 不支持某些功能时,覆盖默认行为。",
197
200
  "compat.supports_developer_role": "支持 developer 角色",
198
201
  "compat.supports_developer_role_desc": "使用 'developer' 角色发送系统提示(推理模型)。如果不支持,请关闭以改用 'system' 角色。",
202
+ "compat.supports_finish_reason": "严格校验 finish_reason",
203
+ "compat.supports_finish_reason_desc": "要求流式响应必须包含 finish_reason,否则报错。上游偶尔掐断流(免费模型常见)时,请关闭以改为自动推断结束原因。",
199
204
  "compat.supports_reasoning_effort": "支持 reasoning_effort",
200
205
  "compat.supports_reasoning_effort_desc": "发送 reasoning_effort 参数。如果 API 不支持,请关闭。",
201
206
 
@@ -294,6 +299,15 @@ const zhCN: Record<string, string> = {
294
299
  "settings.ui_zoom_desc": "按百分比缩放整个界面(50%–200%)",
295
300
  "settings.ui_zoom_reset": "重置",
296
301
  "settings.enabled_models_desc": "点击标签以启用或禁用模型",
302
+ "settings.copilot_title": "GitHub Copilot",
303
+ "settings.copilot_desc": "通过 GitHub 计费 API 统计 Copilot 用量(premium requests / AI credits)",
304
+ "settings.copilot_username": "GitHub 用户名",
305
+ "settings.copilot_token": "Token(classic PAT)",
306
+ "settings.copilot_save": "保存",
307
+ "settings.copilot_saving": "保存中…",
308
+ "settings.copilot_saved": "已保存 — 下次打开仪表盘时刷新用量",
309
+ "settings.copilot_save_failed": "保存失败",
310
+ "settings.copilot_token_hint": "在 github.com/settings/tokens 创建 classic 个人访问令牌(计费用量接口不支持 fine-grained token)。仅增强计费平台的账号会显示 Copilot 用量。",
297
311
  "settings.updates_title": "更新检测",
298
312
  "settings.updates_desc": "检查 pi 本体与扩展在 npm 上是否有新版本。",
299
313
  "settings.check_updates": "检查更新",
@@ -341,63 +355,6 @@ const zhCN: Record<string, string> = {
341
355
  "loading.error_title": "加载配置失败",
342
356
  "loading.retry": "重试",
343
357
 
344
- // Chat
345
- "chat.sessions": "会话",
346
- "chat.new_session": "新建会话",
347
- "chat.loading": "加载中...",
348
- "chat.no_sessions": "暂无会话。点击 + 开始新对话。",
349
- "chat.welcome_title": "欢迎使用 Pi Chat",
350
- "chat.welcome_desc": "从侧栏选择一个会话,或点击 + 在项目目录中开始新的对话。",
351
- "chat.select_cwd": "选择工作目录",
352
- "chat.cancel": "取消",
353
- "chat.start_chat": "开始对话",
354
- "chat.delete_confirm": "确定删除此会话?此操作无法撤销。",
355
- "chat.delete": "删除",
356
- "chat.loading_session": "正在加载会话...",
357
- "chat.thinking": "思考中...",
358
- "chat.running_tool": "正在运行工具...",
359
- "chat.running_command": "正在执行命令...",
360
- "chat.send_message": "发送消息...(/ 选择命令,! 执行命令)",
361
- "chat.type_to_steer": "输入以引导...",
362
- "chat.compacting": "正在压缩上下文...",
363
- "chat.compaction_failed": "压缩失败:{0}",
364
- "chat.retrying": "重试中 ({0}/{1}){2}",
365
- "chat.steering_queued": "{0} 条引导,{1} 条跟进已排队",
366
- "chat.recall": "撤回",
367
- "chat.default_tools": "默认工具",
368
- "chat.all_tools": "全部工具",
369
- "chat.no_tools": "无工具",
370
- "chat.auto": "自动",
371
- "chat.no_model": "无模型",
372
- "chat.no_models_available": "暂无可用模型,请检查模型配置。",
373
- "chat.search_models": "搜索模型...",
374
- "chat.no_models_found": "未找到模型",
375
- "chat.models_count": "{0} 个模型",
376
- "chat.models_filtered": "{0} / {1} 个模型",
377
- "chat.attach_image": "附加图片",
378
- "chat.tool_preset": "工具预设",
379
- "chat.compact_context": "压缩上下文",
380
- "chat.stop": "停止",
381
- "chat.send": "发送",
382
- "chat.fork_from_here": "从此处分叉",
383
- "chat.show_less": "收起",
384
- "chat.show_more": "展开剩余 {0} 个字符",
385
- "chat.tool_call": "工具调用",
386
- "chat.thinking_collapsed": "思考(已折叠)",
387
- "chat.thinking_label": "思考",
388
- "chat.result": "结果",
389
- "chat.error_label": "(错误)",
390
- "chat.exit_code": "退出码",
391
- "chat.msg_count": "{0} 条消息",
392
- "chat.untitled": "未命名",
393
- "chat.just_now": "刚刚",
394
- "chat.min_ago": "{0} 分钟前",
395
- "chat.hr_ago": "{0} 小时前",
396
- "chat.day_ago": "{0} 天前",
397
- "chat.invalid_directory": "无效目录",
398
- "chat.expand_all": "全部展开",
399
- "chat.collapse_all": "全部折叠",
400
-
401
358
  "language.label": "语言",
402
359
  "language.en": "English",
403
360
  "language.zh-CN": "简体中文",
@@ -62,7 +62,6 @@ const zhTW: Record<string, string> = {
62
62
 
63
63
  "nav.sessions": "會話",
64
64
  "nav.memory": "記憶",
65
- "nav.chat": "聊天",
66
65
  "nav.settings": "設定",
67
66
  "app.subtitle": "設定管理器",
68
67
  "app.version": "pi-switch v0.1.0",
@@ -107,6 +106,10 @@ const zhTW: Record<string, string> = {
107
106
  "dashboard.source_opencode": "OpenCode",
108
107
  "dashboard.source_gemini": "Gemini",
109
108
  "dashboard.source_grok": "Grok",
109
+ "dashboard.source_atomcode": "AtomCode",
110
+ "dashboard.source_copilot": "Copilot",
111
+ "dashboard.copilot_not_configured": "GitHub Copilot 未設定 — 請在 設定 → 進階 中填寫使用者名稱與 Token",
112
+ "dashboard.copilot_api_error": "從 GitHub API 取得 Copilot 用量失敗 — 請檢查 Token 與計費平台",
110
113
  "dashboard.requests_count": "{0} 次請求 · 總成本 {1}",
111
114
  "dashboard.range.today": "當天",
112
115
  "dashboard.range.7d": "7天",
@@ -196,6 +199,8 @@ const zhTW: Record<string, string> = {
196
199
  "compat.desc": "當 OpenAI 相容 API 不支援某些功能時,覆蓋預設行為。",
197
200
  "compat.supports_developer_role": "支援 developer 角色",
198
201
  "compat.supports_developer_role_desc": "使用 'developer' 角色發送系統提示(推理模型)。如果不支援,請關閉以改用 'system' 角色。",
202
+ "compat.supports_finish_reason": "嚴格校驗 finish_reason",
203
+ "compat.supports_finish_reason_desc": "要求串流回應必須包含 finish_reason,否則報錯。上游偶爾掐斷串流(免費模型常見)時,請關閉以改為自動推斷結束原因。",
199
204
  "compat.supports_reasoning_effort": "支援 reasoning_effort",
200
205
  "compat.supports_reasoning_effort_desc": "發送 reasoning_effort 參數。如果 API 不支援,請關閉。",
201
206
 
@@ -294,6 +299,15 @@ const zhTW: Record<string, string> = {
294
299
  "settings.ui_zoom_desc": "依百分比縮放整個介面(50%–200%)",
295
300
  "settings.ui_zoom_reset": "重設",
296
301
  "settings.enabled_models_desc": "點擊標籤以啟用或停用模型",
302
+ "settings.copilot_title": "GitHub Copilot",
303
+ "settings.copilot_desc": "透過 GitHub 計費 API 統計 Copilot 用量(premium requests / AI credits)",
304
+ "settings.copilot_username": "GitHub 使用者名稱",
305
+ "settings.copilot_token": "Token(classic PAT)",
306
+ "settings.copilot_save": "儲存",
307
+ "settings.copilot_saving": "儲存中…",
308
+ "settings.copilot_saved": "已儲存 — 下次開啟儀表板時重新整理用量",
309
+ "settings.copilot_save_failed": "儲存失敗",
310
+ "settings.copilot_token_hint": "在 github.com/settings/tokens 建立 classic 個人存取權杖(計費用量 API 不支援 fine-grained token)。僅增強計費平台的帳號會顯示 Copilot 用量。",
297
311
  "settings.updates_title": "更新檢測",
298
312
  "settings.updates_desc": "檢查 pi 本體與擴充在 npm 上是否有新版本。",
299
313
  "settings.check_updates": "檢查更新",
@@ -341,63 +355,6 @@ const zhTW: Record<string, string> = {
341
355
  "loading.error_title": "載入設定失敗",
342
356
  "loading.retry": "重試",
343
357
 
344
- // Chat
345
- "chat.sessions": "會話",
346
- "chat.new_session": "新建會話",
347
- "chat.loading": "載入中...",
348
- "chat.no_sessions": "尚無會話。點擊 + 開始新對話。",
349
- "chat.welcome_title": "歡迎使用 Pi Chat",
350
- "chat.welcome_desc": "從側欄選擇一個會話,或點擊 + 在專案目錄中開始新的對話。",
351
- "chat.select_cwd": "選擇工作目錄",
352
- "chat.cancel": "取消",
353
- "chat.start_chat": "開始對話",
354
- "chat.delete_confirm": "確定刪除此會話?此操作無法復原。",
355
- "chat.delete": "刪除",
356
- "chat.loading_session": "正在載入會話...",
357
- "chat.thinking": "思考中...",
358
- "chat.running_tool": "正在執行工具...",
359
- "chat.running_command": "正在執行指令...",
360
- "chat.send_message": "發送訊息…(/ 選擇指令,! 執行指令)",
361
- "chat.type_to_steer": "輸入以引導...",
362
- "chat.compacting": "正在壓縮上下文...",
363
- "chat.compaction_failed": "壓縮失敗:{0}",
364
- "chat.retrying": "重試中 ({0}/{1}){2}",
365
- "chat.steering_queued": "{0} 條引導,{1} 條跟進已排隊",
366
- "chat.recall": "撤回",
367
- "chat.default_tools": "預設工具",
368
- "chat.all_tools": "全部工具",
369
- "chat.no_tools": "無工具",
370
- "chat.auto": "自動",
371
- "chat.no_model": "無模型",
372
- "chat.no_models_available": "暫無可用模型,請檢查模型配置。",
373
- "chat.search_models": "搜尋模型...",
374
- "chat.no_models_found": "未找到模型",
375
- "chat.models_count": "{0} 個模型",
376
- "chat.models_filtered": "{0} / {1} 個模型",
377
- "chat.attach_image": "附加圖片",
378
- "chat.tool_preset": "工具預設",
379
- "chat.compact_context": "壓縮上下文",
380
- "chat.stop": "停止",
381
- "chat.send": "發送",
382
- "chat.fork_from_here": "從此分叉",
383
- "chat.show_less": "收起",
384
- "chat.show_more": "展開剩餘 {0} 個字元",
385
- "chat.tool_call": "工具呼叫",
386
- "chat.thinking_collapsed": "思考(已摺疊)",
387
- "chat.thinking_label": "思考",
388
- "chat.result": "結果",
389
- "chat.error_label": "(錯誤)",
390
- "chat.exit_code": "退出碼",
391
- "chat.msg_count": "{0} 條訊息",
392
- "chat.untitled": "未命名",
393
- "chat.just_now": "剛剛",
394
- "chat.min_ago": "{0} 分鐘前",
395
- "chat.hr_ago": "{0} 小時前",
396
- "chat.day_ago": "{0} 天前",
397
- "chat.invalid_directory": "無效目錄",
398
- "chat.expand_all": "全部展開",
399
- "chat.collapse_all": "全部摺疊",
400
-
401
358
  "language.label": "語言",
402
359
  "language.en": "English",
403
360
  "language.zh-CN": "简体中文",
@@ -19,6 +19,7 @@ export interface ThinkingLevelMap {
19
19
  export interface ModelCompat {
20
20
  supportsStore?: boolean;
21
21
  supportsDeveloperRole?: boolean;
22
+ supportsFinishReason?: boolean;
22
23
  supportsReasoningEffort?: boolean;
23
24
  supportsUsageInStreaming?: boolean;
24
25
  maxTokensField?: "max_completion_tokens" | "max_tokens";