ccc-notifier 0.6.2 → 0.7.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 (30) hide show
  1. package/README.md +5 -0
  2. package/dist/{budget-V7CCMJHF.js → budget-O4VAP6RB.js} +2 -2
  3. package/dist/chunk-3M5UQK76.js +92 -0
  4. package/dist/{sweep-65D57PXU.js → chunk-6BXD6HU5.js} +275 -113
  5. package/dist/chunk-6IVSZ3S4.js +22 -0
  6. package/dist/{chunk-NV5UOHJA.js → chunk-JLDI4D5E.js} +5 -5
  7. package/dist/{chunk-T6Z2ZAN4.js → chunk-ML5H43NH.js} +1 -1
  8. package/dist/{chunk-6UZXXO5J.js → chunk-O2E4VTDR.js} +36 -9
  9. package/dist/{chunk-D4D76RGQ.js → chunk-OCKZZVOG.js} +353 -20
  10. package/dist/{chunk-27SJELD2.js → chunk-PXMXEFM7.js} +22 -107
  11. package/dist/{chunk-6HTETN26.js → chunk-Q45AAPJY.js} +18 -1
  12. package/dist/chunk-V4IS4FXH.js +454 -0
  13. package/dist/{chunk-OOAC5ULQ.js → chunk-WONMZ466.js} +184 -4
  14. package/dist/{chunk-OXXDZZPJ.js → chunk-X7U63BZG.js} +4 -6
  15. package/dist/{chunk-J5QAYTFE.js → chunk-XG73C6CC.js} +10 -1
  16. package/dist/cli.js +286 -29
  17. package/dist/{dashboard-VEKQ4TI3.js → dashboard-64XHDUVT.js} +6 -4
  18. package/dist/{history-DL4SG3PG.js → history-W34EJOVV.js} +5 -3
  19. package/dist/{mute-UIR5P5N5.js → mute-23BWQXS3.js} +2 -2
  20. package/dist/reset-cursors-5CCM6MQL.js +41 -0
  21. package/dist/scan-UB6ORRZK.js +87 -0
  22. package/dist/{setup-I3JNGWZG.js → setup-VLMW433R.js} +5 -6
  23. package/dist/{subagent-store-US4TJJQR.js → subagent-store-USG3WJEB.js} +1 -1
  24. package/dist/sweep-DVOV4XIZ.js +20 -0
  25. package/dist/track-P6A5WDJZ.js +368 -0
  26. package/package.json +1 -1
  27. package/dist/chunk-HLJAJS2W.js +0 -55
  28. package/dist/chunk-HTYUYKFW.js +0 -21
  29. package/dist/chunk-OYD6H3ZZ.js +0 -124
  30. package/dist/track-WCP7446C.js +0 -257
@@ -1,257 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- notifyOS,
4
- notifySlack
5
- } from "./chunk-NV5UOHJA.js";
6
- import {
7
- collectSubagentUsage
8
- } from "./chunk-OYD6H3ZZ.js";
9
- import {
10
- aggregateCodexTurn,
11
- aggregateNewTurn,
12
- getUsdJpy
13
- } from "./chunk-D4D76RGQ.js";
14
- import {
15
- computeCost,
16
- loadPriceTable
17
- } from "./chunk-6HTETN26.js";
18
- import {
19
- writeDashboardHtml
20
- } from "./chunk-6UZXXO5J.js";
21
- import "./chunk-DGXUSPS4.js";
22
- import "./chunk-J5QAYTFE.js";
23
- import {
24
- isFullDashboardDue,
25
- makeFullDashboardState,
26
- waitForDataLock,
27
- writeFullDashboardStateAtomic
28
- } from "./chunk-27SJELD2.js";
29
- import {
30
- appendTurn,
31
- closeCodexRootContext,
32
- isMuted,
33
- loadCursor,
34
- logError,
35
- paths,
36
- readConfig,
37
- readTurns,
38
- sanitizeCursor,
39
- saveCursor,
40
- todayTotalUSD
41
- } from "./chunk-OOAC5ULQ.js";
42
-
43
- // src/track.ts
44
- function isRecord(v) {
45
- return typeof v === "object" && v !== null && !Array.isArray(v);
46
- }
47
- function emptyBuckets() {
48
- return { input: 0, output: 0, cacheWrite5m: 0, cacheWrite1h: 0, cacheRead: 0 };
49
- }
50
- function sumBuckets(usage) {
51
- const total = emptyBuckets();
52
- for (const b of Object.values(usage)) {
53
- total.input += b.input;
54
- total.output += b.output;
55
- total.cacheWrite5m += b.cacheWrite5m;
56
- total.cacheWrite1h += b.cacheWrite1h;
57
- total.cacheRead += b.cacheRead;
58
- }
59
- return total;
60
- }
61
- function collectModels(main, sidechain) {
62
- const models = [];
63
- for (const m of Object.keys(main)) {
64
- if (!models.includes(m)) models.push(m);
65
- }
66
- for (const m of Object.keys(sidechain)) {
67
- if (!models.includes(m)) models.push(m);
68
- }
69
- return models;
70
- }
71
- function withCodexModel(agg, payloadModel) {
72
- const model = typeof payloadModel === "string" && payloadModel.length > 0 ? payloadModel : null;
73
- if (model === null) return agg;
74
- const buckets = Object.values(agg.main)[0] ?? emptyBuckets();
75
- return { ...agg, main: { [model]: buckets } };
76
- }
77
- async function runTrack(stdinText, opts) {
78
- try {
79
- let parsed;
80
- try {
81
- parsed = JSON.parse(stdinText);
82
- } catch {
83
- return;
84
- }
85
- if (!isRecord(parsed)) return;
86
- const input = parsed;
87
- const isCodex = opts?.codex === true;
88
- let activityProjectionKey = null;
89
- if (isCodex) {
90
- try {
91
- activityProjectionKey = closeCodexRootContext(parsed);
92
- } catch {
93
- logError("track:codex-subagent-projection", new Error("activity projection was not attached"));
94
- }
95
- }
96
- const transcriptPath = input.transcript_path;
97
- if (typeof transcriptPath !== "string") return;
98
- const cfg = readConfig();
99
- const cacheDir = paths().cacheDir;
100
- const table = await loadPriceTable(cacheDir, { offline: true });
101
- const fx = await getUsdJpy(cfg, cacheDir);
102
- let record;
103
- let hasMainUsage = false;
104
- const commitLock = await waitForDataLock(1e3);
105
- if (commitLock === null) {
106
- logError("track:data-lock", new Error("data lock timeout; turn was not consumed"));
107
- return;
108
- }
109
- try {
110
- const cursor = sanitizeCursor(loadCursor(transcriptPath));
111
- let agg = isCodex ? await aggregateCodexTurn(transcriptPath, cursor) : await aggregateNewTurn(transcriptPath, cursor);
112
- if (isCodex && agg === null) return;
113
- hasMainUsage = agg !== null;
114
- if (isCodex && agg !== null) {
115
- agg = withCodexModel(agg, input.model);
116
- }
117
- let sa = null;
118
- if (!isCodex) {
119
- try {
120
- const excluded = new Set(cursor?.seenMessageKeys ?? []);
121
- if (agg !== null && "messageKeys" in agg) {
122
- for (const key of agg.messageKeys) excluded.add(key);
123
- }
124
- sa = await collectSubagentUsage(transcriptPath, { excludeMessageKeys: excluded });
125
- } catch (err) {
126
- logError("track:subagents", err);
127
- sa = null;
128
- }
129
- }
130
- if (agg === null && (sa === null || sa.apiCalls === 0)) {
131
- for (const nc of sa?.newCursors ?? []) saveCursor(nc.path, nc.cursor);
132
- return;
133
- }
134
- const main = agg?.main ?? {};
135
- const sidechain = agg?.sidechain ?? {};
136
- const breakdown = computeCost(main, sidechain, table);
137
- const sessionId = agg?.sessionId || sa?.sessionId || (typeof input.session_id === "string" ? input.session_id : "") || "";
138
- const project = agg?.cwd ?? sa?.cwd ?? (typeof input.cwd === "string" ? input.cwd : void 0) ?? "";
139
- const sidechainHasModels = Object.keys(sidechain).length > 0;
140
- record = {
141
- schemaVersion: 1,
142
- ts: agg?.lastTs ?? sa?.lastTs ?? (/* @__PURE__ */ new Date()).toISOString(),
143
- sessionId,
144
- project,
145
- gitBranch: agg?.gitBranch ?? sa?.gitBranch ?? null,
146
- models: hasMainUsage ? collectModels(main, sidechain) : collectModels(sa?.perModel ?? {}, {}),
147
- tokens: sumBuckets(main),
148
- sidechainTokens: sidechainHasModels ? sumBuckets(sidechain) : null,
149
- apiCalls: agg?.apiCalls ?? 0,
150
- costUSD: breakdown.usd,
151
- costByModel: breakdown.byModel,
152
- // モデル別 USD(main+sidechain 合算、丸めない)
153
- costJPY: breakdown.usd * fx.rate,
154
- // 丸めない(表示時に丸める)
155
- fxRate: fx.rate,
156
- fxSource: fx.source,
157
- prompt: agg?.prompt ?? ""
158
- };
159
- if (isCodex) {
160
- record.source = "codex";
161
- if (activityProjectionKey !== null) record.activityProjectionKey = activityProjectionKey;
162
- }
163
- if (breakdown.unknownModels.length > 0) {
164
- record.unknownModels = breakdown.unknownModels;
165
- }
166
- if (sa !== null && sa.apiCalls > 0) {
167
- const saBreakdown = computeCost(sa.perModel, {}, table);
168
- record.subagents = {
169
- costUSD: saBreakdown.usd,
170
- costByModel: saBreakdown.byModel,
171
- tokens: sumBuckets(sa.perModel),
172
- apiCalls: sa.apiCalls,
173
- agentFiles: sa.agentFiles
174
- };
175
- if (saBreakdown.unknownModels.length > 0) {
176
- const merged = record.unknownModels ? [...record.unknownModels] : [];
177
- for (const m of saBreakdown.unknownModels) {
178
- if (!merged.includes(m)) merged.push(m);
179
- }
180
- record.unknownModels = merged;
181
- }
182
- }
183
- appendTurn(record);
184
- if (agg !== null) saveCursor(transcriptPath, agg.newCursor);
185
- if (sa !== null) {
186
- for (const nc of sa.newCursors) {
187
- saveCursor(nc.path, nc.cursor);
188
- }
189
- }
190
- } finally {
191
- commitLock.release();
192
- }
193
- const tasks = [];
194
- if (hasMainUsage && (cfg.notify.os || cfg.notify.slack !== null) && record.costUSD >= cfg.minNotifyUSD && !isMuted()) {
195
- const todayUSD = cfg.includeDailyTotal ? todayTotalUSD() : void 0;
196
- tasks.push(notifyOS(record, cfg, todayUSD));
197
- tasks.push(notifySlack(record, cfg, todayUSD));
198
- }
199
- if (cfg.dashboard.autoRegenerate) {
200
- tasks.push(
201
- (async () => {
202
- const now = /* @__PURE__ */ new Date();
203
- const dashboardLock = await waitForDataLock(1e3);
204
- if (dashboardLock === null) {
205
- logError("track:dashboard-lock", new Error("data lock timeout; dashboard skipped"));
206
- return;
207
- }
208
- try {
209
- let allTurns;
210
- try {
211
- allTurns = readTurns();
212
- } catch (err) {
213
- logError("track:dashboard-read", err);
214
- return;
215
- }
216
- try {
217
- writeDashboardHtml({
218
- days: cfg.dashboard.days,
219
- outPath: paths().recentDashboardFile,
220
- autoReloadSec: cfg.dashboard.autoReloadSec,
221
- allTurns,
222
- variant: "recent"
223
- });
224
- } catch (err) {
225
- logError("track:dashboard-recent", err);
226
- }
227
- if (isFullDashboardDue(now)) {
228
- try {
229
- writeDashboardHtml({
230
- days: null,
231
- outPath: paths().fullDashboardFile,
232
- autoReloadSec: cfg.dashboard.autoReloadSec,
233
- allTurns,
234
- variant: "full",
235
- generatedAt: now.toISOString()
236
- });
237
- writeFullDashboardStateAtomic(makeFullDashboardState(now));
238
- } catch (err) {
239
- logError("track:dashboard-full", err);
240
- }
241
- }
242
- } finally {
243
- dashboardLock.release();
244
- }
245
- })()
246
- );
247
- }
248
- if (tasks.length > 0) {
249
- await Promise.allSettled(tasks);
250
- }
251
- } catch (err) {
252
- logError("track", err);
253
- }
254
- }
255
- export {
256
- runTrack
257
- };