token-larper 1.0.0

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.
Files changed (42) hide show
  1. package/README.md +334 -0
  2. package/Start-TokenLarper.vbs +5 -0
  3. package/bin/cli.js +34 -0
  4. package/llms.txt +59 -0
  5. package/package.json +61 -0
  6. package/scripts/docs-demo-server.ts +141 -0
  7. package/scripts/launch-on-default-desktop.ps1 +42 -0
  8. package/scripts/launch-silent.vbs +6 -0
  9. package/scripts/run-server.ps1 +59 -0
  10. package/scripts/tray-host.ps1 +181 -0
  11. package/src/ccusage.ts +1075 -0
  12. package/src/client/App.tsx +560 -0
  13. package/src/client/charts.tsx +341 -0
  14. package/src/client/components/Calendar.tsx +207 -0
  15. package/src/client/components/DateRangePicker.tsx +131 -0
  16. package/src/client/components/KpiCards.tsx +122 -0
  17. package/src/client/components/RankChip.tsx +22 -0
  18. package/src/client/components/SelectMenu.tsx +116 -0
  19. package/src/client/components/SettingsDialog.tsx +207 -0
  20. package/src/client/components/ThemeSettings.tsx +131 -0
  21. package/src/client/context.tsx +60 -0
  22. package/src/client/index.html +54 -0
  23. package/src/client/lib/aggregate.ts +266 -0
  24. package/src/client/lib/range.ts +87 -0
  25. package/src/client/lib/rank.ts +323 -0
  26. package/src/client/lib/shareCard.ts +139 -0
  27. package/src/client/logo.svg +8 -0
  28. package/src/client/main.tsx +12 -0
  29. package/src/client/styles.css +1113 -0
  30. package/src/client/themes.ts +268 -0
  31. package/src/client/utils.ts +61 -0
  32. package/src/client/views/Models.tsx +71 -0
  33. package/src/client/views/Overview.tsx +280 -0
  34. package/src/client/views/Projects.tsx +88 -0
  35. package/src/client/views/Rank.tsx +255 -0
  36. package/src/client/views/Sessions.tsx +108 -0
  37. package/src/client/views/Tools.tsx +114 -0
  38. package/src/projects.ts +214 -0
  39. package/src/server.ts +173 -0
  40. package/src/startup.ts +110 -0
  41. package/src/tray.ts +293 -0
  42. package/src/types.ts +155 -0
@@ -0,0 +1,42 @@
1
+ Add-Type @"
2
+ using System;
3
+ using System.Runtime.InteropServices;
4
+ public class DefaultDesktopLauncher {
5
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
6
+ public struct STARTUPINFO {
7
+ public int cb;
8
+ public string lpReserved;
9
+ public string lpDesktop;
10
+ public string lpTitle;
11
+ public int dwX; public int dwY; public int dwXSize; public int dwYSize;
12
+ public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute;
13
+ public int dwFlags; public short wShowWindow; public short cbReserved2;
14
+ public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError;
15
+ }
16
+ [StructLayout(LayoutKind.Sequential)]
17
+ public struct PROCESS_INFORMATION {
18
+ public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId;
19
+ }
20
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
21
+ public static extern bool CreateProcess(
22
+ string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
23
+ bool bInheritHandles, uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
24
+ ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
25
+
26
+ public static int LaunchOnDefaultDesktop(string cmdLine, string workDir) {
27
+ STARTUPINFO si = new STARTUPINFO();
28
+ si.cb = Marshal.SizeOf(si);
29
+ si.lpDesktop = "WinSta0\\Default";
30
+ si.dwFlags = 1;
31
+ si.wShowWindow = 0;
32
+ PROCESS_INFORMATION pi;
33
+ uint CREATE_NO_WINDOW = 0x08000000;
34
+ bool ok = CreateProcess(null, cmdLine, IntPtr.Zero, IntPtr.Zero, false, CREATE_NO_WINDOW, IntPtr.Zero, workDir, ref si, out pi);
35
+ if (!ok) return -Marshal.GetLastWin32Error();
36
+ return pi.dwProcessId;
37
+ }
38
+ }
39
+ "@
40
+ $cmd = "powershell.exe -NoProfile -ExecutionPolicy Bypass -Sta -File `"F:\Just Some Files\opensource\tokenlarper\scripts\tray-host.ps1`""
41
+ $launchedPid = [DefaultDesktopLauncher]::LaunchOnDefaultDesktop($cmd, "F:\Just Some Files\opensource\tokenlarper")
42
+ Write-Output $launchedPid
@@ -0,0 +1,6 @@
1
+ Set fso = CreateObject("Scripting.FileSystemObject")
2
+ scriptDir = fso.GetParentFolderName(WScript.ScriptFullName)
3
+ rootDir = fso.GetParentFolderName(scriptDir)
4
+ Set WshShell = CreateObject("WScript.Shell")
5
+ WshShell.CurrentDirectory = rootDir
6
+ WshShell.Run "powershell.exe -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File """ & fso.BuildPath(scriptDir, "run-server.ps1") & """", 0, False
@@ -0,0 +1,59 @@
1
+ $ErrorActionPreference = "Stop"
2
+ $projectRoot = Split-Path -Parent $PSScriptRoot
3
+ $cacheDir = Join-Path $projectRoot ".cache"
4
+ $settingsPath = Join-Path $cacheDir "settings.json"
5
+ $port = 4269
6
+ $openBrowser = $false
7
+
8
+ try {
9
+ if (Test-Path -LiteralPath $settingsPath) {
10
+ $settings = Get-Content -LiteralPath $settingsPath -Raw | ConvertFrom-Json
11
+ $savedPort = 0
12
+ if ([int]::TryParse([string]$settings.port, [ref]$savedPort) -and $savedPort -gt 0 -and $savedPort -le 65535) {
13
+ $port = $savedPort
14
+ }
15
+ $openBrowser = $settings.openBrowserOnBoot -eq $true
16
+ }
17
+ } catch {
18
+ $port = 4269
19
+ $openBrowser = $false
20
+ }
21
+
22
+ $baseUrl = "http://127.0.0.1:$port"
23
+ try {
24
+ $status = Invoke-RestMethod -Uri "$baseUrl/api/tray-status" -TimeoutSec 2
25
+ if ($null -ne $status.shortTooltip) {
26
+ if ($openBrowser) { Start-Process $baseUrl }
27
+ exit 0
28
+ }
29
+ } catch {
30
+ # The server is not running yet.
31
+ }
32
+
33
+ try {
34
+ $bunCommand = Get-Command bun.exe -ErrorAction SilentlyContinue
35
+ $bunPath = if ($bunCommand) { $bunCommand.Source } else { Join-Path $env:USERPROFILE ".bun\bin\bun.exe" }
36
+ if (-not (Test-Path -LiteralPath $bunPath)) { throw "Bun was not found at $bunPath" }
37
+
38
+ $env:PORT = [string]$port
39
+ $serverEntry = Join-Path $projectRoot "src\server.ts"
40
+ $server = Start-Process -FilePath $bunPath -ArgumentList "`"$serverEntry`"" -WorkingDirectory $projectRoot -WindowStyle Hidden -PassThru
41
+
42
+ $ready = $false
43
+ for ($attempt = 0; $attempt -lt 40; $attempt++) {
44
+ if ($server.HasExited) { throw "Token Larper exited before the dashboard was ready" }
45
+ try {
46
+ $status = Invoke-RestMethod -Uri "$baseUrl/api/tray-status" -TimeoutSec 1
47
+ if ($null -ne $status.shortTooltip) { $ready = $true; break }
48
+ } catch {
49
+ Start-Sleep -Milliseconds 250
50
+ }
51
+ }
52
+ if (-not $ready) { throw "Token Larper did not respond on port $port" }
53
+ Remove-Item -LiteralPath (Join-Path $cacheDir "startup-error.log") -ErrorAction SilentlyContinue
54
+ if ($openBrowser) { Start-Process $baseUrl }
55
+ } catch {
56
+ New-Item -ItemType Directory -Path $cacheDir -Force | Out-Null
57
+ Set-Content -LiteralPath (Join-Path $cacheDir "startup-error.log") -Value $_.Exception.Message
58
+ exit 1
59
+ }
@@ -0,0 +1,181 @@
1
+ Add-Type -AssemblyName System.Windows.Forms
2
+ Add-Type -AssemblyName System.Drawing
3
+
4
+ $ServerPort = 4269
5
+ $ServerPid = 8904
6
+ $BaseUrl = "http://127.0.0.1:$ServerPort"
7
+
8
+ # Opt into DPI awareness so the icon is drawn at the tray's real pixel size
9
+ # (20px at 125%, 24px at 150%) instead of being drawn at 16px and blurred up.
10
+ Add-Type -Namespace TokenLarper -Name Dpi -MemberDefinition '[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();'
11
+ [TokenLarper.Dpi]::SetProcessDPIAware() | Out-Null
12
+
13
+ # The t. monogram from src/client/logo.svg, drawn in its 64-unit coordinates.
14
+ $iconSize = [Math]::Max(16, [System.Windows.Forms.SystemInformation]::SmallIconSize.Width)
15
+ $bmp = New-Object System.Drawing.Bitmap($iconSize, $iconSize)
16
+ $g = [System.Drawing.Graphics]::FromImage($bmp)
17
+ $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
18
+ $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
19
+ $g.Clear([System.Drawing.Color]::Transparent)
20
+ $g.ScaleTransform($iconSize / 64, $iconSize / 64)
21
+
22
+ $green = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(255, 47, 90, 67))
23
+ $cream = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(255, 243, 227, 191))
24
+ $gold = New-Object System.Drawing.SolidBrush([System.Drawing.Color]::FromArgb(255, 225, 183, 92))
25
+
26
+ # Rounded square: x 3, y 3, size 58, corner radius 14.
27
+ $tile = New-Object System.Drawing.Drawing2D.GraphicsPath
28
+ $tile.AddArc(3, 3, 28, 28, 180, 90)
29
+ $tile.AddArc(33, 3, 28, 28, 270, 90)
30
+ $tile.AddArc(33, 33, 28, 28, 0, 90)
31
+ $tile.AddArc(3, 33, 28, 28, 90, 90)
32
+ $tile.CloseFigure()
33
+ $g.FillPath($green, $tile)
34
+
35
+ # Letter t: a stem with a curved foot, plus the crossbar.
36
+ $stem = New-Object System.Drawing.Drawing2D.GraphicsPath
37
+ $stem.AddLine(20, 12, 28, 12)
38
+ $stem.AddLine(28, 12, 28, 43.5)
39
+ $stem.AddBezier(28, 43.5, 28, 45.2, 28.8, 46, 30.5, 46)
40
+ $stem.AddLine(30.5, 46, 35, 46)
41
+ $stem.AddLine(35, 46, 35, 53)
42
+ $stem.AddLine(35, 53, 28.5, 53)
43
+ $stem.AddBezier(28.5, 53, 22.8, 53, 20, 50.2, 20, 44.5)
44
+ $stem.CloseFigure()
45
+ $g.FillPath($cream, $stem)
46
+ $g.FillRectangle($cream, 13, 21, 22, 7)
47
+
48
+ # The dot.
49
+ $g.FillEllipse($gold, 39.5, 42, 11, 11)
50
+
51
+ $hIcon = $bmp.GetHicon()
52
+ $icon = [System.Drawing.Icon]::FromHandle($hIcon)
53
+
54
+ $notifyIcon = New-Object System.Windows.Forms.NotifyIcon
55
+ $notifyIcon.Icon = $icon
56
+ $notifyIcon.Text = "Token Larper - AI Coding Telemetry (Port $ServerPort)"
57
+ $notifyIcon.Visible = $true
58
+
59
+ # Context Menu
60
+ $menu = New-Object System.Windows.Forms.ContextMenuStrip
61
+
62
+ $itemHeader = New-Object System.Windows.Forms.ToolStripMenuItem("Token Larper Telemetry")
63
+ $itemHeader.Enabled = $false
64
+ $menu.Items.Add($itemHeader) | Out-Null
65
+
66
+ $itemStats = New-Object System.Windows.Forms.ToolStripMenuItem("Loading usage stats...")
67
+ $itemStats.Enabled = $false
68
+ $menu.Items.Add($itemStats) | Out-Null
69
+
70
+ $menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
71
+
72
+ $itemOpen = New-Object System.Windows.Forms.ToolStripMenuItem("Open Dashboard (http://localhost:$ServerPort)")
73
+ $itemOpen.Font = New-Object System.Drawing.Font($itemOpen.Font, [System.Drawing.FontStyle]::Bold)
74
+ $itemOpen.Add_Click({
75
+ Start-Process "$BaseUrl"
76
+ })
77
+ $menu.Items.Add($itemOpen) | Out-Null
78
+
79
+ $itemSync = New-Object System.Windows.Forms.ToolStripMenuItem("Sync Harnesses Now (ccusage)")
80
+ $itemSync.Add_Click({
81
+ try {
82
+ $notifyIcon.ShowBalloonTip(2000, "Token Larper", "Syncing coding harnesses via ccusage...", [System.Windows.Forms.ToolTipIcon]::Info)
83
+ Invoke-RestMethod -Uri "$BaseUrl/api/usage?refresh=1" -Method Get -TimeoutSec 20 | Out-Null
84
+ Update-TrayStatus
85
+ $notifyIcon.ShowBalloonTip(2500, "Token Larper Synced", $itemStats.Text, [System.Windows.Forms.ToolTipIcon]::Info)
86
+ } catch {
87
+ $notifyIcon.ShowBalloonTip(2500, "Token Larper", "Failed to sync harnesses.", [System.Windows.Forms.ToolTipIcon]::Warning)
88
+ }
89
+ })
90
+ $menu.Items.Add($itemSync) | Out-Null
91
+
92
+ $menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
93
+
94
+ $itemBoot = New-Object System.Windows.Forms.ToolStripMenuItem("Start on Windows Boot")
95
+ $itemBoot.CheckOnClick = $false
96
+ $itemBoot.Add_Click({
97
+ try {
98
+ $nextState = -not $itemBoot.Checked
99
+ $body = @{ enabled = $nextState; openBrowserOnBoot = $itemOpenOnBoot.Checked } | ConvertTo-Json
100
+ $res = Invoke-RestMethod -Uri "$BaseUrl/api/startup" -Method Post -Body $body -ContentType "application/json" -TimeoutSec 5
101
+ $itemBoot.Checked = [bool]$res.enabled
102
+ $itemOpenOnBoot.Checked = [bool]$res.openBrowserOnBoot
103
+ } catch {}
104
+ })
105
+ $menu.Items.Add($itemBoot) | Out-Null
106
+
107
+ $itemOpenOnBoot = New-Object System.Windows.Forms.ToolStripMenuItem("Auto-Open Browser on Boot")
108
+ $itemOpenOnBoot.CheckOnClick = $false
109
+ $itemOpenOnBoot.Add_Click({
110
+ try {
111
+ $nextOpen = -not $itemOpenOnBoot.Checked
112
+ $body = @{ enabled = $itemBoot.Checked; openBrowserOnBoot = $nextOpen } | ConvertTo-Json
113
+ $res = Invoke-RestMethod -Uri "$BaseUrl/api/startup" -Method Post -Body $body -ContentType "application/json" -TimeoutSec 5
114
+ $itemBoot.Checked = [bool]$res.enabled
115
+ $itemOpenOnBoot.Checked = [bool]$res.openBrowserOnBoot
116
+ } catch {}
117
+ })
118
+ $menu.Items.Add($itemOpenOnBoot) | Out-Null
119
+
120
+ $menu.Items.Add((New-Object System.Windows.Forms.ToolStripSeparator)) | Out-Null
121
+
122
+ $itemQuit = New-Object System.Windows.Forms.ToolStripMenuItem("Quit Token Larper")
123
+ $itemQuit.Add_Click({
124
+ $notifyIcon.Visible = $false
125
+ try {
126
+ Invoke-RestMethod -Uri "$BaseUrl/api/shutdown" -Method Post -ContentType "application/json" -TimeoutSec 3 | Out-Null
127
+ } catch {}
128
+ try {
129
+ Stop-Process -Id $ServerPid -Force -ErrorAction SilentlyContinue
130
+ } catch {}
131
+ $notifyIcon.Dispose()
132
+ [System.Windows.Forms.Application]::Exit()
133
+ })
134
+ $menu.Items.Add($itemQuit) | Out-Null
135
+
136
+ $notifyIcon.ContextMenuStrip = $menu
137
+
138
+ # Double-click tray icon opens dashboard
139
+ $notifyIcon.Add_DoubleClick({
140
+ Start-Process "$BaseUrl"
141
+ })
142
+
143
+ function Update-TrayStatus {
144
+ try {
145
+ $st = Invoke-RestMethod -Uri "$BaseUrl/api/tray-status" -Method Get -TimeoutSec 4
146
+ if ($null -ne $st) {
147
+ $itemStats.Text = $st.summaryText
148
+ $tooltip = "Token Larper: $($st.shortTooltip)"
149
+ if ($tooltip.Length -gt 63) {
150
+ $tooltip = $tooltip.Substring(0, 63)
151
+ }
152
+ $notifyIcon.Text = $tooltip
153
+ $itemBoot.Checked = [bool]$st.bootEnabled
154
+ $itemOpenOnBoot.Checked = [bool]$st.openBrowserOnBoot
155
+ }
156
+ } catch {}
157
+ }
158
+
159
+ # Timer to check parent Bun server health & update stats
160
+ $timer = New-Object System.Windows.Forms.Timer
161
+ $timer.Interval = 5000
162
+ $script:tickCount = 0
163
+ $timer.Add_Tick({
164
+ $proc = Get-Process -Id $ServerPid -ErrorAction SilentlyContinue
165
+ if ($null -eq $proc) {
166
+ $notifyIcon.Visible = $false
167
+ $notifyIcon.Dispose()
168
+ [System.Windows.Forms.Application]::Exit()
169
+ return
170
+ }
171
+ $script:tickCount++
172
+ if ($script:tickCount -eq 1 -or ($script:tickCount % 3 -eq 0)) {
173
+ Update-TrayStatus
174
+ }
175
+ })
176
+ $timer.Start()
177
+
178
+ Update-TrayStatus
179
+ $notifyIcon.ShowBalloonTip(2500, "Token Larper Running", "Right-click or double-click the green t. icon in your system tray.", [System.Windows.Forms.ToolTipIcon]::Info)
180
+
181
+ [System.Windows.Forms.Application]::Run()