ccc-notifier 0.6.3 → 0.8.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-U37CCG4Y.js} +2 -2
  3. package/dist/chunk-3M5UQK76.js +92 -0
  4. package/dist/chunk-6IVSZ3S4.js +22 -0
  5. package/dist/{sweep-CONNNBK7.js → chunk-C7QOYVGT.js} +324 -120
  6. package/dist/{chunk-PYU7CAK2.js → chunk-DSTGXYSY.js} +44 -11
  7. package/dist/{chunk-D4D76RGQ.js → chunk-GAOGTALW.js} +361 -20
  8. package/dist/{chunk-T6Z2ZAN4.js → chunk-ML5H43NH.js} +1 -1
  9. package/dist/{chunk-27SJELD2.js → chunk-PXMXEFM7.js} +22 -107
  10. package/dist/{chunk-6HTETN26.js → chunk-Q45AAPJY.js} +18 -1
  11. package/dist/{chunk-OXXDZZPJ.js → chunk-RE72XBXB.js} +4 -6
  12. package/dist/{chunk-NV5UOHJA.js → chunk-TTD3BGOL.js} +5 -5
  13. package/dist/{chunk-OOAC5ULQ.js → chunk-WONMZ466.js} +184 -4
  14. package/dist/{chunk-J5QAYTFE.js → chunk-XOGYLFX3.js} +12 -1
  15. package/dist/chunk-YH45W7TA.js +479 -0
  16. package/dist/cli.js +287 -30
  17. package/dist/{dashboard-O7LJLYM3.js → dashboard-YG4H3GLA.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-UVQXFN5Y.js +44 -0
  21. package/dist/scan-QB2N2O4Q.js +94 -0
  22. package/dist/{setup-I3JNGWZG.js → setup-2QDA3OWE.js} +5 -6
  23. package/dist/{subagent-store-US4TJJQR.js → subagent-store-USG3WJEB.js} +1 -1
  24. package/dist/sweep-OLI2LIXJ.js +22 -0
  25. package/dist/track-TIINM4ZR.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-RBLLR25M.js +0 -257
package/README.md CHANGED
@@ -23,6 +23,8 @@ in 1.2k(cache 40%) / out 480 · 📁 my-app · 今日: $1.85
23
23
  - 月予算を設定し、今月の使用率を確認できます
24
24
  - 通知を一時停止しても、履歴の記録は続けられます
25
25
  - Codex CLIも任意で追加し、Claude Codeと同じダッシュボードで確認できます
26
+ - Claude デスクトップアプリの**Code タブ(ローカルエージェントモード)**での作業と、Codex Desktop の利用分も`scan`コマンド(または応答完了時の自動便乗り取込)でローカルログから取り込めます(macOS)
27
+ - **ホームタブの通常チャット(および claude.ai / ChatGPT の通常チャット)は対象外です。**これらは手元のログにトークン数が残らないため(2026-08-12時点の実測)、現在の方式では計測できません。対応表は[計測できるもの・できないもの](docs/how-it-works.md#計測できるものできないもの--what-is-and-isnt-measured)を参照してください
26
28
 
27
29
  ## 必要なもの
28
30
 
@@ -131,6 +133,9 @@ ccc-notifier init
131
133
  | `ccc-notifier unmute` | 通知を再開する |
132
134
  | `ccc-notifier sweep --dry-run [--days N]` | 履歴を作り直した場合の件数と概算を確認する |
133
135
  | `ccc-notifier sweep [--days N]` | 残っている利用データから履歴を作り直す |
136
+ | `ccc-notifier scan --dry-run` | hook非依存の増分取り込み(Claude デスクトップの Code タブ・Codex Desktop 等の取りこぼし回収)の予定件数・金額を確認する |
137
+ | `ccc-notifier scan` | 未追跡分(Claude デスクトップの Code タブ、Codex Desktop 等)を履歴へ取り込む |
138
+ | `ccc-notifier reset-cursors` | 取り込み位置を捨てて次回に全再走査させる(履歴は保持。`doctor`が案内したときに使う) |
134
139
 
135
140
  > [!CAUTION]
136
141
  > **`sweep`は履歴を作り直すコマンドです。** 保存済みの履歴をいったん消し、Claude Code / Codex CLIに残っているデータから再作成します。設定や通知は消えませんが、履歴のバックアップは作りません。以前に削除・伏せ字にした履歴も、Claude Code / Codex CLI側の元データに残っていれば再び入ります。また、再作成した時点の単価と為替を使うため、以前の金額から変わることがあります。先に`--dry-run`で確認してください。詳しくは[履歴の再生成](docs/sweep.md)を参照してください。
@@ -2,12 +2,12 @@
2
2
  import {
3
3
  formatJPY,
4
4
  formatUSD
5
- } from "./chunk-J5QAYTFE.js";
5
+ } from "./chunk-XOGYLFX3.js";
6
6
  import {
7
7
  currentMonthTotals,
8
8
  paths,
9
9
  readConfig
10
- } from "./chunk-OOAC5ULQ.js";
10
+ } from "./chunk-WONMZ466.js";
11
11
 
12
12
  // src/budget.ts
13
13
  import { writeFileSync } from "fs";
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ paths
4
+ } from "./chunk-WONMZ466.js";
5
+
6
+ // src/dashboard-state.ts
7
+ import {
8
+ closeSync,
9
+ existsSync,
10
+ openSync,
11
+ readFileSync,
12
+ readSync,
13
+ renameSync,
14
+ rmSync,
15
+ writeFileSync
16
+ } from "fs";
17
+ import { randomUUID } from "crypto";
18
+ function localDate(now) {
19
+ const y = now.getFullYear();
20
+ const m = String(now.getMonth() + 1).padStart(2, "0");
21
+ const d = String(now.getDate()).padStart(2, "0");
22
+ return `${y}-${m}-${d}`;
23
+ }
24
+ function timeZone() {
25
+ return Intl.DateTimeFormat().resolvedOptions().timeZone || "unknown";
26
+ }
27
+ function makeFullDashboardState(now = /* @__PURE__ */ new Date()) {
28
+ return { localDate: localDate(now), timeZone: timeZone(), generatedAt: now.toISOString() };
29
+ }
30
+ function readState() {
31
+ const file = paths().dashboardFullStateFile;
32
+ if (!existsSync(file)) return null;
33
+ try {
34
+ const value = JSON.parse(readFileSync(file, "utf8"));
35
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
36
+ const v = value;
37
+ if (typeof v.localDate !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(v.localDate) || typeof v.timeZone !== "string" || v.timeZone.length === 0 || typeof v.generatedAt !== "string" || !Number.isFinite(Date.parse(v.generatedAt))) {
38
+ return null;
39
+ }
40
+ return v;
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+ function isFullDashboardDue(now = /* @__PURE__ */ new Date()) {
46
+ const p = paths();
47
+ if (!existsSync(p.fullDashboardFile)) return true;
48
+ try {
49
+ const fd = openSync(p.fullDashboardFile, "r");
50
+ try {
51
+ const head = Buffer.alloc(512);
52
+ const n = readSync(fd, head, 0, head.length, 0);
53
+ if (head.toString("utf8", 0, n).includes('name="cccn-placeholder"')) return true;
54
+ } finally {
55
+ closeSync(fd);
56
+ }
57
+ } catch {
58
+ return true;
59
+ }
60
+ const state = readState();
61
+ if (state === null) return true;
62
+ const expected = makeFullDashboardState(now);
63
+ if (state.timeZone !== expected.timeZone) return true;
64
+ if (state.localDate !== expected.localDate) return true;
65
+ if (state.localDate > expected.localDate) return true;
66
+ if (Date.parse(state.generatedAt) > now.getTime()) return true;
67
+ return false;
68
+ }
69
+ function writeFullDashboardStateAtomic(state) {
70
+ const file = paths().dashboardFullStateFile;
71
+ const tmp = `${file}.${process.pid}.${randomUUID()}.tmp`;
72
+ try {
73
+ writeFileSync(tmp, `${JSON.stringify(state)}
74
+ `, "utf8");
75
+ renameSync(tmp, file);
76
+ } finally {
77
+ rmSync(tmp, { force: true });
78
+ }
79
+ }
80
+ function invalidateCanonicalDashboards() {
81
+ const p = paths();
82
+ for (const file of [p.recentDashboardFile, p.fullDashboardFile, p.dashboardFullStateFile]) {
83
+ rmSync(file, { force: true });
84
+ }
85
+ }
86
+
87
+ export {
88
+ makeFullDashboardState,
89
+ isFullDashboardDue,
90
+ writeFullDashboardStateAtomic,
91
+ invalidateCanonicalDashboards
92
+ };
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/surface.ts
4
+ function effectiveSurface(rec) {
5
+ return rec.surface ?? "cli";
6
+ }
7
+ var SURFACE_LABELS = {
8
+ cli: "CLI",
9
+ desktop: "\u30C7\u30B9\u30AF\u30C8\u30C3\u30D7\u30A2\u30D7\u30EA",
10
+ vscode: "VS Code\u62E1\u5F35",
11
+ "claude-code": "Claude Code(Codex rollout)",
12
+ "chrome-extension": "Chrome\u62E1\u5F35",
13
+ other: "\u305D\u306E\u4ED6"
14
+ };
15
+ function surfaceLabel(surface) {
16
+ return SURFACE_LABELS[surface] ?? surface;
17
+ }
18
+
19
+ export {
20
+ effectiveSurface,
21
+ surfaceLabel
22
+ };