ccc-notifier 0.2.0 → 0.3.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.
- package/README.md +15 -9
- package/dist/{budget-5H2GQRXH.js → budget-KKTFYAXH.js} +2 -2
- package/dist/{chunk-KUJZYZSG.js → chunk-4RZ6OGTD.js} +1 -1
- package/dist/{chunk-OXMHOVUL.js → chunk-7KVOQ4UZ.js} +228 -34
- package/dist/chunk-DSV75EF7.js +357 -0
- package/dist/{chunk-IIYMGLV4.js → chunk-ECADO26T.js} +9 -2
- package/dist/chunk-HTYUYKFW.js +21 -0
- package/dist/{chunk-TBFKGFZX.js → chunk-J5QAYTFE.js} +3 -0
- package/dist/{chunk-OEG3AVU6.js → chunk-LHKBGA5K.js} +27 -1
- package/dist/{chunk-4JNZ7BHO.js → chunk-NV5UOHJA.js} +1 -1
- package/dist/{chunk-64N5SGTT.js → chunk-QX5KIRSU.js} +109 -13
- package/dist/cli.js +67 -16
- package/dist/{dashboard-LKK6NOBN.js → dashboard-TH3NOVT3.js} +3 -3
- package/dist/{history-MWFHO5VR.js → history-DLFYQJFM.js} +1 -1
- package/dist/{mute-2JW3NQXN.js → mute-EPLYH67P.js} +2 -2
- package/dist/{setup-IXPUR4CM.js → setup-PTO5N46B.js} +5 -4
- package/dist/{sweep-XKKODGMA.js → sweep-25EZAOGC.js} +121 -9
- package/dist/{track-76Q5CZM5.js → track-PXFSGMGL.js} +29 -13
- package/package.json +5 -2
- package/dist/chunk-TB5A7U7G.js +0 -82
|
@@ -7,12 +7,12 @@ import {
|
|
|
7
7
|
formatTokens,
|
|
8
8
|
formatUSD,
|
|
9
9
|
modelDisplayName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-J5QAYTFE.js";
|
|
11
11
|
import {
|
|
12
12
|
paths,
|
|
13
13
|
readConfig,
|
|
14
14
|
readTurns
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-ECADO26T.js";
|
|
16
16
|
|
|
17
17
|
// src/dashboard.ts
|
|
18
18
|
import { spawn, spawnSync } from "child_process";
|
|
@@ -170,7 +170,7 @@ function buildTurnEmbed(rec, map) {
|
|
|
170
170
|
};
|
|
171
171
|
}
|
|
172
172
|
const ms = Date.parse(rec.ts);
|
|
173
|
-
|
|
173
|
+
const out = {
|
|
174
174
|
t: Number.isFinite(ms) ? ms : 0,
|
|
175
175
|
ts: fmtLocalDateTime(rec.ts),
|
|
176
176
|
p: basename(rec.project) || rec.project || "(unknown)",
|
|
@@ -187,6 +187,8 @@ function buildTurnEmbed(rec, map) {
|
|
|
187
187
|
tr: truncated,
|
|
188
188
|
sa
|
|
189
189
|
};
|
|
190
|
+
if (rec.source === "codex") out.sc = "codex";
|
|
191
|
+
return out;
|
|
190
192
|
}
|
|
191
193
|
function computeKpis(turns) {
|
|
192
194
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -331,6 +333,7 @@ section.card > .note{color:var(--muted); font-size:12px; margin:0 0 14px;}
|
|
|
331
333
|
.turns .c-time,.turns .c-model{white-space:nowrap;}
|
|
332
334
|
.turns .c-proj{max-width:160px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
|
|
333
335
|
.turns .c-prompt{color:var(--ink2);}
|
|
336
|
+
.src-badge{display:inline-block; margin-left:6px; padding:1px 6px; border-radius:6px; font-size:11px; font-weight:600; line-height:1.4; background:var(--plane); color:var(--ink2); border:1px solid var(--border); vertical-align:middle;}
|
|
334
337
|
.turn-row{cursor:pointer;}
|
|
335
338
|
.turn-row:hover{background:color-mix(in srgb, var(--ink) 4%, transparent);}
|
|
336
339
|
.turn-row:focus-visible{outline:2px solid var(--s1); outline-offset:-2px;}
|
|
@@ -418,17 +421,37 @@ var APP_JS = `<script>
|
|
|
418
421
|
function ssGet(k){ try { return sessionStorage.getItem(k); } catch(e){ return null; } }
|
|
419
422
|
function ssSet(k, v){ try { sessionStorage.setItem(k, v); } catch(e){} }
|
|
420
423
|
var GRAN = ssGet('cccn-gran'); if(['day','week','month'].indexOf(GRAN) < 0) GRAN = 'day';
|
|
424
|
+
// \u30BD\u30FC\u30B9(Claude/Codex)\u30D5\u30A3\u30EB\u30BF\u3002\u30C1\u30C3\u30D7\u304C\u63CF\u753B\u3055\u308C\u3066\u3044\u308B(=Codex \u30EC\u30B3\u30FC\u30C9\u304C\u5B58\u5728\u3059\u308B)\u3068\u304D\u306E\u307F\u6709\u52B9\u3002
|
|
425
|
+
// \u65E2\u5B9A 'all'\u3002sessionStorage \u306B\u4FDD\u5B58\u3057\u81EA\u52D5\u30EA\u30ED\u30FC\u30C9(meta refresh)\u3092\u8DE8\u3044\u3067\u7DAD\u6301\u3059\u308B(cccn-gran \u3068\u540C\u3058\u4ED5\u7D44\u307F)\u3002
|
|
426
|
+
var HAS_CODEX = document.querySelectorAll('[data-src]').length > 0;
|
|
427
|
+
var SRC = ssGet('cccn-src'); if(['all','claude','codex'].indexOf(SRC) < 0) SRC = 'all';
|
|
428
|
+
// \u8FF0\u8A9E: claude \u2192 sc \u306A\u3057 / codex \u2192 sc==='codex' / all \u2192 \u5168\u4EF6\u3002Codex \u7121\u3057(\u30C1\u30C3\u30D7\u7121\u3057)\u306A\u3089\u5E38\u306B\u5168\u4EF6\u3002
|
|
429
|
+
function activeTurns(){
|
|
430
|
+
if(!HAS_CODEX || SRC === 'all') return turns;
|
|
431
|
+
if(SRC === 'codex') return turns.filter(function(tn){ return tn.sc === 'codex'; });
|
|
432
|
+
return turns.filter(function(tn){ return !tn.sc; });
|
|
433
|
+
}
|
|
421
434
|
// \u65E2\u5B9A\u306F\u300C\u8D77\u52D5\u3057\u305F\u65E5\u300D\u3092\u521D\u671F\u9078\u629E\u3059\u308B(\u672A\u4FDD\u5B58\u6642)\u3002\u660E\u793A\u7684\u306A\u901A\u7B97\u306F '__all__'\u3001\u305D\u306E\u4ED6\u306F\u4FDD\u5B58\u30AD\u30FC\u3002
|
|
422
435
|
var storedSel = ssGet('cccn-sel');
|
|
423
436
|
var SEL = (storedSel === null) ? defaultSel(GRAN) : (storedSel === '__all__' ? null : storedSel);
|
|
424
437
|
function setGran(g){ GRAN = g; ssSet('cccn-gran', g); }
|
|
425
438
|
function setSel(v){ SEL = v; ssSet('cccn-sel', v === null ? '__all__' : v); }
|
|
439
|
+
// \u30BD\u30FC\u30B9\u5207\u66FF\u3002\u30D5\u30A3\u30EB\u30BF\u5F8C\u306B\u9078\u629E\u4E2D\u30D0\u30B1\u30C3\u30C8\u304C\u6D88\u3048\u305F\u3089\u901A\u7B97\u3078\u5012\u3059(\u7A7A\u8868\u793A\u306E\u8AA4\u89E3\u9632\u6B62\u30FBgran \u30C8\u30B0\u30EB\u3068\u540C\u3058\u6D41\u5100)\u3002
|
|
440
|
+
function setSrc(s){
|
|
441
|
+
SRC = s; ssSet('cccn-src', s);
|
|
442
|
+
if(SEL !== null){
|
|
443
|
+
var present = false, bk = buildBuckets(GRAN);
|
|
444
|
+
for(var i=0;i<bk.length;i++){ if(bk[i].key === SEL){ present = true; break; } }
|
|
445
|
+
if(!present) setSel(null);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
426
448
|
var lastRenderedGran = null; // \u76F4\u524D\u306B\u63CF\u753B\u3057\u305F\u7C92\u5EA6\u3002\u5909\u308F\u3063\u305F\u3068\u304D(=\u30D0\u30B1\u30C3\u30C8\u6570\u304C\u5909\u308F\u308B\u3068\u304D)\u3060\u3051\u53F3\u7AEF\u3078\u5BC4\u305B\u308B\u3002
|
|
427
449
|
|
|
428
450
|
function buildBuckets(gran){
|
|
451
|
+
var src = activeTurns();
|
|
429
452
|
var map = {}; var keys = [];
|
|
430
|
-
for(var i=0;i<
|
|
431
|
-
var tn =
|
|
453
|
+
for(var i=0;i<src.length;i++){
|
|
454
|
+
var tn = src[i];
|
|
432
455
|
var k = bucketKey(tn.t, gran);
|
|
433
456
|
if(k === null) continue;
|
|
434
457
|
var b = map[k];
|
|
@@ -452,8 +475,9 @@ var APP_JS = `<script>
|
|
|
452
475
|
}
|
|
453
476
|
|
|
454
477
|
function turnsInSelection(){
|
|
455
|
-
|
|
456
|
-
|
|
478
|
+
var src = activeTurns();
|
|
479
|
+
if(SEL === null) return src;
|
|
480
|
+
return src.filter(function(tn){ return bucketKey(tn.t, GRAN) === SEL; });
|
|
457
481
|
}
|
|
458
482
|
|
|
459
483
|
// ---- SVG \u30D8\u30EB\u30D1\u30FC ----
|
|
@@ -726,6 +750,12 @@ var APP_JS = `<script>
|
|
|
726
750
|
sub.textContent = ' ' + mk + (mk === curMonth ? '(\u4ECA\u6708)' : '');
|
|
727
751
|
h.appendChild(sub);
|
|
728
752
|
budgetEl.appendChild(h);
|
|
753
|
+
// \u4E88\u7B97\u30AB\u30FC\u30C9\u306F\u5E38\u306B\u5168\u30BD\u30FC\u30B9\u5408\u7B97(\u30BD\u30FC\u30B9\u30D5\u30A3\u30EB\u30BF\u975E\u9023\u52D5)\u3002Codex \u304C\u3042\u308B\u6642\u3060\u3051\u305D\u306E\u65E8\u3092\u660E\u8A18\u3059\u308B\u3002
|
|
754
|
+
if(HAS_CODEX){
|
|
755
|
+
var srcNote = document.createElement('p'); srcNote.className = 'note';
|
|
756
|
+
srcNote.textContent = '\u5168\u30BD\u30FC\u30B9\u5408\u7B97 / all sources';
|
|
757
|
+
budgetEl.appendChild(srcNote);
|
|
758
|
+
}
|
|
729
759
|
|
|
730
760
|
var bar = document.createElement('div'); bar.className = 'budget-bar';
|
|
731
761
|
var fill = document.createElement('div'); fill.className = 'budget-fill lvl-' + level;
|
|
@@ -746,6 +776,55 @@ var APP_JS = `<script>
|
|
|
746
776
|
budgetEl.appendChild(foot);
|
|
747
777
|
}
|
|
748
778
|
|
|
779
|
+
// ---- KPI(\u4ECA\u65E5/\u4ECA\u9031/\u4ECA\u6708/\u901A\u7B97)+ \u30D2\u30FC\u30ED\u30FC(\u901A\u7B97\u30D0\u30CA\u30FC)----
|
|
780
|
+
// \u30BD\u30FC\u30B9\u30D5\u30A3\u30EB\u30BF\u9023\u52D5\u3002Codex \u7121\u3057\u306A\u3089\u30B5\u30FC\u30D0\u63CF\u753B\u306E\u307E\u307E(\u65E2\u5B58\u6319\u52D5\u30921px\u3082\u5909\u3048\u306A\u3044\u305F\u3081\u4F55\u3082\u3057\u306A\u3044)\u3002
|
|
781
|
+
// \u30AB\u30FC\u30C9\u306F .kpi \u5185\u306E .stat \u3092\u9806\u306B today / week / month / all \u3068\u3057\u3066\u66F4\u65B0\u3059\u308B(\u30B5\u30FC\u30D0\u63CF\u753B\u9806\u306B\u4E00\u81F4)\u3002
|
|
782
|
+
// \u30D2\u30FC\u30ED\u30FC\u306F\u30D5\u30A3\u30EB\u30BF\u5F8C\u306E\u5168\u671F\u9593\u5408\u8A08\u306B\u5DEE\u3057\u66FF\u3048\u3001SA \u5185\u8A33\u884C\u306F SA \u5408\u8A08\u30BC\u30ED\u306A\u3089\u884C\u3054\u3068\u96A0\u3059
|
|
783
|
+
// (Codex \u30EC\u30B3\u30FC\u30C9\u306F SA \u3092\u6301\u305F\u306A\u3044\u305F\u3081 Codex \u30D5\u30A3\u30EB\u30BF\u6642\u306F\u5FC5\u7136\u7684\u306B\u975E\u8868\u793A)\u3002\u884C\u306E\u6587\u8A00\u306F\u30B5\u30FC\u30D0\u63CF\u753B\u306E
|
|
784
|
+
// \u63A5\u982D\u8F9E($ \u306E\u624B\u524D\u307E\u3067)\u3092\u518D\u5229\u7528\u3057\u3066\u6570\u5024\u90E8\u5206\u3060\u3051\u7D44\u307F\u76F4\u3059(APP_JS \u306B\u8868\u793A\u6587\u8A00\u3092\u91CD\u8907\u3055\u305B\u306A\u3044)\u3002
|
|
785
|
+
var kpiCards = document.querySelectorAll('.kpi .stat');
|
|
786
|
+
var heroValueEl = document.querySelector('.hero .hero-value');
|
|
787
|
+
var heroMetaEls = document.querySelectorAll('.hero .hero-meta');
|
|
788
|
+
var heroSaEl = heroMetaEls.length > 1 ? heroMetaEls[1] : null; // SA \u884C(SA \u3042\u308A\u306E\u3068\u304D\u3060\u3051\u30B5\u30FC\u30D0\u304C\u63CF\u753B)
|
|
789
|
+
var heroSaPrefix = heroSaEl ? ((heroSaEl.textContent || '').split('$')[0]) : '';
|
|
790
|
+
function setKpiCard(card, tot){
|
|
791
|
+
if(!card) return;
|
|
792
|
+
var v = card.querySelector('.stat-value');
|
|
793
|
+
var m = card.querySelector('.stat-meta');
|
|
794
|
+
if(v) v.textContent = formatUSD(tot.usd);
|
|
795
|
+
if(m) m.textContent = formatJPY(tot.jpy) + ' \xB7 ' + tot.turns + ' \u30BF\u30FC\u30F3';
|
|
796
|
+
}
|
|
797
|
+
function renderKpis(){
|
|
798
|
+
if(!HAS_CODEX) return;
|
|
799
|
+
var src = activeTurns();
|
|
800
|
+
var now = new Date();
|
|
801
|
+
var y = now.getFullYear(), mo = now.getMonth(), d = now.getDate();
|
|
802
|
+
var weekCutoff = Date.now() - 7*86400000;
|
|
803
|
+
var today = {usd:0,jpy:0,turns:0}, week = {usd:0,jpy:0,turns:0}, month = {usd:0,jpy:0,turns:0}, all = {usd:0,jpy:0,turns:0};
|
|
804
|
+
var saUsd = 0, saJpy = 0;
|
|
805
|
+
for(var i=0;i<src.length;i++){
|
|
806
|
+
var tn = src[i], bs = tn.bs || {}, fx = tn.fx || 0, u = 0;
|
|
807
|
+
for(var s in bs){ if(bs.hasOwnProperty(s)) u += bs[s]; }
|
|
808
|
+
var j = u * fx;
|
|
809
|
+
if(tn.sa){ var sau = u - (tn.um || 0); saUsd += sau; saJpy += sau * fx; } // SA \u5206 = \u7DCF\u984D \u2212 \u30E1\u30A4\u30F3
|
|
810
|
+
all.usd += u; all.jpy += j; all.turns++;
|
|
811
|
+
var dt = new Date(tn.t);
|
|
812
|
+
if(isNaN(dt.getTime())) continue;
|
|
813
|
+
if(dt.getFullYear()===y && dt.getMonth()===mo && dt.getDate()===d){ today.usd+=u; today.jpy+=j; today.turns++; }
|
|
814
|
+
if(tn.t >= weekCutoff){ week.usd+=u; week.jpy+=j; week.turns++; }
|
|
815
|
+
if(dt.getFullYear()===y && dt.getMonth()===mo){ month.usd+=u; month.jpy+=j; month.turns++; }
|
|
816
|
+
}
|
|
817
|
+
if(kpiCards.length >= 4){
|
|
818
|
+
setKpiCard(kpiCards[0], today); setKpiCard(kpiCards[1], week); setKpiCard(kpiCards[2], month); setKpiCard(kpiCards[3], all);
|
|
819
|
+
}
|
|
820
|
+
if(heroValueEl) heroValueEl.textContent = formatUSD(all.usd);
|
|
821
|
+
if(heroMetaEls.length > 0) heroMetaEls[0].textContent = formatJPY(all.jpy) + ' \xB7 ' + all.turns + ' \u30BF\u30FC\u30F3';
|
|
822
|
+
if(heroSaEl){
|
|
823
|
+
heroSaEl.hidden = !(saUsd > 0);
|
|
824
|
+
if(saUsd > 0) heroSaEl.textContent = heroSaPrefix + formatUSD(saUsd) + '(' + formatJPY(saJpy) + ')';
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
749
828
|
// ---- \u30BF\u30FC\u30F3\u5C65\u6B74 ----
|
|
750
829
|
// \u5168\u671F\u9593\u3060\u3068\u6570\u5343\u884C\u306B\u306A\u308A\u30DA\u30FC\u30B8\u304C\u6975\u7AEF\u306B\u9577\u304F\u30FB\u91CD\u304F\u306A\u308B\u305F\u3081\u3001DOM \u63CF\u753B\u306F\u6700\u5927 HIST_CAP \u4EF6\u306B\u6291\u3048\u308B\u3002
|
|
751
830
|
// \u691C\u7D22\u306F\u9078\u629E\u4E2D\u306E\u5168\u30BF\u30FC\u30F3\u3092\u5BFE\u8C61\u306B\u3057\u3001\u4E00\u81F4\u4EF6\u6570\u3092\u4EF6\u6570\u8868\u793A\u306B\u51FA\u3059(\u5148\u982D HIST_CAP \u4EF6\u3060\u3051\u63CF\u753B)\u3002
|
|
@@ -765,7 +844,14 @@ var APP_JS = `<script>
|
|
|
765
844
|
function cell(text, cls){ var td = document.createElement('td'); if(cls) td.className = cls; td.textContent = text; tr.appendChild(td); return td; }
|
|
766
845
|
cell(t.ts || '', 'c-time');
|
|
767
846
|
cell(t.p || '', 'c-proj');
|
|
768
|
-
cell(t.md || '', 'c-model');
|
|
847
|
+
var mcell = cell(t.md || '', 'c-model');
|
|
848
|
+
// Codex \u7531\u6765\u306F\u30E2\u30C7\u30EB\u540D\u306E\u96A3\u306B\u5C0F\u3055\u306A Codex \u30D0\u30C3\u30B8\u3002\u52D5\u7684\u5024\u306F\u5165\u308C\u305A\u9759\u7684\u30C6\u30AD\u30B9\u30C8\u3092 textContent \u3067\u633F\u5165\u3002
|
|
849
|
+
if(t.sc === 'codex'){
|
|
850
|
+
mcell.appendChild(document.createTextNode(' '));
|
|
851
|
+
var badge = document.createElement('span'); badge.className = 'src-badge';
|
|
852
|
+
badge.textContent = 'Codex';
|
|
853
|
+
mcell.appendChild(badge);
|
|
854
|
+
}
|
|
769
855
|
cell(t.ti || '', 'c-num');
|
|
770
856
|
cell(t.to || '', 'c-num');
|
|
771
857
|
cell(formatUSD(t.um || 0), 'c-num');
|
|
@@ -832,6 +918,8 @@ var APP_JS = `<script>
|
|
|
832
918
|
for(var i=0;i<gbtns.length;i++){ gbtns[i].classList.toggle('active', gbtns[i].getAttribute('data-gran') === GRAN); }
|
|
833
919
|
var allBtn = document.getElementById('cccn-all');
|
|
834
920
|
if(allBtn) allBtn.classList.toggle('active', SEL === null);
|
|
921
|
+
var sbtns = document.querySelectorAll('[data-src]');
|
|
922
|
+
for(var k=0;k<sbtns.length;k++){ sbtns[k].classList.toggle('active', sbtns[k].getAttribute('data-src') === SRC); }
|
|
835
923
|
}
|
|
836
924
|
|
|
837
925
|
// ---- \u5168\u4F53\u30EC\u30F3\u30C0\u30EA\u30F3\u30B0 ----
|
|
@@ -839,6 +927,7 @@ var APP_JS = `<script>
|
|
|
839
927
|
var sub = turnsInSelection();
|
|
840
928
|
renderChart();
|
|
841
929
|
renderBudget();
|
|
930
|
+
renderKpis();
|
|
842
931
|
renderByModel(sub);
|
|
843
932
|
renderByProject(sub);
|
|
844
933
|
renderHistory(sub);
|
|
@@ -853,6 +942,10 @@ var APP_JS = `<script>
|
|
|
853
942
|
}
|
|
854
943
|
var allBtn = document.getElementById('cccn-all');
|
|
855
944
|
if(allBtn) allBtn.addEventListener('click', function(){ setSel(null); render(); });
|
|
945
|
+
var srcBtns = document.querySelectorAll('[data-src]');
|
|
946
|
+
for(var sbi=0;sbi<srcBtns.length;sbi++){
|
|
947
|
+
(function(btn){ btn.addEventListener('click', function(){ setSrc(btn.getAttribute('data-src')); render(); }); })(srcBtns[sbi]);
|
|
948
|
+
}
|
|
856
949
|
if(search){
|
|
857
950
|
var saved = ssGet('cccn-search');
|
|
858
951
|
if(saved !== null) search.value = saved;
|
|
@@ -879,13 +972,13 @@ function renderLegend(slots) {
|
|
|
879
972
|
const items = slots.map((m) => `<span class="legend-item"><span class="swatch k${m.slot}"></span>${esc(m.name)}</span>`).join("");
|
|
880
973
|
return `<div class="legend">${items}</div>`;
|
|
881
974
|
}
|
|
882
|
-
function budgetCard(budgetUSD, month, fallbackRate) {
|
|
975
|
+
function budgetCard(budgetUSD, month, fallbackRate, hasCodex) {
|
|
883
976
|
if (!(budgetUSD > 0)) return "";
|
|
884
977
|
const pct = month.usd / budgetUSD * 100;
|
|
885
978
|
const width = Math.max(0, Math.min(100, pct));
|
|
886
979
|
const level = pct >= 100 ? "over" : pct >= 70 ? "warn" : "ok";
|
|
887
980
|
const budgetJpy = budgetUSD * fallbackRate;
|
|
888
|
-
return `<section class="card" id="cccn-budget"><h2>\u6708\u4E88\u7B97 / Monthly budget<span class="stat-sub"> \u4ECA\u6708(\u66A6\u6708)</span></h2
|
|
981
|
+
return `<section class="card" id="cccn-budget"><h2>\u6708\u4E88\u7B97 / Monthly budget<span class="stat-sub"> \u4ECA\u6708(\u66A6\u6708)</span></h2>` + (hasCodex ? `<p class="note">\u5168\u30BD\u30FC\u30B9\u5408\u7B97 / all sources</p>` : "") + `<div class="budget-bar"><div class="budget-fill lvl-${level}" style="width:${width.toFixed(1)}%"></div></div><div class="budget-foot"><span>\u4ECA\u6708 <b>${esc(formatUSD(month.usd))}</b> / ${esc(formatUSD(budgetUSD))} <span class="muted">(${esc(formatJPY(month.jpy))} / ${esc(formatJPY(budgetJpy))})</span></span><span class="budget-pct lvl-${level}">${pct.toFixed(1)}% used</span></div></section>`;
|
|
889
982
|
}
|
|
890
983
|
function escapeJsonForScript(json) {
|
|
891
984
|
return json.replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
@@ -901,6 +994,7 @@ function renderDashboard(turns, opts) {
|
|
|
901
994
|
const turnsEmbed = turns.map((rec) => buildTurnEmbed(rec, map));
|
|
902
995
|
const anyTruncated = turnsEmbed.some((t) => t.tr);
|
|
903
996
|
const anySub = turns.some((r) => r.subagents);
|
|
997
|
+
const anyCodex = turns.some((r) => r.source === "codex");
|
|
904
998
|
let subUsd = 0;
|
|
905
999
|
let subJpy = 0;
|
|
906
1000
|
for (const r of turns) {
|
|
@@ -929,7 +1023,8 @@ function renderDashboard(turns, opts) {
|
|
|
929
1023
|
const dataJson = escapeJsonForScript(JSON.stringify(embed));
|
|
930
1024
|
const reloadSec = Number.isFinite(opts.autoReloadSec) && opts.autoReloadSec > 0 ? Math.floor(opts.autoReloadSec) : 0;
|
|
931
1025
|
const refreshMeta = reloadSec > 0 ? `<meta http-equiv="refresh" content="${reloadSec}">` : "";
|
|
932
|
-
const
|
|
1026
|
+
const updateTrigger = anyCodex ? "Claude Code / Codex \u306E\u5FDC\u7B54\u5B8C\u4E86\u6642" : "Claude Code \u306E\u5FDC\u7B54\u5B8C\u4E86\u6642";
|
|
1027
|
+
const autoUpdateFoot = reloadSec > 0 ? `<div class="foot">\u7D04 ${reloadSec} \u79D2\u3054\u3068\u306B\u81EA\u52D5\u66F4\u65B0(\u6700\u65B0\u5316\u306F ${updateTrigger})</div>` : "";
|
|
933
1028
|
const head = `<!doctype html><html lang="ja"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="color-scheme" content="light dark">` + refreshMeta + `<title>ccc-notifier \u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9</title>` + STYLE + `</head><body><div class="wrap">`;
|
|
934
1029
|
const foot = autoUpdateFoot + `<div class="foot">ccc-notifier v${esc(version)} \xB7 \u30C7\u30FC\u30BF\u306F\u30ED\u30FC\u30AB\u30EB\u306E\u307F / all data stays local</div></div><div id="cccn-tip" class="cccn-tip" hidden></div><script id="cccn-data" type="application/json">${dataJson}</script>` + APP_JS + `</body></html>`;
|
|
935
1030
|
if (turns.length === 0) {
|
|
@@ -939,8 +1034,9 @@ function renderDashboard(turns, opts) {
|
|
|
939
1034
|
}
|
|
940
1035
|
const header = `<div class="head"><div><h1>ccc-notifier \u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9</h1><div class="sub">${esc(period)}<span class="muted"> \xB7 ${esc(rangeText)}</span></div><div class="sub muted">\u751F\u6210 ${esc(generatedAt)} / generated</div></div><div class="hero"><div class="hero-label">\u901A\u7B97 / Total</div><div class="hero-value">${esc(formatUSD(kpi.all.usd))}</div><div class="hero-meta">${esc(formatJPY(kpi.all.jpy))} \xB7 ${kpi.all.turns} \u30BF\u30FC\u30F3</div>` + (anySub ? `<div class="hero-meta">\u3046\u3061\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8 ${esc(formatUSD(subUsd))}(${esc(formatJPY(subJpy))})</div>` : "") + `</div></div>`;
|
|
941
1036
|
const kpiSection = `<div class="kpi">` + statCard("\u4ECA\u65E5", "Today", kpi.today) + statCard("\u4ECA\u9031", "\u76F4\u8FD17\u65E5", kpi.week) + statCard("\u4ECA\u6708", "\u66A6\u6708", kpi.month) + statCard("\u901A\u7B97", "\u5168\u671F\u9593", kpi.all) + `</div>`;
|
|
942
|
-
const budgetSection = budgetCard(budgetUSD, kpi.month, cfg.fx.fallbackRate);
|
|
943
|
-
const
|
|
1037
|
+
const budgetSection = budgetCard(budgetUSD, kpi.month, cfg.fx.fallbackRate, anyCodex);
|
|
1038
|
+
const srcToggle = anyCodex ? `<div class="seg-toggle" id="cccn-src-toggle"><button type="button" data-src="all">\u5168\u4F53</button><button type="button" data-src="claude">Claude</button><button type="button" data-src="codex">Codex</button></div>` : "";
|
|
1039
|
+
const chartSection = `<section class="card"><h2>\u30B3\u30B9\u30C8\u63A8\u79FB / Cost over time</h2><p class="note">\u7C92\u5EA6\u3092 \u65E5 / \u9031 / \u6708 \u3067\u5207\u308A\u66FF\u3048\u3089\u308C\u307E\u3059(\u6A2A\u30B9\u30AF\u30ED\u30FC\u30EB\u3067\u904E\u53BB\u307E\u3067)\u3002\u68D2\u3092\u30AF\u30EA\u30C3\u30AF\u3059\u308B\u3068\u305D\u306E\u671F\u9593\u304C\u9078\u629E\u3055\u308C\u3001\u4E0B\u306E\u30E2\u30C7\u30EB\u5225\u30FB\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u5225\u30FB\u5C65\u6B74\u304C\u9023\u52D5\u3057\u307E\u3059\u3002\u300C\u901A\u7B97\u300D\u3067\u5168\u671F\u9593\u306B\u623B\u308A\u307E\u3059\u3002\u30E2\u30C7\u30EB\u5225\u306B\u8272\u5206\u3051\u3002</p><div class="toolbar-row"><div class="seg-toggle"><button type="button" data-gran="day">\u65E5</button><button type="button" data-gran="week">\u9031</button><button type="button" data-gran="month">\u6708</button></div><button type="button" id="cccn-all" class="btn">\u901A\u7B97</button>` + srcToggle + `<span id="cccn-sel-label" class="sel-label"></span></div>` + renderLegend(map.slots) + `<div class="chart-scroll"><div id="cccn-chart"></div></div></section>`;
|
|
944
1040
|
const breakdownSection = `<div class="grid2"><section class="card"><h2>\u30E2\u30C7\u30EB\u5225\u5185\u8A33 / By model</h2><p class="note">\u9078\u629E\u4E2D\u306E\u671F\u9593(\u65E2\u5B9A\u306F\u901A\u7B97)\u306E\u30B3\u30B9\u30C8\u964D\u9806\u3002\u8907\u6570\u30E2\u30C7\u30EB\u306E\u30BF\u30FC\u30F3\u306F\u5404\u30E2\u30C7\u30EB\u306B1\u305A\u3064\u8A08\u4E0A\u3002</p><div class="table-wrap" id="cccn-bymodel"></div></section><section class="card"><h2>\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u5225 / By project</h2><p class="note">\u9078\u629E\u4E2D\u306E\u671F\u9593\u306E\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8(\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA basename)\u5358\u4F4D\u30FB\u30B3\u30B9\u30C8\u964D\u9806\u3002</p><div class="table-wrap" id="cccn-byproject"></div></section></div>`;
|
|
945
1041
|
const capNote = "\u4EF6\u6570\u304C\u591A\u3044\u5834\u5408\u306F\u65B0\u3057\u3044\u9806\u306B\u5148\u982D200\u4EF6\u306E\u307F\u63CF\u753B\u3057\u307E\u3059(\u691C\u7D22\u3084\u3001\u4E0A\u306E\u30B0\u30E9\u30D5\u3067\u671F\u9593\u3092\u9078\u3076\u3068\u7D5E\u308A\u8FBC\u3081\u307E\u3059)\u3002";
|
|
946
1042
|
const truncNote = anyTruncated ? `<p class="note">\u9078\u629E\u4E2D\u306E\u671F\u9593\u306E\u30BF\u30FC\u30F3\u3092\u65B0\u3057\u3044\u9806\u306B\u8868\u793A\u3057\u307E\u3059\u3002${capNote}\u30D7\u30ED\u30F3\u30D7\u30C8\u306F1\u4EF6\u3042\u305F\u308A\u6700\u5927 ${PROMPT_MAX.toLocaleString("en-US")} \u5B57\u307E\u3067(\u8D85\u904E\u5206\u306F\u300C${esc(PROMPT_TRUNC_MARK)}\u300D)\u3002\u884C\u30AF\u30EA\u30C3\u30AF\u3067\u5168\u6587\u5C55\u958B\u3002</p>` : `<p class="note">\u9078\u629E\u4E2D\u306E\u671F\u9593\u306E\u30BF\u30FC\u30F3\u3092\u65B0\u3057\u3044\u9806\u306B\u8868\u793A\u3057\u307E\u3059\u3002${capNote}\u884C\u30AF\u30EA\u30C3\u30AF\u3067\u30D7\u30ED\u30F3\u30D7\u30C8\u5168\u6587\u3092\u5C55\u958B\u3057\u307E\u3059\u3002</p>`;
|
package/dist/cli.js
CHANGED
|
@@ -1,36 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
fmtMuteUntil
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4RZ6OGTD.js";
|
|
5
5
|
import {
|
|
6
|
+
codexHooksFile,
|
|
6
7
|
matchesMarker
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-7KVOQ4UZ.js";
|
|
8
9
|
import {
|
|
9
10
|
notifyOS,
|
|
10
11
|
notifySlack,
|
|
11
12
|
selectNotifyBackend
|
|
12
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-NV5UOHJA.js";
|
|
13
14
|
import {
|
|
14
15
|
isWSL
|
|
15
16
|
} from "./chunk-DGXUSPS4.js";
|
|
17
|
+
import {
|
|
18
|
+
codexHome,
|
|
19
|
+
detectCodex
|
|
20
|
+
} from "./chunk-HTYUYKFW.js";
|
|
16
21
|
import {
|
|
17
22
|
aggregateNewTurn,
|
|
18
23
|
computeCost,
|
|
19
24
|
getUsdJpy,
|
|
20
25
|
loadPriceTable
|
|
21
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-LHKBGA5K.js";
|
|
22
27
|
import {
|
|
23
28
|
formatJPY,
|
|
24
29
|
formatTokens,
|
|
25
30
|
formatUSD
|
|
26
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-J5QAYTFE.js";
|
|
27
32
|
import {
|
|
28
33
|
isMuted,
|
|
29
34
|
paths,
|
|
30
35
|
readConfig,
|
|
31
36
|
readMuteState,
|
|
32
37
|
readTurns
|
|
33
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-ECADO26T.js";
|
|
34
39
|
|
|
35
40
|
// src/cli.ts
|
|
36
41
|
import { realpathSync } from "fs";
|
|
@@ -156,6 +161,50 @@ async function checkHookRegistration() {
|
|
|
156
161
|
}
|
|
157
162
|
return true;
|
|
158
163
|
}
|
|
164
|
+
async function checkCodex() {
|
|
165
|
+
if (!detectCodex()) {
|
|
166
|
+
log("ok", "Codex CLI \u306F\u672A\u691C\u51FA\u3067\u3059(\u672A\u4F7F\u7528\u306A\u3089\u554F\u984C\u3042\u308A\u307E\u305B\u3093)");
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
const hooksFile = codexHooksFile();
|
|
170
|
+
const matchedCommands = [];
|
|
171
|
+
if (existsSync(hooksFile)) {
|
|
172
|
+
try {
|
|
173
|
+
const raw = await readFile(hooksFile, "utf8");
|
|
174
|
+
const parsed = JSON.parse(raw);
|
|
175
|
+
if (isRecord(parsed)) {
|
|
176
|
+
const hooks = parsed.hooks;
|
|
177
|
+
const stopEntries = isRecord(hooks) ? hooks.Stop : void 0;
|
|
178
|
+
if (Array.isArray(stopEntries)) {
|
|
179
|
+
for (const entry of stopEntries) {
|
|
180
|
+
if (!isRecord(entry)) continue;
|
|
181
|
+
const innerHooks = entry.hooks;
|
|
182
|
+
if (!Array.isArray(innerHooks)) continue;
|
|
183
|
+
for (const h of innerHooks) {
|
|
184
|
+
if (isRecord(h) && typeof h.command === "string" && matchesMarker(h.command)) {
|
|
185
|
+
matchedCommands.push(h.command);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (matchedCommands.length > 0) {
|
|
195
|
+
log("ok", `Codex \u306E Stop hook \u304C\u767B\u9332\u3055\u308C\u3066\u3044\u307E\u3059: ${matchedCommands.join(" / ")}`);
|
|
196
|
+
log("ok", "codex \u5074\u3067 hook \u3092\u627F\u8A8D\u6E08\u307F\u304B\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044(\u672A\u627F\u8A8D\u3060\u3068\u901A\u77E5\u3055\u308C\u307E\u305B\u3093)");
|
|
197
|
+
} else {
|
|
198
|
+
log("warn", "Codex \u3092\u691C\u51FA\u3057\u307E\u3057\u305F\u304C hook \u304C\u672A\u767B\u9332\u3067\u3059\u3002init --codex \u3067\u767B\u9332\u3067\u304D\u307E\u3059");
|
|
199
|
+
}
|
|
200
|
+
const sessionsDir = join(codexHome(), "sessions");
|
|
201
|
+
if (existsSync(sessionsDir)) {
|
|
202
|
+
log("ok", `Codex \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u78BA\u8A8D\u3057\u307E\u3057\u305F: ${sessionsDir}`);
|
|
203
|
+
} else {
|
|
204
|
+
log("ok", `Codex \u306E\u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u307E\u3060\u3042\u308A\u307E\u305B\u3093: ${sessionsDir}(\u30BB\u30C3\u30B7\u30E7\u30F3\u672A\u4F5C\u6210\u306E\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059)`);
|
|
205
|
+
}
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
159
208
|
function readDirSafe(dir) {
|
|
160
209
|
try {
|
|
161
210
|
return readdirSync(dir, { withFileTypes: true });
|
|
@@ -339,6 +388,7 @@ async function checkRecentSessionTotal(latestTranscript) {
|
|
|
339
388
|
async function runDoctor() {
|
|
340
389
|
const results = [];
|
|
341
390
|
results.push(await safeRun("settings.json", () => checkHookRegistration()));
|
|
391
|
+
results.push(await safeRun("codex", () => checkCodex()));
|
|
342
392
|
let latestTranscript = null;
|
|
343
393
|
results.push(
|
|
344
394
|
await safeRun("projects", async () => {
|
|
@@ -631,19 +681,20 @@ async function main(argv) {
|
|
|
631
681
|
switch (cmd) {
|
|
632
682
|
case "track": {
|
|
633
683
|
const text = await readStdin();
|
|
684
|
+
const codex = rest.includes("--codex");
|
|
634
685
|
try {
|
|
635
|
-
const trackMod = await import("./track-
|
|
636
|
-
await trackMod.runTrack(text);
|
|
686
|
+
const trackMod = await import("./track-PXFSGMGL.js");
|
|
687
|
+
await trackMod.runTrack(text, { codex });
|
|
637
688
|
} catch {
|
|
638
689
|
}
|
|
639
690
|
return 0;
|
|
640
691
|
}
|
|
641
692
|
case "init": {
|
|
642
|
-
const { runInit } = await import("./setup-
|
|
693
|
+
const { runInit } = await import("./setup-PTO5N46B.js");
|
|
643
694
|
return await runInit(rest);
|
|
644
695
|
}
|
|
645
696
|
case "uninstall": {
|
|
646
|
-
const { runUninstall } = await import("./setup-
|
|
697
|
+
const { runUninstall } = await import("./setup-PTO5N46B.js");
|
|
647
698
|
return await runUninstall(rest);
|
|
648
699
|
}
|
|
649
700
|
case "doctor":
|
|
@@ -651,27 +702,27 @@ async function main(argv) {
|
|
|
651
702
|
case "report":
|
|
652
703
|
return await runReport(rest);
|
|
653
704
|
case "dashboard": {
|
|
654
|
-
const { runDashboard } = await import("./dashboard-
|
|
705
|
+
const { runDashboard } = await import("./dashboard-TH3NOVT3.js");
|
|
655
706
|
return await runDashboard(rest);
|
|
656
707
|
}
|
|
657
708
|
case "sweep": {
|
|
658
|
-
const { runSweep } = await import("./sweep-
|
|
709
|
+
const { runSweep } = await import("./sweep-25EZAOGC.js");
|
|
659
710
|
return await runSweep(rest);
|
|
660
711
|
}
|
|
661
712
|
case "history": {
|
|
662
|
-
const { runHistory } = await import("./history-
|
|
713
|
+
const { runHistory } = await import("./history-DLFYQJFM.js");
|
|
663
714
|
return await runHistory(rest);
|
|
664
715
|
}
|
|
665
716
|
case "budget": {
|
|
666
|
-
const { runBudget } = await import("./budget-
|
|
717
|
+
const { runBudget } = await import("./budget-KKTFYAXH.js");
|
|
667
718
|
return runBudget(rest);
|
|
668
719
|
}
|
|
669
720
|
case "mute": {
|
|
670
|
-
const { runMute } = await import("./mute-
|
|
721
|
+
const { runMute } = await import("./mute-EPLYH67P.js");
|
|
671
722
|
return runMute(rest);
|
|
672
723
|
}
|
|
673
724
|
case "unmute": {
|
|
674
|
-
const { runUnmute } = await import("./mute-
|
|
725
|
+
const { runUnmute } = await import("./mute-EPLYH67P.js");
|
|
675
726
|
return runUnmute();
|
|
676
727
|
}
|
|
677
728
|
case "--version":
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
browserOpenPlan,
|
|
4
4
|
runDashboard,
|
|
5
5
|
writeDashboardHtml
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QX5KIRSU.js";
|
|
7
7
|
import "./chunk-DGXUSPS4.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-J5QAYTFE.js";
|
|
9
|
+
import "./chunk-ECADO26T.js";
|
|
10
10
|
export {
|
|
11
11
|
browserOpenPlan,
|
|
12
12
|
runDashboard,
|
|
@@ -3,11 +3,12 @@ import {
|
|
|
3
3
|
matchesMarker,
|
|
4
4
|
runInit,
|
|
5
5
|
runUninstall
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-7KVOQ4UZ.js";
|
|
7
|
+
import "./chunk-NV5UOHJA.js";
|
|
8
8
|
import "./chunk-DGXUSPS4.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-HTYUYKFW.js";
|
|
10
|
+
import "./chunk-J5QAYTFE.js";
|
|
11
|
+
import "./chunk-ECADO26T.js";
|
|
11
12
|
export {
|
|
12
13
|
matchesMarker,
|
|
13
14
|
runInit,
|