token-usage-insights 0.9.2 → 0.9.5

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.
package/README.en.md CHANGED
@@ -277,6 +277,8 @@ Usage:
277
277
 
278
278
  The dashboard fully backfills existing `chatSessions` files and resynchronizes them when file size or modification time changes. Chat sessions without token fields are still shown with a token count of 0. Only local chat files are read; cloud sessions, Remote SSH hosts, and `state.vscdb` are not included.
279
279
 
280
+ **Where cache-read tokens come from**: VS Code's `chatSessions` files only persist the `promptTokens` of the last model call in a request plus the accumulated `completionTokens`; they never record prompt-cache reads. The dashboard therefore also reads the Copilot Chat extension debug log written next to them, `GitHub.copilot-chat/debug-logs/<sessionId>/main.jsonl`, sums `inputTokens`, `outputTokens`, and `cachedTokens` across every model call of the turn, and splits the result into non-cached input, cache read, and output tokens so cost estimates use the cache-read rate. The debug log is controlled by the VS Code setting `github.copilot.chat.agentDebugLog.fileLogging.enabled` (already enabled by experiment for some users) and keeps only the 50 most recent sessions by default. Sessions without a debug log fall back to VS Code's own token fields and show 0 cache reads.
281
+
280
282
  If VS Code uses `--user-data-dir` or Portable Mode, specify a custom data root for the dashboard:
281
283
 
282
284
  macOS / Linux:
@@ -567,8 +569,26 @@ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/s
567
569
 
568
570
  This downloads the installed version and immediately enables `token-usage-insights.service`; you do not need to build or edit a systemd file yourself.
569
571
 
572
+ ### macOS: install and enable the launchd LaunchAgent with one command
573
+
574
+ ```bash
575
+ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
576
+ ```
577
+
578
+ This installs `com.tokenusageinsights.plist` into `~/Library/LaunchAgents/` and loads it immediately; stdout and stderr logs are located in `~/Library/Logs/`.
579
+
580
+ ### Windows: install and enable background service with one command (Task Scheduler)
581
+
582
+ ```powershell
583
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
584
+ ```
585
+
586
+ This registers the `TokenUsageInsights_<username>` task in Windows Task Scheduler for the current user and starts it immediately; it starts automatically at user logon in the background, with logs in the installation `logs\` directory (default `%LOCALAPPDATA%\TokenUsageInsights\logs\`).
587
+
570
588
  ### Manage the service
571
589
 
590
+ Linux:
591
+
572
592
  ```bash
573
593
  systemctl --user status token-usage-insights.service
574
594
  journalctl --user -u token-usage-insights.service -n 50 -f
@@ -576,6 +596,100 @@ systemctl --user restart token-usage-insights.service
576
596
  systemctl --user stop token-usage-insights.service
577
597
  ```
578
598
 
599
+ macOS:
600
+
601
+ ```bash
602
+ launchctl print gui/$(id -u)/com.tokenusageinsights
603
+ launchctl kickstart -k gui/$(id -u)/com.tokenusageinsights
604
+ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.tokenusageinsights.plist
605
+ ```
606
+
607
+ Windows PowerShell:
608
+
609
+ ```powershell
610
+ # Resolve installation directory (defaults to %LOCALAPPDATA%\TokenUsageInsights, or dynamically resolved from task/shortcut)
611
+ $TaskName = if ($env:USERNAME) { "TokenUsageInsights_$env:USERNAME" } else { "TokenUsageInsights" }
612
+ $InstallDir = $null
613
+ $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
614
+ if (-not $Task) {
615
+ $Task = Get-ScheduledTask -TaskName "TokenUsageInsights" -ErrorAction SilentlyContinue
616
+ if ($Task) {
617
+ $TaskName = "TokenUsageInsights"
618
+ }
619
+ }
620
+ if ($Task -and $Task.Actions) {
621
+ foreach ($Action in @($Task.Actions)) {
622
+ if ($Action.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
623
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
624
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
625
+ break
626
+ } elseif ($Action.WorkingDirectory) {
627
+ $InstallDir = $Action.WorkingDirectory
628
+ break
629
+ }
630
+ }
631
+ }
632
+ $StartupShortcut = Join-Path ([Environment]::GetFolderPath('Startup')) "token-usage-insights.lnk"
633
+ if (!(Test-Path $StartupShortcut)) {
634
+ $StartupShortcut = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\token-usage-insights.lnk"
635
+ }
636
+ if (-not $InstallDir -and (Test-Path $StartupShortcut)) {
637
+ $WshShell = New-Object -ComObject WScript.Shell
638
+ $Shortcut = $WshShell.CreateShortcut($StartupShortcut)
639
+ if ($Shortcut.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
640
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
641
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
642
+ } elseif ($Shortcut.WorkingDirectory) {
643
+ $InstallDir = $Shortcut.WorkingDirectory
644
+ }
645
+ }
646
+ if (-not $InstallDir) {
647
+ $InstallDir = Join-Path $env:LOCALAPPDATA "TokenUsageInsights"
648
+ }
649
+ $TargetExe = "$InstallDir\token-usage-insights.exe".ToLowerInvariant().Replace('/', '\')
650
+ $EscapedDir = [regex]::Escape($InstallDir)
651
+
652
+ # Check service status (Task Scheduler or background process)
653
+ Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
654
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
655
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
656
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
657
+ } | Select-Object ProcessId, Name, CommandLine
658
+
659
+ # View logs
660
+ Get-Content (Join-Path $InstallDir "logs\token-usage-insights.out.log") -Tail 50 -Wait
661
+
662
+ # Restart service (scoped to this install directory; compatible with Task Scheduler and Startup folder modes)
663
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
664
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
665
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
666
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
667
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
668
+ if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
669
+ Start-ScheduledTask -TaskName $TaskName
670
+ } elseif (Test-Path $StartupShortcut) {
671
+ Start-Process $StartupShortcut
672
+ }
673
+
674
+ # Stop service (scoped to this install directory)
675
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
676
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
677
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
678
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
679
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
680
+
681
+ # Unregister service
682
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
683
+ Unregister-ScheduledTask -TaskName "TokenUsageInsights" -Confirm:$false -ErrorAction SilentlyContinue
684
+ if (Test-Path $StartupShortcut) {
685
+ Remove-Item $StartupShortcut -Force -ErrorAction SilentlyContinue
686
+ }
687
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
688
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
689
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
690
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
691
+ ```
692
+
579
693
  * * *
580
694
 
581
695
  ## Installation options and manual installation
@@ -592,7 +706,7 @@ Linux / macOS:
592
706
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash
593
707
  ```
594
708
 
595
- To install and enable the systemd user service at the same time on Linux:
709
+ To install and enable the background service at the same time (systemd on Linux; launchd on macOS):
596
710
 
597
711
  ```bash
598
712
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
@@ -604,6 +718,12 @@ Windows PowerShell:
604
718
  irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1 | iex
605
719
  ```
606
720
 
721
+ To install and enable the background service at the same time on Windows:
722
+
723
+ ```powershell
724
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
725
+ ```
726
+
607
727
  After installation, run (on Linux/macOS, confirm that `bin_dir` is on `PATH`; Windows creates a `.cmd` shim):
608
728
 
609
729
  ```bash
@@ -614,7 +734,7 @@ Environment variables can control the version and installation paths (all option
614
734
 
615
735
  | Variable | Platforms | Description |
616
736
  | --- | --- | --- |
617
- | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | Release tag to install, such as `v0.9.2`; defaults to `latest` |
737
+ | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | Release tag to install, such as `v0.9.5`; defaults to `latest` |
618
738
  | `TOKEN_USAGE_INSIGHTS_INSTALL_DIR` | Linux / macOS | Installation directory, passed to `install.sh` |
619
739
  | `TOKEN_USAGE_INSIGHTS_BIN_DIR` | Linux / macOS | Executable-link directory, passed to `install.sh` |
620
740
 
@@ -633,7 +753,7 @@ If you do not want to execute a remote script directly, download the archive for
633
753
  - Frontend assets in `static/`
634
754
  - The model pricing table `pricing.csv`
635
755
  - Status Line and service scripts in `shell/`
636
- - The `scripts/` directory (including `install.sh`, `install.ps1`, `get.sh`, and `get.ps1`)
756
+ - The `scripts/` directory (including `install.sh`, `install.ps1`, `get.sh`, `get.ps1`, and `run-service.ps1`)
637
757
  - README, LICENSE, and VERSION
638
758
 
639
759
  Linux or macOS:
@@ -644,7 +764,7 @@ cd token-usage-insights-<tag>-<target>
644
764
  ./install.sh
645
765
  ```
646
766
 
647
- To install and enable the systemd user service on Linux:
767
+ To install and enable the background service (systemd on Linux; launchd on macOS):
648
768
 
649
769
  ```bash
650
770
  ./install.sh --service
@@ -658,6 +778,12 @@ cd token-usage-insights-<tag>-x86_64-pc-windows-msvc
658
778
  powershell -ExecutionPolicy Bypass -File .\install.ps1
659
779
  ```
660
780
 
781
+ To install and enable the background service on Windows:
782
+
783
+ ```powershell
784
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Service
785
+ ```
786
+
661
787
  Custom Windows installation location and port:
662
788
 
663
789
  ```powershell
package/README.ja.md CHANGED
@@ -277,6 +277,8 @@ VS Code Stable と Insiders に対応しています:
277
277
 
278
278
  既存の `chatSessions` ファイルは完全に取り込み、ファイルサイズまたは更新日時が変わると再同期します。Token フィールドのないチャット Session も表示されますが、Token 数は 0 です。読み取るのはローカルのチャットファイルだけで、クラウド Session、Remote SSH ホスト、`state.vscdb` は含まれません。
279
279
 
280
+ **キャッシュ読み取り Token の取得元**:VS Code の `chatSessions` ファイルには、各リクエストの最後のモデル呼び出しの `promptTokens` と累計の `completionTokens` しか記録されず、Prompt Cache のキャッシュ読み取り数は記録されません。そのためダッシュボードは、同じワークスペースディレクトリに Copilot Chat 拡張機能が書き出すデバッグログ `GitHub.copilot-chat/debug-logs/<sessionId>/main.jsonl` も読み取り、そのターンの全モデル呼び出しの `inputTokens`・`outputTokens`・`cachedTokens` を合計して、非キャッシュ入力・キャッシュ読み取り・出力 Token に分解し、コスト推定にもキャッシュ読み取り単価を適用します。このデバッグログは VS Code 設定 `github.copilot.chat.agentDebugLog.fileLogging.enabled` で制御され(一部ユーザーには実験機能として有効化済み)、既定では最新 50 Session 分のみ保持されます。デバッグログのない Session は VS Code 標準の Token フィールドにフォールバックし、キャッシュ読み取りは 0 と表示されます。
281
+
280
282
  VS Code で `--user-data-dir` または Portable Mode を使う場合は、ダッシュボードのカスタムデータルートを指定できます:
281
283
 
282
284
  macOS / Linux:
@@ -567,8 +569,26 @@ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/s
567
569
 
568
570
  これはインストール版をダウンロードして `token-usage-insights.service` を直ちに有効化します。systemd ファイルを自分でビルドまたは編集する必要はありません。
569
571
 
572
+ ### macOS:1 行で launchd LaunchAgent をインストールして有効化
573
+
574
+ ```bash
575
+ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
576
+ ```
577
+
578
+ これは `com.tokenusageinsights.plist` を `~/Library/LaunchAgents/` にインストールして直ちにロードします。標準出力とエラーログは `~/Library/Logs/` に出力されます。
579
+
580
+ ### Windows:1 行でバックグラウンド常駐サービス(タスクスケジューラ)をインストールして有効化
581
+
582
+ ```powershell
583
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
584
+ ```
585
+
586
+ これは Windows タスクスケジューラ(Task Scheduler)に現在のユーザー専用の `TokenUsageInsights_<username>` タスクを登録して直ちに起動します。ユーザーログイン時に自動的にバックグラウンドで実行され、標準出力とエラーログはインストールディレクトリ配下の `logs\`(デフォルトは `%LOCALAPPDATA%\TokenUsageInsights\logs\`)に出力されます。
587
+
570
588
  ### サービスを管理
571
589
 
590
+ Linux:
591
+
572
592
  ```bash
573
593
  systemctl --user status token-usage-insights.service
574
594
  journalctl --user -u token-usage-insights.service -n 50 -f
@@ -576,6 +596,100 @@ systemctl --user restart token-usage-insights.service
576
596
  systemctl --user stop token-usage-insights.service
577
597
  ```
578
598
 
599
+ macOS:
600
+
601
+ ```bash
602
+ launchctl print gui/$(id -u)/com.tokenusageinsights
603
+ launchctl kickstart -k gui/$(id -u)/com.tokenusageinsights
604
+ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.tokenusageinsights.plist
605
+ ```
606
+
607
+ Windows PowerShell:
608
+
609
+ ```powershell
610
+ # インストールディレクトリを解決(デフォルトは %LOCALAPPDATA%\TokenUsageInsights、またはタスク/ショートカットから動的取得)
611
+ $TaskName = if ($env:USERNAME) { "TokenUsageInsights_$env:USERNAME" } else { "TokenUsageInsights" }
612
+ $InstallDir = $null
613
+ $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
614
+ if (-not $Task) {
615
+ $Task = Get-ScheduledTask -TaskName "TokenUsageInsights" -ErrorAction SilentlyContinue
616
+ if ($Task) {
617
+ $TaskName = "TokenUsageInsights"
618
+ }
619
+ }
620
+ if ($Task -and $Task.Actions) {
621
+ foreach ($Action in @($Task.Actions)) {
622
+ if ($Action.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
623
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
624
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
625
+ break
626
+ } elseif ($Action.WorkingDirectory) {
627
+ $InstallDir = $Action.WorkingDirectory
628
+ break
629
+ }
630
+ }
631
+ }
632
+ $StartupShortcut = Join-Path ([Environment]::GetFolderPath('Startup')) "token-usage-insights.lnk"
633
+ if (!(Test-Path $StartupShortcut)) {
634
+ $StartupShortcut = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\token-usage-insights.lnk"
635
+ }
636
+ if (-not $InstallDir -and (Test-Path $StartupShortcut)) {
637
+ $WshShell = New-Object -ComObject WScript.Shell
638
+ $Shortcut = $WshShell.CreateShortcut($StartupShortcut)
639
+ if ($Shortcut.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
640
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
641
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
642
+ } elseif ($Shortcut.WorkingDirectory) {
643
+ $InstallDir = $Shortcut.WorkingDirectory
644
+ }
645
+ }
646
+ if (-not $InstallDir) {
647
+ $InstallDir = Join-Path $env:LOCALAPPDATA "TokenUsageInsights"
648
+ }
649
+ $TargetExe = "$InstallDir\token-usage-insights.exe".ToLowerInvariant().Replace('/', '\')
650
+ $EscapedDir = [regex]::Escape($InstallDir)
651
+
652
+ # サービス状態を確認(タスクスケジューラまたはバックグラウンドプロセス)
653
+ Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
654
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
655
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
656
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
657
+ } | Select-Object ProcessId, Name, CommandLine
658
+
659
+ # ログをリアルタイム確認
660
+ Get-Content (Join-Path $InstallDir "logs\token-usage-insights.out.log") -Tail 50 -Wait
661
+
662
+ # サービスを再起動(このインストールディレクトリに限定、タスクスケジューラとスタートアップフォルダの両方に対応)
663
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
664
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
665
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
666
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
667
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
668
+ if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
669
+ Start-ScheduledTask -TaskName $TaskName
670
+ } elseif (Test-Path $StartupShortcut) {
671
+ Start-Process $StartupShortcut
672
+ }
673
+
674
+ # サービスを停止(このインストールディレクトリに限定)
675
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
676
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
677
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
678
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
679
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
680
+
681
+ # 常駐サービスを登録解除
682
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
683
+ Unregister-ScheduledTask -TaskName "TokenUsageInsights" -Confirm:$false -ErrorAction SilentlyContinue
684
+ if (Test-Path $StartupShortcut) {
685
+ Remove-Item $StartupShortcut -Force -ErrorAction SilentlyContinue
686
+ }
687
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
688
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
689
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
690
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
691
+ ```
692
+
579
693
  * * *
580
694
 
581
695
  ## インストールオプションと手動インストール
@@ -592,7 +706,7 @@ Linux / macOS:
592
706
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash
593
707
  ```
594
708
 
595
- Linux systemd ユーザーサービスも同時にインストールして有効化する場合:
709
+ Linux(systemd user service)または macOS(launchd LaunchAgent)で常駐サービスも同時にインストールして有効化する場合:
596
710
 
597
711
  ```bash
598
712
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
@@ -604,6 +718,12 @@ Windows PowerShell:
604
718
  irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1 | iex
605
719
  ```
606
720
 
721
+ Windows PowerShell で常駐サービスも同時にインストールして有効化する場合:
722
+
723
+ ```powershell
724
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
725
+ ```
726
+
607
727
  インストール後に実行します(Linux/macOS では `bin_dir` が `PATH` に含まれることを確認してください。Windows では `.cmd` shim が作成されます):
608
728
 
609
729
  ```bash
@@ -614,7 +734,7 @@ token-usage-insights
614
734
 
615
735
  | 変数 | 対応プラットフォーム | 説明 |
616
736
  | --- | --- | --- |
617
- | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | `v0.9.2` のようなインストール対象の Release tag。デフォルトは `latest` |
737
+ | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | `v0.9.5` のようなインストール対象の Release tag。デフォルトは `latest` |
618
738
  | `TOKEN_USAGE_INSIGHTS_INSTALL_DIR` | Linux / macOS | `install.sh` に渡すインストールディレクトリ |
619
739
  | `TOKEN_USAGE_INSIGHTS_BIN_DIR` | Linux / macOS | `install.sh` に渡す実行ファイルリンクディレクトリ |
620
740
 
@@ -633,7 +753,7 @@ Invoke-WebRequest -Uri https://raw.githubusercontent.com/doggy8088/TokenUsageIns
633
753
  - `static/` のフロントエンドアセット
634
754
  - モデル料金表 `pricing.csv`
635
755
  - `shell/` の Status Line およびサービススクリプト
636
- - `scripts/` ディレクトリ(`install.sh`、`install.ps1`、`get.sh`、`get.ps1` を含む)
756
+ - `scripts/` ディレクトリ(`install.sh`、`install.ps1`、`get.sh`、`get.ps1`、`run-service.ps1` を含む)
637
757
  - README、LICENSE、VERSION
638
758
 
639
759
  Linux または macOS:
@@ -644,7 +764,7 @@ cd token-usage-insights-<tag>-<target>
644
764
  ./install.sh
645
765
  ```
646
766
 
647
- Linux systemd ユーザーサービスをインストールして有効化する場合:
767
+ Linux(systemd user service)または macOS(launchd LaunchAgent)で常駐サービスをインストールして有効化する場合:
648
768
 
649
769
  ```bash
650
770
  ./install.sh --service
@@ -658,6 +778,12 @@ cd token-usage-insights-<tag>-x86_64-pc-windows-msvc
658
778
  powershell -ExecutionPolicy Bypass -File .\install.ps1
659
779
  ```
660
780
 
781
+ Windows でバックグラウンド常駐サービスをインストールして有効化する場合:
782
+
783
+ ```powershell
784
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Service
785
+ ```
786
+
661
787
  Windows のインストール先とポートをカスタマイズ:
662
788
 
663
789
  ```powershell
package/README.ko.md CHANGED
@@ -277,6 +277,8 @@ VS Code Stable 및 Insiders를 지원합니다.
277
277
 
278
278
  대시보드는 기존 `chatSessions` 파일을 모두 채우고 파일 크기나 수정 시간이 변경되면 다시 동기화합니다. Token 필드가 없는 채팅 Session도 표시되지만 Token 수는 0입니다. 로컬 채팅 파일만 읽으며 클라우드 Session, Remote SSH 호스트 또는 `state.vscdb`는 포함하지 않습니다.
279
279
 
280
+ **캐시 읽기 Token 출처**: VS Code의 `chatSessions` 파일은 각 요청에서 마지막 모델 호출의 `promptTokens`와 누적 `completionTokens`만 기록하며 Prompt Cache 캐시 읽기 수는 기록하지 않습니다. 따라서 대시보드는 같은 워크스페이스 디렉터리에 Copilot Chat 확장이 기록하는 디버그 로그 `GitHub.copilot-chat/debug-logs/<sessionId>/main.jsonl`도 함께 읽어, 해당 턴의 모든 모델 호출의 `inputTokens`, `outputTokens`, `cachedTokens`를 합산한 뒤 비캐시 입력, 캐시 읽기, 출력 Token으로 나누고 비용 추정에도 캐시 읽기 단가를 적용합니다. 이 디버그 로그는 VS Code 설정 `github.copilot.chat.agentDebugLog.fileLogging.enabled`로 제어되며(일부 사용자는 실험 기능으로 이미 활성화됨) 기본적으로 최근 50개 Session만 보존합니다. 디버그 로그가 없는 Session은 VS Code 기본 Token 필드로 대체되며 캐시 읽기는 0으로 표시됩니다.
281
+
280
282
  VS Code에서 `--user-data-dir` 또는 Portable Mode를 사용하는 경우 대시보드의 사용자 지정 데이터 루트를 지정할 수 있습니다.
281
283
 
282
284
  macOS / Linux:
@@ -567,8 +569,26 @@ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/s
567
569
 
568
570
  이 명령은 설치 버전을 다운로드하고 `token-usage-insights.service`를 즉시 활성화합니다. systemd 파일을 직접 빌드하거나 수정할 필요가 없습니다.
569
571
 
572
+ ### macOS: 한 줄로 launchd LaunchAgent 설치 및 활성화
573
+
574
+ ```bash
575
+ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
576
+ ```
577
+
578
+ 이 명령은 `com.tokenusageinsights.plist`를 `~/Library/LaunchAgents/`에 설치하고 즉시 로드합니다. 표준 출력과 오류 로그는 `~/Library/Logs/`에 저장됩니다.
579
+
580
+ ### Windows: 한 줄로 백그라운드 상주 서비스(작업 스케줄러) 설치 및 활성화
581
+
582
+ ```powershell
583
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
584
+ ```
585
+
586
+ 이 명령은 Windows 작업 스케줄러(Task Scheduler)에 현재 사용자 전용 `TokenUsageInsights_<username>` 작업을 등록하고 즉시 시작합니다. 사용자가 로그인할 때마다 백그라운드에서 자동으로 실행되며 표준 출력 및 오류 로그는 설치 디렉터리 하위의 `logs\`(기본값은 `%LOCALAPPDATA%\TokenUsageInsights\logs\`)에 저장됩니다.
587
+
570
588
  ### 서비스 관리
571
589
 
590
+ Linux:
591
+
572
592
  ```bash
573
593
  systemctl --user status token-usage-insights.service
574
594
  journalctl --user -u token-usage-insights.service -n 50 -f
@@ -576,6 +596,100 @@ systemctl --user restart token-usage-insights.service
576
596
  systemctl --user stop token-usage-insights.service
577
597
  ```
578
598
 
599
+ macOS:
600
+
601
+ ```bash
602
+ launchctl print gui/$(id -u)/com.tokenusageinsights
603
+ launchctl kickstart -k gui/$(id -u)/com.tokenusageinsights
604
+ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.tokenusageinsights.plist
605
+ ```
606
+
607
+ Windows PowerShell:
608
+
609
+ ```powershell
610
+ # 설치 디렉터리 확인(기본값은 %LOCALAPPDATA%\TokenUsageInsights, 또는 작업/바로 가기에서 동적 확인)
611
+ $TaskName = if ($env:USERNAME) { "TokenUsageInsights_$env:USERNAME" } else { "TokenUsageInsights" }
612
+ $InstallDir = $null
613
+ $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
614
+ if (-not $Task) {
615
+ $Task = Get-ScheduledTask -TaskName "TokenUsageInsights" -ErrorAction SilentlyContinue
616
+ if ($Task) {
617
+ $TaskName = "TokenUsageInsights"
618
+ }
619
+ }
620
+ if ($Task -and $Task.Actions) {
621
+ foreach ($Action in @($Task.Actions)) {
622
+ if ($Action.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
623
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
624
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
625
+ break
626
+ } elseif ($Action.WorkingDirectory) {
627
+ $InstallDir = $Action.WorkingDirectory
628
+ break
629
+ }
630
+ }
631
+ }
632
+ $StartupShortcut = Join-Path ([Environment]::GetFolderPath('Startup')) "token-usage-insights.lnk"
633
+ if (!(Test-Path $StartupShortcut)) {
634
+ $StartupShortcut = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\token-usage-insights.lnk"
635
+ }
636
+ if (-not $InstallDir -and (Test-Path $StartupShortcut)) {
637
+ $WshShell = New-Object -ComObject WScript.Shell
638
+ $Shortcut = $WshShell.CreateShortcut($StartupShortcut)
639
+ if ($Shortcut.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
640
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
641
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
642
+ } elseif ($Shortcut.WorkingDirectory) {
643
+ $InstallDir = $Shortcut.WorkingDirectory
644
+ }
645
+ }
646
+ if (-not $InstallDir) {
647
+ $InstallDir = Join-Path $env:LOCALAPPDATA "TokenUsageInsights"
648
+ }
649
+ $TargetExe = "$InstallDir\token-usage-insights.exe".ToLowerInvariant().Replace('/', '\')
650
+ $EscapedDir = [regex]::Escape($InstallDir)
651
+
652
+ # 서비스 상태 확인(작업 스케줄러 또는 백그라운드 프로세스)
653
+ Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
654
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
655
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
656
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
657
+ } | Select-Object ProcessId, Name, CommandLine
658
+
659
+ # 실시간 로그 확인
660
+ Get-Content (Join-Path $InstallDir "logs\token-usage-insights.out.log") -Tail 50 -Wait
661
+
662
+ # 서비스 다시 시작(해당 설치 디렉터리에 한정, 작업 스케줄러 및 시작프로그램 모드 자동 호환)
663
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
664
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
665
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
666
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
667
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
668
+ if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
669
+ Start-ScheduledTask -TaskName $TaskName
670
+ } elseif (Test-Path $StartupShortcut) {
671
+ Start-Process $StartupShortcut
672
+ }
673
+
674
+ # 서비스 중지(해당 설치 디렉터리에 한정)
675
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
676
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
677
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
678
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
679
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
680
+
681
+ # 상주 서비스 등록 해제
682
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
683
+ Unregister-ScheduledTask -TaskName "TokenUsageInsights" -Confirm:$false -ErrorAction SilentlyContinue
684
+ if (Test-Path $StartupShortcut) {
685
+ Remove-Item $StartupShortcut -Force -ErrorAction SilentlyContinue
686
+ }
687
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
688
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
689
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
690
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
691
+ ```
692
+
579
693
  * * *
580
694
 
581
695
  ## 설치 옵션 및 수동 설치
@@ -592,7 +706,7 @@ Linux / macOS:
592
706
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash
593
707
  ```
594
708
 
595
- Linux에서 systemd 사용자 서비스를 함께 설치하고 활성화하려면:
709
+ Linux(systemd user service) 또는 macOS(launchd LaunchAgent)에서 상주 서비스를 함께 설치하고 활성화하려면:
596
710
 
597
711
  ```bash
598
712
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
@@ -604,6 +718,12 @@ Windows PowerShell:
604
718
  irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1 | iex
605
719
  ```
606
720
 
721
+ Windows PowerShell에서 상주 서비스를 함께 설치하고 활성화하려면:
722
+
723
+ ```powershell
724
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
725
+ ```
726
+
607
727
  설치가 끝나면 실행합니다(Linux/macOS는 `bin_dir`가 `PATH`에 포함되는지 확인하고, Windows는 `.cmd` shim을 만듭니다).
608
728
 
609
729
  ```bash
@@ -614,7 +734,7 @@ token-usage-insights
614
734
 
615
735
  | 변수 | 대상 플랫폼 | 설명 |
616
736
  | --- | --- | --- |
617
- | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 설치할 Release tag(예: `v0.9.2`); 기본값은 `latest` |
737
+ | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 설치할 Release tag(예: `v0.9.5`); 기본값은 `latest` |
618
738
  | `TOKEN_USAGE_INSIGHTS_INSTALL_DIR` | Linux / macOS | `install.sh`에 전달할 설치 디렉터리 |
619
739
  | `TOKEN_USAGE_INSIGHTS_BIN_DIR` | Linux / macOS | `install.sh`에 전달할 실행 파일 링크 디렉터리 |
620
740
 
@@ -633,7 +753,7 @@ Invoke-WebRequest -Uri https://raw.githubusercontent.com/doggy8088/TokenUsageIns
633
753
  - `static/`의 프런트엔드 자산
634
754
  - 모델 가격표 `pricing.csv`
635
755
  - `shell/` 디렉터리의 Status Line 및 서비스 스크립트
636
- - `scripts/` 디렉터리(`install.sh`, `install.ps1`, `get.sh`, `get.ps1` 포함)
756
+ - `scripts/` 디렉터리(`install.sh`, `install.ps1`, `get.sh`, `get.ps1`, `run-service.ps1` 포함)
637
757
  - README, LICENSE 및 VERSION
638
758
 
639
759
  Linux 또는 macOS:
@@ -644,7 +764,7 @@ cd token-usage-insights-<tag>-<target>
644
764
  ./install.sh
645
765
  ```
646
766
 
647
- Linux에서 systemd 사용자 서비스를 설치하고 활성화하려면:
767
+ Linux(systemd user service) 또는 macOS(launchd LaunchAgent)에서 상주 서비스를 설치하고 활성화하려면:
648
768
 
649
769
  ```bash
650
770
  ./install.sh --service
@@ -658,6 +778,12 @@ cd token-usage-insights-<tag>-x86_64-pc-windows-msvc
658
778
  powershell -ExecutionPolicy Bypass -File .\install.ps1
659
779
  ```
660
780
 
781
+ Windows에서 백그라운드 상주 서비스를 설치하고 활성화하려면:
782
+
783
+ ```powershell
784
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Service
785
+ ```
786
+
661
787
  Windows 설치 위치 및 포트 사용자 지정:
662
788
 
663
789
  ```powershell
package/README.md CHANGED
@@ -277,6 +277,8 @@ COPILOT_APP_DIR="/path/to/copilot-app-data" token-usage-insights
277
277
 
278
278
  看板會完整回填現有 `chatSessions` 檔案,也會在檔案大小或修改時間變更時重新同步;沒有 Token 欄位的聊天 Session 仍會顯示,但 Token 數為 0。資料只讀取本機聊天檔案,不包含雲端 Session、Remote SSH 主機或 `state.vscdb`。
279
279
 
280
+ **快取讀取 Token 來源**:VS Code 的 `chatSessions` 檔案只記錄每個請求最後一次模型呼叫的 `promptTokens` 與累計的 `completionTokens`,並不記錄 Prompt Cache 的快取讀取數。看板會另外讀取 Copilot Chat 擴充功能在同一個工作區目錄下寫入的除錯記錄 `GitHub.copilot-chat/debug-logs/<sessionId>/main.jsonl`,把該回合所有模型呼叫的 `inputTokens`、`outputTokens` 與 `cachedTokens` 加總後,拆成非快取輸入、快取讀取與輸出 Token,成本估算也會依快取讀取費率計價。此除錯記錄由 VS Code 設定 `github.copilot.chat.agentDebugLog.fileLogging.enabled` 控制(部分使用者已由實驗功能開啟),且預設只保留最近 50 個 Session 的記錄;沒有除錯記錄的 Session 會回退使用 VS Code 內建的 Token 欄位,快取讀取會顯示為 0。
281
+
280
282
  若 VS Code 使用 `--user-data-dir` 或 Portable Mode,可指定看板自訂的資料根目錄:
281
283
 
282
284
  macOS / Linux:
@@ -582,8 +584,26 @@ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/s
582
584
 
583
585
  這會下載安裝版並立即啟用 `token-usage-insights.service`,不需要自行建置或修改 systemd 檔案。
584
586
 
587
+ ### macOS:一行安裝並啟用 launchd LaunchAgent
588
+
589
+ ```bash
590
+ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
591
+ ```
592
+
593
+ 這會將 `com.tokenusageinsights.plist` 安裝到 `~/Library/LaunchAgents/` 並立即載入;標準輸出與錯誤日誌位於 `~/Library/Logs/`。
594
+
595
+ ### Windows:一行安裝並啟用背景常駐服務(工作排程器)
596
+
597
+ ```powershell
598
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
599
+ ```
600
+
601
+ 這會透過 Windows 工作排程器(Task Scheduler)註冊專屬於目前使用者的 `TokenUsageInsights_<username>` 背景工作並立即啟動;使用者每次登入時均會自動於背景執行,標準輸出與錯誤日誌位於安裝目錄下的 `logs\`(預設為 `%LOCALAPPDATA%\TokenUsageInsights\logs\`)。
602
+
585
603
  ### 管理服務
586
604
 
605
+ Linux 可使用:
606
+
587
607
  ```bash
588
608
  systemctl --user status token-usage-insights.service
589
609
  journalctl --user -u token-usage-insights.service -n 50 -f
@@ -591,6 +611,100 @@ systemctl --user restart token-usage-insights.service
591
611
  systemctl --user stop token-usage-insights.service
592
612
  ```
593
613
 
614
+ macOS 可使用:
615
+
616
+ ```bash
617
+ launchctl print gui/$(id -u)/com.tokenusageinsights
618
+ launchctl kickstart -k gui/$(id -u)/com.tokenusageinsights
619
+ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.tokenusageinsights.plist
620
+ ```
621
+
622
+ Windows PowerShell 可使用:
623
+
624
+ ```powershell
625
+ # 解析安裝目錄(預設為 %LOCALAPPDATA%\TokenUsageInsights,或由已註冊排程/捷徑動態解析)
626
+ $TaskName = if ($env:USERNAME) { "TokenUsageInsights_$env:USERNAME" } else { "TokenUsageInsights" }
627
+ $InstallDir = $null
628
+ $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
629
+ if (-not $Task) {
630
+ $Task = Get-ScheduledTask -TaskName "TokenUsageInsights" -ErrorAction SilentlyContinue
631
+ if ($Task) {
632
+ $TaskName = "TokenUsageInsights"
633
+ }
634
+ }
635
+ if ($Task -and $Task.Actions) {
636
+ foreach ($Action in @($Task.Actions)) {
637
+ if ($Action.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
638
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
639
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
640
+ break
641
+ } elseif ($Action.WorkingDirectory) {
642
+ $InstallDir = $Action.WorkingDirectory
643
+ break
644
+ }
645
+ }
646
+ }
647
+ $StartupShortcut = Join-Path ([Environment]::GetFolderPath('Startup')) "token-usage-insights.lnk"
648
+ if (!(Test-Path $StartupShortcut)) {
649
+ $StartupShortcut = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\token-usage-insights.lnk"
650
+ }
651
+ if (-not $InstallDir -and (Test-Path $StartupShortcut)) {
652
+ $WshShell = New-Object -ComObject WScript.Shell
653
+ $Shortcut = $WshShell.CreateShortcut($StartupShortcut)
654
+ if ($Shortcut.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
655
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
656
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
657
+ } elseif ($Shortcut.WorkingDirectory) {
658
+ $InstallDir = $Shortcut.WorkingDirectory
659
+ }
660
+ }
661
+ if (-not $InstallDir) {
662
+ $InstallDir = Join-Path $env:LOCALAPPDATA "TokenUsageInsights"
663
+ }
664
+ $TargetExe = "$InstallDir\token-usage-insights.exe".ToLowerInvariant().Replace('/', '\')
665
+ $EscapedDir = [regex]::Escape($InstallDir)
666
+
667
+ # 檢視服務狀態(工作排程器或背景行程)
668
+ Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
669
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
670
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
671
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
672
+ } | Select-Object ProcessId, Name, CommandLine
673
+
674
+ # 檢視即時日誌
675
+ Get-Content (Join-Path $InstallDir "logs\token-usage-insights.out.log") -Tail 50 -Wait
676
+
677
+ # 重啟服務(僅限此安裝目錄,自動相容工作排程器與啟動資料夾模式)
678
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
679
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
680
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
681
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
682
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
683
+ if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
684
+ Start-ScheduledTask -TaskName $TaskName
685
+ } elseif (Test-Path $StartupShortcut) {
686
+ Start-Process $StartupShortcut
687
+ }
688
+
689
+ # 停止服務(僅限此安裝目錄)
690
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
691
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
692
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
693
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
694
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
695
+
696
+ # 解除安裝常駐服務
697
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
698
+ Unregister-ScheduledTask -TaskName "TokenUsageInsights" -Confirm:$false -ErrorAction SilentlyContinue
699
+ if (Test-Path $StartupShortcut) {
700
+ Remove-Item $StartupShortcut -Force -ErrorAction SilentlyContinue
701
+ }
702
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
703
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
704
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
705
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
706
+ ```
707
+
594
708
  * * *
595
709
 
596
710
  ## 安裝選項與手動安裝
@@ -617,7 +731,7 @@ Linux / macOS:
617
731
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash
618
732
  ```
619
733
 
620
- Linux 如需同時安裝並啟用 systemd user service
734
+ Linuxsystemd user service)或 macOS(launchd LaunchAgent)如需同時安裝並啟用常駐服務:
621
735
 
622
736
  ```bash
623
737
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
@@ -629,6 +743,12 @@ Windows PowerShell:
629
743
  irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1 | iex
630
744
  ```
631
745
 
746
+ Windows PowerShell 如需同時安裝並啟用常駐服務:
747
+
748
+ ```powershell
749
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
750
+ ```
751
+
632
752
  安裝完成後即可執行(Linux/macOS 需確認 `bin_dir` 已加入 `PATH`;Windows 會建立 `.cmd` shim):
633
753
 
634
754
  ```bash
@@ -639,7 +759,7 @@ token-usage-insights
639
759
 
640
760
  | 變數 | 適用平台 | 說明 |
641
761
  | --- | --- | --- |
642
- | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 指定要安裝的 Release tag,例如 `v0.9.2`。預設 `latest` |
762
+ | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 指定要安裝的 Release tag,例如 `v0.9.5`。預設 `latest` |
643
763
  | `TOKEN_USAGE_INSIGHTS_INSTALL_DIR` | Linux / macOS | 安裝目錄,會轉交給 `install.sh` |
644
764
  | `TOKEN_USAGE_INSIGHTS_BIN_DIR` | Linux / macOS | 執行檔連結目錄,會轉交給 `install.sh` |
645
765
 
@@ -658,7 +778,7 @@ Invoke-WebRequest -Uri https://raw.githubusercontent.com/doggy8088/TokenUsageIns
658
778
  - `static/` 前端資產
659
779
  - `pricing.csv` 模型費用表
660
780
  - `shell/` 目錄下的 Status Line 與服務腳本
661
- - `scripts/` 目錄(含 `install.sh`、`install.ps1`、`get.sh`、`get.ps1`)
781
+ - `scripts/` 目錄(含 `install.sh`、`install.ps1`、`get.sh`、`get.ps1`、`run-service.ps1`)
662
782
  - README、LICENSE 與 VERSION
663
783
 
664
784
  Linux 或 macOS:
@@ -669,7 +789,7 @@ cd token-usage-insights-<tag>-<target>
669
789
  ./install.sh
670
790
  ```
671
791
 
672
- Linux 如需安裝並啟用 systemd user service
792
+ Linuxsystemd user service)或 macOS(launchd LaunchAgent)如需安裝並啟用常駐服務:
673
793
 
674
794
  ```bash
675
795
  ./install.sh --service
@@ -683,6 +803,12 @@ cd token-usage-insights-<tag>-x86_64-pc-windows-msvc
683
803
  powershell -ExecutionPolicy Bypass -File .\install.ps1
684
804
  ```
685
805
 
806
+ Windows 如需安裝並啟用背景常駐服務:
807
+
808
+ ```powershell
809
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Service
810
+ ```
811
+
686
812
  自訂 Windows 安裝位置與埠號:
687
813
 
688
814
  ```powershell
package/README.zh-CN.md CHANGED
@@ -277,6 +277,8 @@ COPILOT_APP_DIR="/path/to/copilot-app-data" token-usage-insights
277
277
 
278
278
  看板会完整回填现有的 `chatSessions` 文件,并在文件大小或修改时间变化时重新同步;没有 Token 字段的聊天 Session 仍会显示,但 Token 数为 0。数据只读取本地聊天文件,不包含云端 Session、Remote SSH 主机或 `state.vscdb`。
279
279
 
280
+ **缓存读取 Token 来源**:VS Code 的 `chatSessions` 文件只记录每个请求最后一次模型调用的 `promptTokens` 与累计的 `completionTokens`,并不记录 Prompt Cache 的缓存读取数。看板会另外读取 Copilot Chat 扩展在同一个工作区目录下写入的调试日志 `GitHub.copilot-chat/debug-logs/<sessionId>/main.jsonl`,把该回合所有模型调用的 `inputTokens`、`outputTokens` 与 `cachedTokens` 加总后,拆成非缓存输入、缓存读取与输出 Token,成本估算也会按缓存读取费率计价。此调试日志由 VS Code 设置 `github.copilot.chat.agentDebugLog.fileLogging.enabled` 控制(部分用户已由实验功能开启),且默认只保留最近 50 个 Session 的记录;没有调试日志的 Session 会回退使用 VS Code 内置的 Token 字段,缓存读取会显示为 0。
281
+
280
282
  如果 VS Code 使用 `--user-data-dir` 或 Portable Mode,可以指定看板自定义的数据根目录:
281
283
 
282
284
  macOS / Linux:
@@ -567,8 +569,26 @@ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/s
567
569
 
568
570
  这会下载安装版并立即启用 `token-usage-insights.service`,不需要自行构建或修改 systemd 文件。
569
571
 
572
+ ### macOS:一行安装并启用 launchd LaunchAgent
573
+
574
+ ```bash
575
+ curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
576
+ ```
577
+
578
+ 这会将 `com.tokenusageinsights.plist` 安装到 `~/Library/LaunchAgents/` 并立即加载;标准输出与错误日志位于 `~/Library/Logs/`。
579
+
580
+ ### Windows:一行安装并启用背景常驻服务(任务计划程序)
581
+
582
+ ```powershell
583
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
584
+ ```
585
+
586
+ 这会通过 Windows 任务计划程序(Task Scheduler)注册专属于当前用户的 `TokenUsageInsights_<username>` 计划任务并立即启动;用户每次登录时均会自动在后台运行,标准输出与错误日志位于安装目录下的 `logs\`(默认为 `%LOCALAPPDATA%\TokenUsageInsights\logs\`)。
587
+
570
588
  ### 管理服务
571
589
 
590
+ Linux 可使用:
591
+
572
592
  ```bash
573
593
  systemctl --user status token-usage-insights.service
574
594
  journalctl --user -u token-usage-insights.service -n 50 -f
@@ -576,6 +596,100 @@ systemctl --user restart token-usage-insights.service
576
596
  systemctl --user stop token-usage-insights.service
577
597
  ```
578
598
 
599
+ macOS 可使用:
600
+
601
+ ```bash
602
+ launchctl print gui/$(id -u)/com.tokenusageinsights
603
+ launchctl kickstart -k gui/$(id -u)/com.tokenusageinsights
604
+ launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.tokenusageinsights.plist
605
+ ```
606
+
607
+ Windows PowerShell 可使用:
608
+
609
+ ```powershell
610
+ # 解析安装目录(默认为 %LOCALAPPDATA%\TokenUsageInsights,或由已注册计划任务/快捷方式动态解析)
611
+ $TaskName = if ($env:USERNAME) { "TokenUsageInsights_$env:USERNAME" } else { "TokenUsageInsights" }
612
+ $InstallDir = $null
613
+ $Task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
614
+ if (-not $Task) {
615
+ $Task = Get-ScheduledTask -TaskName "TokenUsageInsights" -ErrorAction SilentlyContinue
616
+ if ($Task) {
617
+ $TaskName = "TokenUsageInsights"
618
+ }
619
+ }
620
+ if ($Task -and $Task.Actions) {
621
+ foreach ($Action in @($Task.Actions)) {
622
+ if ($Action.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
623
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
624
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
625
+ break
626
+ } elseif ($Action.WorkingDirectory) {
627
+ $InstallDir = $Action.WorkingDirectory
628
+ break
629
+ }
630
+ }
631
+ }
632
+ $StartupShortcut = Join-Path ([Environment]::GetFolderPath('Startup')) "token-usage-insights.lnk"
633
+ if (!(Test-Path $StartupShortcut)) {
634
+ $StartupShortcut = Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\token-usage-insights.lnk"
635
+ }
636
+ if (-not $InstallDir -and (Test-Path $StartupShortcut)) {
637
+ $WshShell = New-Object -ComObject WScript.Shell
638
+ $Shortcut = $WshShell.CreateShortcut($StartupShortcut)
639
+ if ($Shortcut.Arguments -match '(?i)-InstallDir(?:\s+|:)(?:"([^"]+)"|(\S+))') {
640
+ $DetectedInstallDir = if ($Matches[1]) { $Matches[1] } else { $Matches[2] }
641
+ $InstallDir = [Environment]::ExpandEnvironmentVariables($DetectedInstallDir)
642
+ } elseif ($Shortcut.WorkingDirectory) {
643
+ $InstallDir = $Shortcut.WorkingDirectory
644
+ }
645
+ }
646
+ if (-not $InstallDir) {
647
+ $InstallDir = Join-Path $env:LOCALAPPDATA "TokenUsageInsights"
648
+ }
649
+ $TargetExe = "$InstallDir\token-usage-insights.exe".ToLowerInvariant().Replace('/', '\')
650
+ $EscapedDir = [regex]::Escape($InstallDir)
651
+
652
+ # 查看服务状态(任务计划程序或后台进程)
653
+ Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
654
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
655
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
656
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
657
+ } | Select-Object ProcessId, Name, CommandLine
658
+
659
+ # 查看实时日志
660
+ Get-Content (Join-Path $InstallDir "logs\token-usage-insights.out.log") -Tail 50 -Wait
661
+
662
+ # 重启服务(仅限此安装目录,自动兼容任务计划程序与启动文件夹模式)
663
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
664
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
665
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
666
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
667
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
668
+ if (Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue) {
669
+ Start-ScheduledTask -TaskName $TaskName
670
+ } elseif (Test-Path $StartupShortcut) {
671
+ Start-Process $StartupShortcut
672
+ }
673
+
674
+ # 停止服务(仅限此安装目录)
675
+ Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
676
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
677
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
678
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
679
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
680
+
681
+ # 卸载常驻服务
682
+ Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
683
+ Unregister-ScheduledTask -TaskName "TokenUsageInsights" -Confirm:$false -ErrorAction SilentlyContinue
684
+ if (Test-Path $StartupShortcut) {
685
+ Remove-Item $StartupShortcut -Force -ErrorAction SilentlyContinue
686
+ }
687
+ Get-CimInstance Win32_Process -ErrorAction SilentlyContinue | Where-Object {
688
+ ($_.CommandLine -like "*run-service.ps1*" -and $_.CommandLine -match "(?i)[\s`"'\\]$EscapedDir([\\`"'\s]|$)") -or
689
+ ($_.ExecutablePath -and ($_.ExecutablePath.ToLowerInvariant().Replace('/', '\') -eq $TargetExe))
690
+ } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
691
+ ```
692
+
579
693
  * * *
580
694
 
581
695
  ## 安装选项与手动安装
@@ -592,7 +706,7 @@ Linux / macOS:
592
706
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash
593
707
  ```
594
708
 
595
- Linux 如需同时安装并启用 systemd user service
709
+ Linuxsystemd user service)或 macOS(launchd LaunchAgent)如需同时安装并启用常驻服务:
596
710
 
597
711
  ```bash
598
712
  curl -fsSL https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.sh | bash -s -- --service
@@ -604,6 +718,12 @@ Windows PowerShell:
604
718
  irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1 | iex
605
719
  ```
606
720
 
721
+ Windows PowerShell 如需同时安装并启用常驻服务:
722
+
723
+ ```powershell
724
+ & ([scriptblock]::Create((irm https://raw.githubusercontent.com/doggy8088/TokenUsageInsights/main/scripts/get.ps1))) -Service
725
+ ```
726
+
607
727
  安装完成后即可运行(Linux/macOS 需确认 `bin_dir` 已加入 `PATH`;Windows 会创建 `.cmd` shim):
608
728
 
609
729
  ```bash
@@ -614,7 +734,7 @@ token-usage-insights
614
734
 
615
735
  | 变量 | 适用平台 | 说明 |
616
736
  | --- | --- | --- |
617
- | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 指定要安装的 Release tag,例如 `v0.9.2`。默认 `latest` |
737
+ | `TOKEN_USAGE_INSIGHTS_VERSION` | Linux / macOS / Windows | 指定要安装的 Release tag,例如 `v0.9.5`。默认 `latest` |
618
738
  | `TOKEN_USAGE_INSIGHTS_INSTALL_DIR` | Linux / macOS | 安装目录,会传递给 `install.sh` |
619
739
  | `TOKEN_USAGE_INSIGHTS_BIN_DIR` | Linux / macOS | 可执行文件链接目录,会传递给 `install.sh` |
620
740
 
@@ -633,7 +753,7 @@ Invoke-WebRequest -Uri https://raw.githubusercontent.com/doggy8088/TokenUsageIns
633
753
  - `static/` 前端资源
634
754
  - `pricing.csv` 模型费用表
635
755
  - `shell/` 目录下的 Status Line 与服务脚本
636
- - `scripts/` 目录(含 `install.sh`、`install.ps1`、`get.sh`、`get.ps1`)
756
+ - `scripts/` 目录(含 `install.sh`、`install.ps1`、`get.sh`、`get.ps1`、`run-service.ps1`)
637
757
  - README、LICENSE 与 VERSION
638
758
 
639
759
  Linux 或 macOS:
@@ -644,7 +764,7 @@ cd token-usage-insights-<tag>-<target>
644
764
  ./install.sh
645
765
  ```
646
766
 
647
- Linux 如需安装并启用 systemd user service
767
+ Linuxsystemd user service)或 macOS(launchd LaunchAgent)如需安装并启用常驻服务:
648
768
 
649
769
  ```bash
650
770
  ./install.sh --service
@@ -658,6 +778,12 @@ cd token-usage-insights-<tag>-x86_64-pc-windows-msvc
658
778
  powershell -ExecutionPolicy Bypass -File .\install.ps1
659
779
  ```
660
780
 
781
+ Windows 如需安装并启用背景常驻服务:
782
+
783
+ ```powershell
784
+ powershell -ExecutionPolicy Bypass -File .\install.ps1 -Service
785
+ ```
786
+
661
787
  自定义 Windows 安装位置与端口号:
662
788
 
663
789
  ```powershell
package/npm/install.cjs CHANGED
@@ -110,19 +110,53 @@ function run(command, args, options = {}) {
110
110
  if (result.status !== 0) throw new Error(`命令執行失敗:${command}`);
111
111
  }
112
112
 
113
+ // 以 .NET ZipFile API 解壓,不依賴 Microsoft.PowerShell.Archive 模組:
114
+ // 從 pwsh 7 啟動 npx 時,powershell.exe 會繼承 PowerShell 7 的 PSModulePath,
115
+ // 導致 Expand-Archive 因 PSEdition 檢查而無法自動載入。
116
+ const WINDOWS_ZIP_SCRIPT = [
117
+ "$ErrorActionPreference = 'Stop'",
118
+ 'Add-Type -AssemblyName System.IO.Compression.FileSystem',
119
+ '$root = [System.IO.Path]::GetFullPath($env:TUI_DESTINATION)',
120
+ "if (-not $root.EndsWith([System.IO.Path]::DirectorySeparatorChar)) { $root += [System.IO.Path]::DirectorySeparatorChar }",
121
+ '$zip = [System.IO.Compression.ZipFile]::OpenRead($env:TUI_ARCHIVE)',
122
+ 'try {',
123
+ ' foreach ($entry in $zip.Entries) {',
124
+ ' $target = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($root, $entry.FullName))',
125
+ ' if (-not $target.StartsWith($root, [System.StringComparison]::OrdinalIgnoreCase)) { throw "壓縮包含不安全路徑:$($entry.FullName)" }',
126
+ " if ($entry.FullName.EndsWith('/') -or $entry.FullName.EndsWith('\\')) {",
127
+ ' [System.IO.Directory]::CreateDirectory($target) | Out-Null',
128
+ ' continue',
129
+ ' }',
130
+ ' [System.IO.Directory]::CreateDirectory([System.IO.Path]::GetDirectoryName($target)) | Out-Null',
131
+ ' [System.IO.Compression.ZipFileExtensions]::ExtractToFile($entry, $target, $true)',
132
+ ' }',
133
+ '} finally {',
134
+ ' $zip.Dispose()',
135
+ '}',
136
+ ].join('\n');
137
+
138
+ function windowsPowerShellEnvironment(archive, destination, baseEnvironment = process.env) {
139
+ const env = { ...baseEnvironment, TUI_ARCHIVE: archive, TUI_DESTINATION: destination };
140
+ // 移除從 pwsh 7 繼承的 PSModulePath,讓 Windows PowerShell 5.1 使用自身預設模組路徑。
141
+ for (const key of Object.keys(env)) {
142
+ if (key.toLowerCase() === 'psmodulepath') delete env[key];
143
+ }
144
+ return env;
145
+ }
146
+
147
+ function extractWindowsZip(archive, destination) {
148
+ // Windows 10 1803 以後內建 bsdtar(tar.exe),可直接解壓 zip。
149
+ const tar = spawnSync('tar', ['-xf', archive, '-C', destination], { stdio: 'inherit' });
150
+ if (!tar.error && tar.status === 0) return;
151
+ run('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', WINDOWS_ZIP_SCRIPT], {
152
+ env: windowsPowerShellEnvironment(archive, destination),
153
+ });
154
+ }
155
+
113
156
  function extract(archive, destination) {
114
157
  mkdirSync(destination, { recursive: true });
115
158
  if (archive.endsWith('.zip') && process.platform === 'win32') {
116
- run(
117
- 'powershell.exe',
118
- [
119
- '-NoProfile',
120
- '-NonInteractive',
121
- '-Command',
122
- 'Expand-Archive -LiteralPath $env:TUI_ARCHIVE -DestinationPath $env:TUI_DESTINATION -Force',
123
- ],
124
- { env: { ...process.env, TUI_ARCHIVE: archive, TUI_DESTINATION: destination } },
125
- );
159
+ extractWindowsZip(archive, destination);
126
160
  return;
127
161
  }
128
162
  run('tar', [archive.endsWith('.tar.gz') ? '-xzf' : '-xf', archive, '-C', destination]);
@@ -218,6 +252,7 @@ if (require.main === module) {
218
252
 
219
253
  module.exports = {
220
254
  TARGETS,
255
+ WINDOWS_ZIP_SCRIPT,
221
256
  artifactName,
222
257
  cargoTarget,
223
258
  checksumForArtifact,
@@ -229,4 +264,5 @@ module.exports = {
229
264
  releaseBaseUrl,
230
265
  sha256,
231
266
  verifyChecksum,
267
+ windowsPowerShellEnvironment,
232
268
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "token-usage-insights",
3
- "version": "0.9.2",
3
+ "version": "0.9.5",
4
4
  "description": "Local-first AI coding agent token usage dashboard and CLI",
5
5
  "bin": {
6
6
  "token-usage-insights": "npm/cli.cjs"