ccstatusline-editor 1.0.0__py3-none-any.whl
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.
- ccstatusline_editor/__init__.py +0 -0
- ccstatusline_editor/app.py +542 -0
- ccstatusline_editor/templates/index.html +834 -0
- ccstatusline_editor-1.0.0.dist-info/METADATA +58 -0
- ccstatusline_editor-1.0.0.dist-info/RECORD +8 -0
- ccstatusline_editor-1.0.0.dist-info/WHEEL +5 -0
- ccstatusline_editor-1.0.0.dist-info/entry_points.txt +2 -0
- ccstatusline_editor-1.0.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
import threading
|
|
4
|
+
import webbrowser
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from flask import Flask, render_template, request, jsonify
|
|
7
|
+
|
|
8
|
+
app = Flask(__name__)
|
|
9
|
+
|
|
10
|
+
SETTINGS_PATH = Path.home() / ".config" / "ccstatusline" / "settings.json"
|
|
11
|
+
USER_PRESETS_PATH = Path.home() / ".config" / "ccstatusline" / "user_presets.json"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def load_user_presets():
|
|
15
|
+
if not USER_PRESETS_PATH.exists():
|
|
16
|
+
return []
|
|
17
|
+
with open(USER_PRESETS_PATH) as f:
|
|
18
|
+
return json.load(f)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def save_user_presets(presets):
|
|
22
|
+
USER_PRESETS_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
23
|
+
with open(USER_PRESETS_PATH, "w") as f:
|
|
24
|
+
json.dump(presets, f, indent=2)
|
|
25
|
+
|
|
26
|
+
WIDGET_TYPES = [
|
|
27
|
+
{"type": "model", "group": "AI"},
|
|
28
|
+
{"type": "output-style", "group": "AI"},
|
|
29
|
+
{"type": "thinking-effort", "group": "AI"},
|
|
30
|
+
{"type": "skills", "group": "AI"},
|
|
31
|
+
{"type": "version", "group": "AI"},
|
|
32
|
+
{"type": "context-percentage", "group": "Context"},
|
|
33
|
+
{"type": "context-percentage-usable","group": "Context"},
|
|
34
|
+
{"type": "context-length", "group": "Context"},
|
|
35
|
+
{"type": "context-window", "group": "Context"},
|
|
36
|
+
{"type": "context-bar", "group": "Context"},
|
|
37
|
+
{"type": "compaction-counter", "group": "Context"},
|
|
38
|
+
{"type": "session-cost", "group": "Session"},
|
|
39
|
+
{"type": "session-clock", "group": "Session"},
|
|
40
|
+
{"type": "session-name", "group": "Session"},
|
|
41
|
+
{"type": "session-usage", "group": "Session"},
|
|
42
|
+
{"type": "block-timer", "group": "Session"},
|
|
43
|
+
{"type": "reset-timer", "group": "Session"},
|
|
44
|
+
{"type": "tokens-input", "group": "Tokens"},
|
|
45
|
+
{"type": "tokens-output", "group": "Tokens"},
|
|
46
|
+
{"type": "tokens-cached", "group": "Tokens"},
|
|
47
|
+
{"type": "tokens-total", "group": "Tokens"},
|
|
48
|
+
{"type": "cache-hit-rate", "group": "Tokens"},
|
|
49
|
+
{"type": "cache-read", "group": "Tokens"},
|
|
50
|
+
{"type": "cache-write", "group": "Tokens"},
|
|
51
|
+
{"type": "input-speed", "group": "Speed"},
|
|
52
|
+
{"type": "output-speed", "group": "Speed"},
|
|
53
|
+
{"type": "total-speed", "group": "Speed"},
|
|
54
|
+
{"type": "weekly-usage", "group": "Usage"},
|
|
55
|
+
{"type": "weekly-sonnet-usage", "group": "Usage"},
|
|
56
|
+
{"type": "weekly-opus-usage", "group": "Usage"},
|
|
57
|
+
{"type": "weekly-reset-timer", "group": "Usage"},
|
|
58
|
+
{"type": "extra-usage-utilization", "group": "Usage"},
|
|
59
|
+
{"type": "extra-usage-remaining", "group": "Usage"},
|
|
60
|
+
{"type": "extra-usage-used", "group": "Usage"},
|
|
61
|
+
{"type": "git-branch", "group": "Git"},
|
|
62
|
+
{"type": "git-changes", "group": "Git"},
|
|
63
|
+
{"type": "git-status", "group": "Git"},
|
|
64
|
+
{"type": "git-clean-status", "group": "Git"},
|
|
65
|
+
{"type": "git-staged", "group": "Git"},
|
|
66
|
+
{"type": "git-unstaged", "group": "Git"},
|
|
67
|
+
{"type": "git-untracked", "group": "Git"},
|
|
68
|
+
{"type": "git-staged-files", "group": "Git"},
|
|
69
|
+
{"type": "git-unstaged-files", "group": "Git"},
|
|
70
|
+
{"type": "git-untracked-files", "group": "Git"},
|
|
71
|
+
{"type": "git-insertions", "group": "Git"},
|
|
72
|
+
{"type": "git-deletions", "group": "Git"},
|
|
73
|
+
{"type": "git-ahead-behind", "group": "Git"},
|
|
74
|
+
{"type": "git-conflicts", "group": "Git"},
|
|
75
|
+
{"type": "git-sha", "group": "Git"},
|
|
76
|
+
{"type": "git-root-dir", "group": "Git"},
|
|
77
|
+
{"type": "git-review", "group": "Git"},
|
|
78
|
+
{"type": "git-worktree", "group": "Git"},
|
|
79
|
+
{"type": "git-origin-owner", "group": "Git Origin"},
|
|
80
|
+
{"type": "git-origin-repo", "group": "Git Origin"},
|
|
81
|
+
{"type": "git-origin-owner-repo", "group": "Git Origin"},
|
|
82
|
+
{"type": "git-upstream-owner", "group": "Git Origin"},
|
|
83
|
+
{"type": "git-upstream-repo", "group": "Git Origin"},
|
|
84
|
+
{"type": "git-upstream-owner-repo", "group": "Git Origin"},
|
|
85
|
+
{"type": "git-is-fork", "group": "Git Origin"},
|
|
86
|
+
{"type": "worktree-mode", "group": "Worktree"},
|
|
87
|
+
{"type": "worktree-name", "group": "Worktree"},
|
|
88
|
+
{"type": "worktree-branch", "group": "Worktree"},
|
|
89
|
+
{"type": "worktree-original-branch", "group": "Worktree"},
|
|
90
|
+
{"type": "jj-bookmarks", "group": "Jujutsu"},
|
|
91
|
+
{"type": "jj-workspace", "group": "Jujutsu"},
|
|
92
|
+
{"type": "jj-root-dir", "group": "Jujutsu"},
|
|
93
|
+
{"type": "jj-changes", "group": "Jujutsu"},
|
|
94
|
+
{"type": "jj-insertions", "group": "Jujutsu"},
|
|
95
|
+
{"type": "jj-deletions", "group": "Jujutsu"},
|
|
96
|
+
{"type": "jj-description", "group": "Jujutsu"},
|
|
97
|
+
{"type": "jj-revision", "group": "Jujutsu"},
|
|
98
|
+
{"type": "current-working-dir", "group": "System"},
|
|
99
|
+
{"type": "free-memory", "group": "System"},
|
|
100
|
+
{"type": "terminal-width", "group": "System"},
|
|
101
|
+
{"type": "claude-session-id", "group": "System"},
|
|
102
|
+
{"type": "claude-account-email", "group": "System"},
|
|
103
|
+
{"type": "vim-mode", "group": "System"},
|
|
104
|
+
{"type": "voice-status", "group": "System"},
|
|
105
|
+
{"type": "remote-control-status", "group": "System"},
|
|
106
|
+
{"type": "custom-text", "group": "Custom"},
|
|
107
|
+
{"type": "custom-symbol", "group": "Custom"},
|
|
108
|
+
{"type": "custom-command", "group": "Custom"},
|
|
109
|
+
{"type": "link", "group": "Custom"},
|
|
110
|
+
{"type": "separator", "group": "Layout"},
|
|
111
|
+
{"type": "flex-separator", "group": "Layout"},
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
GROUPS = ["AI","Context","Session","Tokens","Speed","Usage","Git","Git Origin","Worktree","Jujutsu","System","Custom"]
|
|
116
|
+
|
|
117
|
+
def scheme(name, desc, ai, ctx, ses, tok, spd, use, git, gito, wt, jj, sys_, cus):
|
|
118
|
+
return {"name": name, "desc": desc, "colors": {
|
|
119
|
+
"AI": ai, "Context": ctx, "Session": ses, "Tokens": tok,
|
|
120
|
+
"Speed": spd, "Usage": use, "Git": git, "Git Origin": gito,
|
|
121
|
+
"Worktree": wt, "Jujutsu": jj, "System": sys_, "Custom": cus,
|
|
122
|
+
}}
|
|
123
|
+
|
|
124
|
+
# name desc AI Ctx Ses Tok Spd Use Git GitO WT JJ Sys Cus
|
|
125
|
+
SCHEMES = [
|
|
126
|
+
scheme("Ocean", "Cool blues and cyans", "cyan", "blue", "green", "cyan", "blue", "yellow", "blue", "blue", "cyan", "blue", "white", "white"),
|
|
127
|
+
scheme("Deep Sea", "All blues, deep and calm", "blue", "cyan", "blue", "cyan", "blue", "blue", "cyan", "blue", "cyan", "blue", "cyan", "white"),
|
|
128
|
+
scheme("Sky", "Cyan and white, open air", "cyan", "cyan", "blue", "white", "cyan", "blue", "blue", "blue", "cyan", "blue", "white", "cyan"),
|
|
129
|
+
scheme("Ice", "Pale and cold", "white", "cyan", "white", "cyan", "white", "blue", "cyan", "blue", "white", "cyan", "white", "cyan"),
|
|
130
|
+
scheme("Sapphire", "Rich blue throughout", "blue", "blue", "cyan", "blue", "blue", "cyan", "blue", "blue", "blue", "blue", "white", "blue"),
|
|
131
|
+
scheme("Forest", "Greens and earth tones", "green", "green", "cyan", "yellow", "green", "yellow", "green", "green", "green", "green", "white", "yellow"),
|
|
132
|
+
scheme("Matrix", "Pure green on black", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green"),
|
|
133
|
+
scheme("Nature", "Natural greens and yellows", "green", "yellow", "green", "cyan", "green", "yellow", "green", "green", "green", "green", "white", "white"),
|
|
134
|
+
scheme("Spring", "Fresh greens and cyan", "green", "cyan", "green", "yellow", "cyan", "green", "green", "cyan", "green", "green", "white", "yellow"),
|
|
135
|
+
scheme("Jade", "Teal and green gem", "cyan", "green", "green", "cyan", "green", "yellow", "green", "green", "cyan", "green", "white", "cyan"),
|
|
136
|
+
scheme("Everforest", "Muted greens, warm feel", "green", "green", "yellow", "cyan", "green", "yellow", "green", "green", "green", "green", "white", "yellow"),
|
|
137
|
+
scheme("Fire", "Red and yellow heat", "red", "yellow", "red", "yellow", "red", "yellow", "red", "red", "red", "red", "white", "yellow"),
|
|
138
|
+
scheme("Sunset", "Red, magenta, golden", "red", "yellow", "magenta","yellow", "red", "magenta","yellow", "red", "magenta","red", "white", "yellow"),
|
|
139
|
+
scheme("Autumn", "Warm reds and yellows", "yellow", "red", "yellow", "red", "yellow", "red", "yellow", "red", "yellow", "red", "white", "yellow"),
|
|
140
|
+
scheme("Lava", "Molten red and orange", "red", "yellow", "red", "yellow", "red", "yellow", "red", "red", "red", "yellow", "white", "red"),
|
|
141
|
+
scheme("Ruby", "Deep reds and magenta", "red", "magenta","red", "red", "magenta","red", "red", "magenta","red", "red", "white", "red"),
|
|
142
|
+
scheme("Desert", "Sandy yellows and warm white", "yellow", "yellow", "red", "yellow", "white", "yellow", "yellow", "yellow", "yellow", "yellow", "white", "yellow"),
|
|
143
|
+
scheme("Amber", "All amber/yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "white", "yellow"),
|
|
144
|
+
scheme("Neon", "Electric pop colours", "magenta","cyan", "green", "yellow", "cyan", "magenta","green", "cyan", "magenta","cyan", "white", "yellow"),
|
|
145
|
+
scheme("Royal", "Purple and blue regal", "blue", "magenta","blue", "cyan", "blue", "magenta","blue", "magenta","blue", "blue", "white", "magenta"),
|
|
146
|
+
scheme("Nebula", "Deep space purples", "magenta","blue", "cyan", "magenta","blue", "cyan", "magenta","blue", "magenta","blue", "white", "cyan"),
|
|
147
|
+
scheme("Synthwave", "Retro purple and cyan", "magenta","cyan", "magenta","blue", "cyan", "magenta","cyan", "magenta","cyan", "magenta","white", "cyan"),
|
|
148
|
+
scheme("Rose", "Pink and magenta blooms", "magenta","red", "magenta","red", "magenta","red", "magenta","red", "magenta","magenta","white", "magenta"),
|
|
149
|
+
scheme("Grape", "Solid magenta/purple", "magenta","magenta","blue", "magenta","magenta","magenta","magenta","magenta","magenta","magenta","white", "magenta"),
|
|
150
|
+
scheme("Dracula", "Classic Dracula palette", "magenta","cyan", "green", "cyan", "green", "yellow", "green", "cyan", "magenta","cyan", "white", "magenta"),
|
|
151
|
+
scheme("Nord", "Arctic blues and whites", "blue", "cyan", "white", "blue", "cyan", "blue", "blue", "cyan", "blue", "blue", "white", "blue"),
|
|
152
|
+
scheme("Solarized", "Balanced warm/cool tones", "yellow", "cyan", "green", "yellow", "cyan", "yellow", "green", "cyan", "yellow", "green", "white", "yellow"),
|
|
153
|
+
scheme("Gruvbox", "Warm retro earthy", "yellow", "green", "yellow", "green", "yellow", "red", "green", "yellow", "green", "yellow", "white", "yellow"),
|
|
154
|
+
scheme("Monokai", "Classic Monokai", "magenta","green", "yellow", "cyan", "green", "red", "green", "cyan", "magenta","green", "white", "yellow"),
|
|
155
|
+
scheme("Tokyo Night", "Dark city neons", "blue", "magenta","cyan", "blue", "cyan", "blue", "magenta","blue", "cyan", "magenta","white", "cyan"),
|
|
156
|
+
scheme("Catppuccin", "Soft pastel mocha", "magenta","blue", "cyan", "green", "cyan", "yellow", "green", "blue", "magenta","cyan", "white", "magenta"),
|
|
157
|
+
scheme("One Dark", "Atom One Dark", "blue", "cyan", "green", "yellow", "cyan", "red", "green", "blue", "cyan", "green", "white", "magenta"),
|
|
158
|
+
scheme("Oceanic Next", "Muted ocean blue-green", "cyan", "blue", "cyan", "blue", "cyan", "blue", "green", "cyan", "blue", "cyan", "white", "cyan"),
|
|
159
|
+
scheme("Vibrant", "Every group a different hue", "cyan", "yellow", "green", "blue", "magenta","red", "green", "blue", "cyan", "magenta","white", "yellow"),
|
|
160
|
+
scheme("Candy", "Playful bright mix", "magenta","cyan", "yellow", "green", "cyan", "magenta","green", "blue", "cyan", "magenta","white", "yellow"),
|
|
161
|
+
scheme("Cyberpunk", "High-voltage cyan and magenta", "cyan", "magenta","yellow", "cyan", "magenta","yellow", "cyan", "magenta","cyan", "magenta","white", "yellow"),
|
|
162
|
+
scheme("Aurora", "Northern lights", "green", "cyan", "magenta","green", "cyan", "magenta","green", "cyan", "magenta","green", "white", "cyan"),
|
|
163
|
+
scheme("Carnival", "Circus brights", "red", "yellow", "green", "blue", "magenta","cyan", "green", "blue", "yellow", "red", "white", "magenta"),
|
|
164
|
+
scheme("Monochrome", "Pure white on dark", "white", "white", "white", "white", "white", "white", "white", "white", "white", "white", "white", "white"),
|
|
165
|
+
scheme("Zen", "Mostly quiet, tiny accents", "cyan", "white", "white", "white", "white", "white", "white", "white", "white", "white", "white", "white"),
|
|
166
|
+
scheme("Minimal", "Only AI and Git stand out", "cyan", "white", "white", "white", "white", "white", "green", "white", "white", "white", "white", "white"),
|
|
167
|
+
scheme("Git Focus", "Git highlighted, rest quiet", "white", "white", "white", "white", "white", "white", "green", "green", "green", "white", "white", "white"),
|
|
168
|
+
scheme("Cost Alert", "Session cost in red, rest quiet", "white", "yellow", "red", "yellow", "white", "red", "white", "white", "white", "white", "white", "white"),
|
|
169
|
+
scheme("Dev Mode", "Code-focused: AI, Git, Context", "cyan", "yellow", "white", "white", "white", "white", "green", "white", "green", "green", "white", "white"),
|
|
170
|
+
scheme("Danger", "Everything red — something's wrong","red", "red", "red", "red", "red", "red", "red", "red", "red", "red", "red", "red"),
|
|
171
|
+
scheme("Warning", "All yellow caution", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow"),
|
|
172
|
+
scheme("Safe", "All green, everything OK", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green", "green"),
|
|
173
|
+
scheme("Winter", "Cold blue-white season", "white", "cyan", "blue", "white", "cyan", "blue", "white", "blue", "white", "blue", "white", "cyan"),
|
|
174
|
+
scheme("Summer", "Warm sunny vibes", "yellow", "green", "green", "cyan", "yellow", "green", "green", "green", "yellow", "green", "white", "yellow"),
|
|
175
|
+
scheme("Christmas", "Red and green festive", "red", "green", "red", "green", "red", "green", "green", "red", "green", "red", "white", "yellow"),
|
|
176
|
+
scheme("Halloween", "Orange-yellow and red spooky", "red", "yellow", "red", "yellow", "red", "yellow", "yellow", "red", "yellow", "red", "white", "yellow"),
|
|
177
|
+
scheme("Cobalt", "Strong cyan and yellow contrast", "cyan", "yellow", "green", "cyan", "white", "yellow", "cyan", "yellow", "cyan", "cyan", "white", "yellow"),
|
|
178
|
+
scheme("Hemisu", "Blue and white with cyan hints", "blue", "cyan", "white", "cyan", "blue", "white", "white", "cyan", "blue", "white", "white", "cyan"),
|
|
179
|
+
scheme("Flatland", "Clean multi-hue flat design", "blue", "cyan", "green", "yellow", "cyan", "blue", "green", "blue", "cyan", "green", "white", "yellow"),
|
|
180
|
+
scheme("Paraiso", "Tropical bright mix", "magenta","cyan", "green", "yellow", "green", "red", "green", "cyan", "magenta","green", "white", "yellow"),
|
|
181
|
+
scheme("Retro Terminal", "Old-school amber phosphor", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow", "yellow"),
|
|
182
|
+
scheme("Hacker", "Green on black, old hacker", "green", "green", "green", "green", "green", "yellow", "green", "green", "green", "green", "white", "green"),
|
|
183
|
+
scheme("Blueprint", "Engineer blue-on-white feel", "blue", "blue", "blue", "cyan", "blue", "blue", "blue", "blue", "blue", "blue", "white", "blue"),
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def w(type_, color=None):
|
|
188
|
+
d = {"type": type_}
|
|
189
|
+
if color: d["color"] = color
|
|
190
|
+
return d
|
|
191
|
+
|
|
192
|
+
def fsep():
|
|
193
|
+
return {"type": "flex-separator"}
|
|
194
|
+
|
|
195
|
+
def sep(char=None):
|
|
196
|
+
d = {"type": "separator"}
|
|
197
|
+
if char: d["metadata"] = {"character": char}
|
|
198
|
+
return d
|
|
199
|
+
|
|
200
|
+
WIDGET_SCHEMES = [
|
|
201
|
+
{
|
|
202
|
+
"name": "Context Watch",
|
|
203
|
+
"desc": "Laser focus on how full your context window is getting. Catch compaction before it surprises you.",
|
|
204
|
+
"tags": ["context","compaction"],
|
|
205
|
+
"lines": [
|
|
206
|
+
[w("context-percentage","yellow"), fsep(), w("context-percentage-usable","yellow"), w("context-window","blue"), w("context-length","blue")],
|
|
207
|
+
[w("context-bar","green"), fsep(), w("compaction-counter","red")],
|
|
208
|
+
]
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
"name": "Cost Monitor",
|
|
212
|
+
"desc": "Track session spend, weekly budget burn, and time until reset. Know before it hurts.",
|
|
213
|
+
"tags": ["cost","budget","usage"],
|
|
214
|
+
"lines": [
|
|
215
|
+
[w("session-cost","red"), fsep(), w("block-timer","white"), w("reset-timer","yellow")],
|
|
216
|
+
[w("weekly-usage","yellow"), w("weekly-sonnet-usage","yellow"), w("weekly-opus-usage","red"), fsep(), w("weekly-reset-timer","white")],
|
|
217
|
+
[w("extra-usage-utilization","yellow"), fsep(), w("extra-usage-remaining","green"), w("extra-usage-used","red")],
|
|
218
|
+
]
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
"name": "Project Orientation",
|
|
222
|
+
"desc": "Answer 'where am I and what state is it in?' at a glance. Good for context-switching between repos.",
|
|
223
|
+
"tags": ["git","project","orientation"],
|
|
224
|
+
"lines": [
|
|
225
|
+
[w("current-working-dir","white"), fsep(), w("git-root-dir","white"), w("git-branch","magenta")],
|
|
226
|
+
[w("git-status","yellow"), w("git-clean-status","green"), fsep(), w("git-ahead-behind","cyan")],
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"name": "Git Full Picture",
|
|
231
|
+
"desc": "Everything git at once — staged, unstaged, conflicts, insertions/deletions, remote status.",
|
|
232
|
+
"tags": ["git","staged","conflicts"],
|
|
233
|
+
"lines": [
|
|
234
|
+
[w("git-branch","magenta"), w("git-status","yellow"), fsep(), w("git-ahead-behind","cyan"), w("git-review","blue")],
|
|
235
|
+
[w("git-staged","green"), w("git-unstaged","yellow"), w("git-untracked","white"), fsep(), w("git-conflicts","red")],
|
|
236
|
+
[w("git-insertions","green"), w("git-deletions","red"), fsep(), w("git-staged-files","green"), w("git-unstaged-files","yellow"), w("git-untracked-files","white")],
|
|
237
|
+
]
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"name": "Git Minimal",
|
|
241
|
+
"desc": "Branch and dirty status only. Low noise for when you mostly trust your own git awareness.",
|
|
242
|
+
"tags": ["git","minimal"],
|
|
243
|
+
"lines": [
|
|
244
|
+
[w("git-branch","magenta"), fsep(), w("git-changes","yellow"), w("git-clean-status","green")],
|
|
245
|
+
]
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"name": "Code Reviewer",
|
|
249
|
+
"desc": "Focused on review workflow — PR status, ahead/behind, diff stats, and conflicts.",
|
|
250
|
+
"tags": ["git","review","pr"],
|
|
251
|
+
"lines": [
|
|
252
|
+
[w("git-branch","magenta"), w("git-review","blue"), fsep(), w("git-ahead-behind","cyan"), w("git-conflicts","red")],
|
|
253
|
+
[w("git-insertions","green"), w("git-deletions","red"), fsep(), w("git-staged-files","green"), w("git-unstaged-files","yellow")],
|
|
254
|
+
]
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
"name": "Remote Origin",
|
|
258
|
+
"desc": "Which remote repo are you working against? Fork status and upstream visibility.",
|
|
259
|
+
"tags": ["git","remote","fork"],
|
|
260
|
+
"lines": [
|
|
261
|
+
[w("git-origin-owner-repo","blue"), fsep(), w("git-is-fork","yellow"), w("git-branch","magenta")],
|
|
262
|
+
[w("git-upstream-owner-repo","magenta"), fsep(), w("git-ahead-behind","cyan"), w("git-review","blue")],
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"name": "Token Economy",
|
|
267
|
+
"desc": "Watch every token: input, output, cached, and total. Cache hit rate shows if caching is paying off.",
|
|
268
|
+
"tags": ["tokens","cache","cost"],
|
|
269
|
+
"lines": [
|
|
270
|
+
[w("tokens-input","white"), w("tokens-output","white"), fsep(), w("tokens-cached","cyan"), w("tokens-total","white")],
|
|
271
|
+
[w("cache-hit-rate","green"), w("cache-read","green"), fsep(), w("cache-write","yellow")],
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"name": "Speed Check",
|
|
276
|
+
"desc": "How fast is the model responding? Useful for noticing throttling or latency spikes.",
|
|
277
|
+
"tags": ["speed","performance","tokens"],
|
|
278
|
+
"lines": [
|
|
279
|
+
[w("input-speed","white"), w("output-speed","cyan"), w("total-speed","white"), fsep(), w("cache-hit-rate","green")],
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"name": "Session Overview",
|
|
284
|
+
"desc": "A balanced view of the current session — model, time, cost, and context in one sweep.",
|
|
285
|
+
"tags": ["session","overview","model"],
|
|
286
|
+
"lines": [
|
|
287
|
+
[w("model","cyan"), w("session-name","white"), fsep(), w("session-clock","white"), w("block-timer","white")],
|
|
288
|
+
[w("session-cost","green"), w("session-usage","yellow"), fsep(), w("context-percentage","yellow"), w("compaction-counter","red")],
|
|
289
|
+
]
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"name": "Model Intelligence",
|
|
293
|
+
"desc": "What AI am I talking to and how is it configured? Model, output style, thinking effort.",
|
|
294
|
+
"tags": ["model","ai","settings"],
|
|
295
|
+
"lines": [
|
|
296
|
+
[w("model","cyan"), w("output-style","blue"), fsep(), w("thinking-effort","magenta"), w("skills","blue")],
|
|
297
|
+
[w("version","white"), fsep(), w("vim-mode","yellow"), w("voice-status","green")],
|
|
298
|
+
]
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
"name": "Budget Dashboard",
|
|
302
|
+
"desc": "Weekly spend across model tiers plus extra usage. Know your bill before the end of the month.",
|
|
303
|
+
"tags": ["budget","weekly","usage"],
|
|
304
|
+
"lines": [
|
|
305
|
+
[w("weekly-usage","yellow"), fsep(), w("weekly-sonnet-usage","yellow"), w("weekly-opus-usage","red")],
|
|
306
|
+
[w("extra-usage-utilization","yellow"), fsep(), w("extra-usage-remaining","green"), w("extra-usage-used","red")],
|
|
307
|
+
[w("weekly-reset-timer","white"), fsep(), w("session-cost","green")],
|
|
308
|
+
]
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"name": "Writing / Docs",
|
|
312
|
+
"desc": "Non-coding work. Just model, session time, cost, and context — no git noise.",
|
|
313
|
+
"tags": ["writing","minimal","docs"],
|
|
314
|
+
"lines": [
|
|
315
|
+
[w("model","cyan"), w("session-clock","white"), fsep(), w("session-cost","green"), w("context-percentage","yellow")],
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"name": "Focus Mode",
|
|
320
|
+
"desc": "Absolute minimum. Context fill and cost only. Everything else is distraction.",
|
|
321
|
+
"tags": ["minimal","focus"],
|
|
322
|
+
"lines": [
|
|
323
|
+
[w("context-percentage","yellow"), fsep(), w("session-cost","green")],
|
|
324
|
+
]
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"name": "Minimal Classic",
|
|
328
|
+
"desc": "Model, cost, git branch, changes. The timeless four.",
|
|
329
|
+
"tags": ["minimal","classic"],
|
|
330
|
+
"lines": [
|
|
331
|
+
[w("model","cyan"), fsep(), w("session-cost","green"), w("git-branch","magenta"), w("git-changes","yellow")],
|
|
332
|
+
]
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"name": "Status Board",
|
|
336
|
+
"desc": "A broader dashboard — model, git, context, tokens and cache at a glance.",
|
|
337
|
+
"tags": ["overview","dashboard"],
|
|
338
|
+
"lines": [
|
|
339
|
+
[w("model","cyan"), w("git-branch","magenta"), fsep(), w("session-cost","green"), w("context-percentage","yellow")],
|
|
340
|
+
[w("tokens-total","white"), w("cache-hit-rate","green"), fsep(), w("git-changes","yellow"), w("git-ahead-behind","cyan")],
|
|
341
|
+
]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
"name": "Workspace Navigator",
|
|
345
|
+
"desc": "Where exactly are you? Working dir, git root, branch and worktree all visible.",
|
|
346
|
+
"tags": ["workspace","worktree","navigation"],
|
|
347
|
+
"lines": [
|
|
348
|
+
[w("current-working-dir","white"), fsep(), w("git-root-dir","white"), w("git-branch","magenta")],
|
|
349
|
+
[w("worktree-mode","cyan"), w("worktree-name","cyan"), fsep(), w("worktree-branch","cyan"), w("worktree-original-branch","blue")],
|
|
350
|
+
]
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"name": "Multi-Worktree",
|
|
354
|
+
"desc": "Managing several worktrees simultaneously. Full worktree context with base branch reference.",
|
|
355
|
+
"tags": ["worktree","git","parallel"],
|
|
356
|
+
"lines": [
|
|
357
|
+
[w("worktree-mode","cyan"), w("worktree-name","cyan"), w("worktree-branch","magenta"), fsep(), w("worktree-original-branch","blue"), w("git-ahead-behind","yellow")],
|
|
358
|
+
[w("git-staged","green"), w("git-unstaged","yellow"), fsep(), w("git-conflicts","red")],
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"name": "Pair Programming",
|
|
363
|
+
"desc": "Shared session context — who's driving? Session name, model, and current branch prominently shown.",
|
|
364
|
+
"tags": ["pair","session","git"],
|
|
365
|
+
"lines": [
|
|
366
|
+
[w("session-name","cyan"), w("model","blue"), fsep(), w("git-branch","magenta"), w("git-status","yellow")],
|
|
367
|
+
[w("context-percentage","yellow"), fsep(), w("session-cost","green"), w("block-timer","white")],
|
|
368
|
+
]
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
"name": "Performance Audit",
|
|
372
|
+
"desc": "Detailed performance analysis — token throughput, cache efficiency, cost per operation.",
|
|
373
|
+
"tags": ["performance","tokens","cache","speed"],
|
|
374
|
+
"lines": [
|
|
375
|
+
[w("tokens-input","white"), w("tokens-output","white"), w("tokens-cached","cyan"), fsep(), w("tokens-total","white")],
|
|
376
|
+
[w("cache-hit-rate","green"), w("cache-read","green"), w("cache-write","yellow"), fsep(), w("input-speed","white"), w("output-speed","cyan"), w("total-speed","white")],
|
|
377
|
+
[w("session-cost","red"), fsep(), w("context-percentage","yellow"), w("compaction-counter","red")],
|
|
378
|
+
]
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"name": "Night Owl",
|
|
382
|
+
"desc": "Late session check-in. Time, cost, context. Know when to stop.",
|
|
383
|
+
"tags": ["session","time","cost"],
|
|
384
|
+
"lines": [
|
|
385
|
+
[w("session-clock","white"), w("block-timer","white"), fsep(), w("session-cost","red"), w("reset-timer","yellow")],
|
|
386
|
+
[w("context-percentage","yellow"), fsep(), w("compaction-counter","red")],
|
|
387
|
+
]
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"name": "Ops / DevOps",
|
|
391
|
+
"desc": "System and environment info alongside git state. Good for infrastructure or deployment work.",
|
|
392
|
+
"tags": ["ops","system","git"],
|
|
393
|
+
"lines": [
|
|
394
|
+
[w("current-working-dir","white"), w("git-branch","magenta"), fsep(), w("git-clean-status","green"), w("git-ahead-behind","cyan")],
|
|
395
|
+
[w("free-memory","cyan"), w("terminal-width","white"), fsep(), w("session-cost","green"), w("block-timer","white")],
|
|
396
|
+
]
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "Open Source Contributor",
|
|
400
|
+
"desc": "Fork, upstream, PR status and diff stats. The view a contributor needs.",
|
|
401
|
+
"tags": ["git","oss","fork","pr"],
|
|
402
|
+
"lines": [
|
|
403
|
+
[w("git-origin-owner-repo","blue"), w("git-is-fork","yellow"), fsep(), w("git-branch","magenta"), w("git-review","blue")],
|
|
404
|
+
[w("git-upstream-owner-repo","magenta"), fsep(), w("git-ahead-behind","cyan"), w("git-conflicts","red")],
|
|
405
|
+
[w("git-insertions","green"), w("git-deletions","red"), fsep(), w("git-staged-files","green"), w("git-unstaged-files","yellow")],
|
|
406
|
+
]
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
"name": "Jujutsu User",
|
|
410
|
+
"desc": "For jj VCS users. Bookmarks, workspace, changes and revision info front and centre.",
|
|
411
|
+
"tags": ["jj","jujutsu","vcs"],
|
|
412
|
+
"lines": [
|
|
413
|
+
[w("jj-bookmarks","magenta"), w("jj-workspace","cyan"), fsep(), w("jj-description","white"), w("jj-revision","white")],
|
|
414
|
+
[w("jj-changes","yellow"), w("jj-insertions","green"), w("jj-deletions","red"), fsep(), w("jj-root-dir","white")],
|
|
415
|
+
]
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"name": "Weekly Reviewer",
|
|
419
|
+
"desc": "End-of-week accounting. Usage across model tiers, time to reset, extra quota consumed.",
|
|
420
|
+
"tags": ["weekly","budget","review"],
|
|
421
|
+
"lines": [
|
|
422
|
+
[w("weekly-usage","yellow"), fsep(), w("weekly-sonnet-usage","yellow"), w("weekly-opus-usage","red")],
|
|
423
|
+
[w("extra-usage-utilization","yellow"), w("extra-usage-used","red"), fsep(), w("extra-usage-remaining","green"), w("weekly-reset-timer","white")],
|
|
424
|
+
]
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
"name": "Long Session Survival",
|
|
428
|
+
"desc": "Context creeping up, compaction looming, cost ticking. The endurance runner's view.",
|
|
429
|
+
"tags": ["context","cost","compaction","session"],
|
|
430
|
+
"lines": [
|
|
431
|
+
[w("context-percentage","yellow"), w("context-length","blue"), fsep(), w("compaction-counter","red"), w("context-bar","green")],
|
|
432
|
+
[w("session-cost","red"), w("session-clock","white"), fsep(), w("block-timer","white"), w("reset-timer","yellow")],
|
|
433
|
+
]
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
"name": "Identity",
|
|
437
|
+
"desc": "Who am I, where am I, what session is this? Account, session ID, working dir.",
|
|
438
|
+
"tags": ["account","session","identity"],
|
|
439
|
+
"lines": [
|
|
440
|
+
[w("claude-account-email","white"), w("session-name","cyan"), fsep(), w("claude-session-id","white")],
|
|
441
|
+
[w("current-working-dir","white"), fsep(), w("git-branch","magenta"), w("model","cyan")],
|
|
442
|
+
]
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
"name": "Diff Watcher",
|
|
446
|
+
"desc": "Watch changes accumulate as you work. Lines added and deleted, files modified.",
|
|
447
|
+
"tags": ["git","diff","changes"],
|
|
448
|
+
"lines": [
|
|
449
|
+
[w("git-insertions","green"), w("git-deletions","red"), fsep(), w("git-staged-files","green"), w("git-unstaged-files","yellow"), w("git-untracked-files","white")],
|
|
450
|
+
[w("git-branch","magenta"), fsep(), w("git-clean-status","green"), w("git-conflicts","red")],
|
|
451
|
+
]
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
"name": "Cache Economist",
|
|
455
|
+
"desc": "All about cache efficiency. Hit rate, reads, writes. Know if you're wasting money on repeated tokens.",
|
|
456
|
+
"tags": ["cache","tokens","cost"],
|
|
457
|
+
"lines": [
|
|
458
|
+
[w("cache-hit-rate","green"), fsep(), w("cache-read","green"), w("cache-write","yellow")],
|
|
459
|
+
[w("tokens-cached","cyan"), w("tokens-total","white"), fsep(), w("session-cost","red")],
|
|
460
|
+
]
|
|
461
|
+
},
|
|
462
|
+
{
|
|
463
|
+
"name": "The Kitchen Sink",
|
|
464
|
+
"desc": "Everything, grouped logically across lines. Maximum information density.",
|
|
465
|
+
"tags": ["all","everything","full"],
|
|
466
|
+
"lines": [
|
|
467
|
+
[w("model","cyan"), w("output-style","cyan"), w("thinking-effort","blue"), fsep(), w("context-percentage","yellow"), w("context-length","blue"), w("compaction-counter","red")],
|
|
468
|
+
[w("session-cost","green"), w("block-timer","white"), fsep(), w("weekly-usage","yellow"), w("reset-timer","yellow")],
|
|
469
|
+
[w("tokens-input","white"), w("tokens-output","white"), w("tokens-cached","cyan"), fsep(), w("cache-hit-rate","green"), w("output-speed","cyan")],
|
|
470
|
+
[w("git-branch","magenta"), w("git-status","yellow"), fsep(), w("git-ahead-behind","cyan"), w("git-conflicts","red")],
|
|
471
|
+
]
|
|
472
|
+
},
|
|
473
|
+
]
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
@app.route("/")
|
|
477
|
+
def index():
|
|
478
|
+
return render_template("index.html", widget_types=WIDGET_TYPES, color_schemes=SCHEMES, widget_schemes=WIDGET_SCHEMES, groups=GROUPS)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
@app.route("/api/settings", methods=["GET"])
|
|
482
|
+
def get_settings():
|
|
483
|
+
if not SETTINGS_PATH.exists():
|
|
484
|
+
return jsonify({"error": f"Not found: {SETTINGS_PATH}"}), 404
|
|
485
|
+
with open(SETTINGS_PATH) as f:
|
|
486
|
+
return jsonify(json.load(f))
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
@app.route("/api/settings", methods=["POST"])
|
|
490
|
+
def save_settings():
|
|
491
|
+
data = request.get_json()
|
|
492
|
+
SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
493
|
+
with open(SETTINGS_PATH, "w") as f:
|
|
494
|
+
json.dump(data, f, indent=2)
|
|
495
|
+
return jsonify({"ok": True, "path": str(SETTINGS_PATH)})
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
@app.route("/api/widgets")
|
|
499
|
+
def get_widgets():
|
|
500
|
+
return jsonify(WIDGET_TYPES)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@app.route("/api/presets", methods=["GET"])
|
|
504
|
+
def get_presets():
|
|
505
|
+
return jsonify(load_user_presets())
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
@app.route("/api/presets", methods=["POST"])
|
|
509
|
+
def add_preset():
|
|
510
|
+
preset = request.get_json()
|
|
511
|
+
if not preset or not preset.get("name"):
|
|
512
|
+
return jsonify({"error": "name required"}), 400
|
|
513
|
+
presets = load_user_presets()
|
|
514
|
+
presets = [p for p in presets if p["name"] != preset["name"]]
|
|
515
|
+
presets.insert(0, preset)
|
|
516
|
+
save_user_presets(presets)
|
|
517
|
+
return jsonify({"ok": True})
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
@app.route("/api/presets/<name>", methods=["DELETE"])
|
|
521
|
+
def delete_preset(name):
|
|
522
|
+
presets = [p for p in load_user_presets() if p["name"] != name]
|
|
523
|
+
save_user_presets(presets)
|
|
524
|
+
return jsonify({"ok": True})
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
@app.route("/api/shutdown", methods=["POST"])
|
|
528
|
+
def shutdown():
|
|
529
|
+
threading.Timer(0.2, lambda: os._exit(0)).start()
|
|
530
|
+
return jsonify({"ok": True})
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
def main():
|
|
534
|
+
url = "http://127.0.0.1:5199"
|
|
535
|
+
print(f"ccstatusline-editor: {url}")
|
|
536
|
+
print(f"Editing: {SETTINGS_PATH}")
|
|
537
|
+
threading.Timer(0.5, lambda: webbrowser.open(url)).start()
|
|
538
|
+
app.run(port=5199)
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
if __name__ == "__main__":
|
|
542
|
+
main()
|