claude-finops 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/run.py +15 -0
- package/web/app.js +4 -1
- package/web/styles.css +7 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-finops",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Local FinOps dashboard for Claude Code: what you used, what it cost, why it cost that much, and what to change. Reads your own transcripts, no API key, no data leaves the machine.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"claude-finops": "bin/claude-finops.js"
|
package/run.py
CHANGED
|
@@ -105,6 +105,11 @@ Environment:
|
|
|
105
105
|
"""
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
def _version():
|
|
109
|
+
from finops.update import _installed
|
|
110
|
+
return _installed()
|
|
111
|
+
|
|
112
|
+
|
|
108
113
|
def version():
|
|
109
114
|
"""Which copy is this, and is it current?
|
|
110
115
|
|
|
@@ -222,6 +227,16 @@ def main():
|
|
|
222
227
|
return
|
|
223
228
|
if "--share" in args:
|
|
224
229
|
return share()
|
|
230
|
+
# A flag we do not know used to fall straight through and start the
|
|
231
|
+
# dashboard, so a typo (or a flag from a newer release than the one you
|
|
232
|
+
# have installed) looked like the command silently doing nothing.
|
|
233
|
+
known = {"--rebuild", "--detach", "--foreground"}
|
|
234
|
+
unknown = [a for a in args if a.startswith("-") and a not in known]
|
|
235
|
+
if unknown:
|
|
236
|
+
print(f"Unknown option: {unknown[0]}")
|
|
237
|
+
print(f"This is claude-finops {_version() or 'unknown'}; "
|
|
238
|
+
f"run --help to see what it supports.")
|
|
239
|
+
sys.exit(2)
|
|
225
240
|
stop() # replace a previous detached server
|
|
226
241
|
port = os.environ.get("PORT", "8787")
|
|
227
242
|
source = os.environ.get("CLAUDE_PROJECTS", os.path.join(os.path.expanduser("~"), ".claude", "projects"))
|
package/web/app.js
CHANGED
|
@@ -485,7 +485,10 @@ async function openSession(id) {
|
|
|
485
485
|
/* ---------- charts added to table-first pages ---------- */
|
|
486
486
|
// Inserts a chart card after the page's KPI row (or at the top) and draws into it.
|
|
487
487
|
function addChart(page, title, draw, opts = {}) {
|
|
488
|
-
|
|
488
|
+
// .chart carries every chart style (text fill, gridlines, axes); .cchart is
|
|
489
|
+
// just the hook this helper looks up. Missing .chart left SVG labels at the
|
|
490
|
+
// browser default fill — black text, invisible on the dark theme.
|
|
491
|
+
const c = h(card(title, '<div class="chart cchart"></div>', opts));
|
|
489
492
|
const anchor = opts.after ? page.querySelector(opts.after) : page.querySelector(':scope > .grid');
|
|
490
493
|
if (anchor) anchor.after(c); else page.prepend(c);
|
|
491
494
|
draw(c.querySelector('.cchart'));
|
package/web/styles.css
CHANGED
|
@@ -76,15 +76,19 @@ button, input, select { font: inherit; color: inherit; }
|
|
|
76
76
|
|
|
77
77
|
/* ---------- shell ---------- */
|
|
78
78
|
.app { display: grid; grid-template-columns: 216px 1fr; min-height: 100vh; }
|
|
79
|
+
/* The sidebar itself no longer scrolls: the nav does. A sticky footer inside a
|
|
80
|
+
scrolling column still has the rest of the list running underneath it, which
|
|
81
|
+
showed as nav items bleeding through the account block. */
|
|
79
82
|
.sidebar { background: var(--surface); border-right: 1px solid var(--border);
|
|
80
|
-
padding: 14px 0; position: sticky; top:0; height:100vh; overflow
|
|
83
|
+
padding: 14px 0; position: sticky; top:0; height:100vh; overflow:hidden;
|
|
81
84
|
display:flex; flex-direction:column; }
|
|
82
85
|
.brand { padding: 0 16px 14px; border-bottom: 1px solid var(--border); margin-bottom: 10px; }
|
|
83
86
|
.brand .mark { display:flex; align-items:center; gap:8px; font-weight:660; font-size:14px;
|
|
84
87
|
letter-spacing:-0.01em; }
|
|
85
88
|
.brand .dot { width:9px; height:9px; border-radius:3px; background:var(--s2); flex:none; }
|
|
86
89
|
.brand .sub { font-size:10.5px; color:var(--muted); margin-top:3px; letter-spacing:.02em; }
|
|
87
|
-
.nav { display:flex; flex-direction:column; gap:1px; padding: 0 8px;
|
|
90
|
+
.nav { display:flex; flex-direction:column; gap:1px; padding: 0 8px;
|
|
91
|
+
flex:1 1 auto; min-height:0; overflow-y:auto; }
|
|
88
92
|
.nav .group { font-size:9.5px; text-transform:uppercase; letter-spacing:.09em; color:var(--muted);
|
|
89
93
|
padding: 13px 8px 5px; font-weight:600; }
|
|
90
94
|
.nav a { display:flex; align-items:center; gap:8px; padding:6px 9px; border-radius:7px;
|
|
@@ -401,8 +405,7 @@ table.tbl .sub { font-size:10.5px; color:var(--muted); }
|
|
|
401
405
|
so every screenshot carries the name of the account it came from. */
|
|
402
406
|
/* Sticky, because the nav is taller than the viewport and an identity you have
|
|
403
407
|
to scroll to find is one nobody checks. */
|
|
404
|
-
.who {
|
|
405
|
-
display:flex; align-items:center; gap:9px;
|
|
408
|
+
.who { flex:none; display:flex; align-items:center; gap:9px;
|
|
406
409
|
padding:12px 16px; background:var(--surface);
|
|
407
410
|
border-top:1px solid var(--border); }
|
|
408
411
|
.who:empty { display:none; }
|