@ramath/ccusage-dashboard
v0.1.1
Published
ดู usage/cost ของ coding agent CLI เป็นหน้าเว็บ เสิร์ฟบน port ว่างอัตโนมัติ
Maintainers
Readme
ccusage-dashboard
ดู usage/cost ของ coding agent CLI (Claude Code, Gemini CLI ฯลฯ) เป็น หน้าเว็บ แทนตารางในเทอร์มินัล รันคำสั่งเดียว → เสิร์ฟ HTML บน port ว่างอัตโนมัติ → ดูได้ทั้งทีละโปรเจกต์และทั้งเครื่อง
npx @ramath/ccusage-dashboard
ตัวเลข/ชื่อโปรเจกต์ในภาพเป็นข้อมูลตัวอย่างที่สร้างขึ้น ไม่ใช่ข้อมูลของใคร (สร้างด้วย
node docs/make-screenshot.mjs)
ต่างจาก ccusage เปล่าๆ ยังไง
ccusage อ่าน log ของ agent แล้วสรุป cost ให้ได้เก่งมาก
แต่ตอนสรุปราย session มันคืน session UUID เปล่าๆ มาให้ ไม่มีชื่อโปรเจกต์ติดมาเลย:
┌──────────────────────────────────────┬────────┬──────────┐
│ 00c50d5f-41aa-4322-8769-e3255ee081e0 │ 1.2M │ $12.42 │
└──────────────────────────────────────┴────────┴──────────┘ดูแล้วบอกไม่ได้ว่าเงินก้อนนี้หมดไปกับงานไหน ccusage-dashboard เข้ามาเติมตรงนี้:
| | ccusage | ccusage-dashboard |
|---|---|---|
| รูปแบบผลลัพธ์ | ตาราง ASCII ในเทอร์มินัล | หน้าเว็บ + JSON API |
| แยกตามโปรเจกต์ | ❌ (คืน session UUID) | ✅ map UUID → path ของโปรเจกต์ |
| ชื่อ session ภาษาคน | ❌ | ✅ ดึงชื่อที่ AI ตั้งให้จาก log |
| กราฟรายวัน | ❌ | ✅ SVG แยกสีตาม agent |
| ที่มาของตัวเลข cost | คำนวณเอง | ใช้ของ ccusage ทั้งหมด ไม่คำนวณเอง |
วิธี map: ชื่อไฟล์ log ของ Claude Code (~/.claude/projects/<โปรเจกต์>/<uuid>.jsonl) คือ session UUID ตัวเดียวกับที่ ccusage คืนมา — ใช้เป็น join key ได้
ส่วน path ของโปรเจกต์อ่านจาก field cwd ในไฟล์ ไม่ได้เดาจากชื่อโฟลเดอร์ (ชื่อโฟลเดอร์แทน / ด้วย - ซึ่ง decode กลับไม่ได้ ถ้าชื่อโปรเจกต์มี - อยู่แล้วจะได้ path ผิด)
การใช้งาน
ไม่ต้องติดตั้ง — npx ดึงมารันแล้วจบ (ต้องมี Node.js 20 ขึ้นไป)
cd ~/work/my-app
npx @ramath/ccusage-dashboard # ดูเฉพาะโปรเจกต์นี้ + เปิด browser ให้อัตโนมัติ
npx @ramath/ccusage-dashboard --all # ดูทั้งเครื่อง ทุกโปรเจกต์ ทุก agent
npx @ramath/ccusage-dashboard --json # ไม่ยิง server — พ่น JSON ที่ join แล้วออก stdoutปิดด้วย Ctrl+C — ไม่มี daemon ค้าง ไม่มีไฟล์ state ไม่มี DB อ่านสดทุกครั้ง
flag ทั้งหมด
| flag | ความหมาย |
|---|---|
| -j, --json | พ่น JSON ออก stdout แทนการเปิดหน้าเว็บ |
| --all | ดูข้อมูลทั้งเครื่อง ทุกโปรเจกต์ ทุก agent |
| -p, --project <path> | ดูเฉพาะโปรเจกต์ที่ path นี้ (ไม่ใส่ = โฟลเดอร์ปัจจุบัน) |
| --port <n> | ระบุ port เอง (ไม่ใส่ = ให้ OS เลือก port ว่างให้) |
| --no-open | ไม่ต้องเปิด browser ให้ |
| --timeout <วินาที> | เพดานเวลาของการรัน ccusage หนึ่งครั้ง (ไม่ใส่ = 60) |
| -s, --since <YYYY-MM-DD> | กรองตั้งแต่วันที่ |
| -u, --until <YYYY-MM-DD> | กรองถึงวันที่ (รวมวันนั้น) |
| -z, --timezone <IANA> | timezone ที่ใช้จัดกลุ่มวัน เช่น Asia/Bangkok |
| -O, --offline | ใช้ตาราง pricing ที่ cache ไว้ ไม่ต้องต่อเน็ต |
| -h, --help | แสดงรายการ flag |
ใช้ --all คู่กับ --project ไม่ได้ (ขัดกันเอง โปรแกรมจะเตือนแล้วออก)
--port ที่ถูกใช้อยู่แล้วจะ error ทันที ไม่แอบเลื่อนไป port อื่น เพราะการแอบเลื่อนทำให้เปิดผิดหน้าโดยไม่รู้ตัว
หน้าเว็บมีอะไรบ้าง
| route | ได้อะไร |
|---|---|
| GET / | หน้า dashboard (?scope=all / ?project=<path> สลับขอบเขตได้โดยไม่ต้องรัน ccusage ใหม่) |
| GET /api/report | JSON ก้อนเดียวกับที่ --json พิมพ์ออกมาเป๊ะ |
| GET/POST /api/refresh | เก็บข้อมูลใหม่ทั้งรอบ (ปุ่ม Refresh บนหน้าเว็บเรียกอันนี้) กดรัวๆ ก็ไม่ spawn ซ้อน |
หน้าเว็บ bind ที่ 127.0.0.1 เท่านั้น ไม่เปิดออกนอกเครื่อง และ ไม่มี resource ภายนอกเลย
(CSS/JS inline หมด ไม่มี CDN ไม่มี font นอก) จึงใช้งานได้ตอนออฟไลน์ และมี CSP กันหน้าโหลดของนอกซ้ำอีกชั้น

ข้อจำกัดที่ควรรู้ก่อนเชื่อตัวเลข
เครื่องมือนี้เลือก บอกความจริงว่าอะไรที่บอกไม่ได้ มากกว่าจะเดาแล้วโชว์เลขสวยๆ
แยกรายโปรเจกต์ได้แม่นเฉพาะ Claude Code เพราะมันเป็น agent เดียวที่เก็บ log แยกไฟล์ต่อ session โดยตั้งชื่อไฟล์เป็น session UUID จึง join กลับได้
agent อื่น (Gemini CLI, ฯลฯ) จะไปอยู่ถัง "ระบุโปรเจกต์ไม่ได้" Gemini เก็บ log เป็นโฟลเดอร์ตาม basename ของโปรเจกต์ ซึ่งชนกันได้ถ้ามีสองโปรเจกต์ชื่อท้ายเหมือนกัน จึงเลือกโชว์แยกเป็นก้อน
unmappedพร้อมเหตุผล แทนที่จะเดาว่าเป็นของโปรเจกต์ไหน — ตัวเลขผิดแย่กว่าไม่มีตัวเลข (ก้อนนี้ไม่เคยถูกซ่อน และไม่ถูกนับรวมตอนดูเจาะรายโปรเจกต์)กราฟ/ยอดรายวันเป็นของทั้งเครื่องเสมอ แม้กำลังดูเจาะโปรเจกต์เดียว
ccusageไม่ได้ผูกโปรเจกต์เข้ากับยอดรายวัน และ session มีแค่เวลา "ใช้ล่าสุด" ซึ่งเอามากระจายยอดทั้ง session ลงรายวันไม่ได้โดยไม่โกหก — หน้าเว็บจึงติดป้ายกำกับไว้ตรงกราฟ และ JSON ติดธงmeta.dailyScope: "machine"--offlineให้ราคาต่างจากแบบออนไลน์ได้ โหมดออฟไลน์ใช้ตารางราคาที่ cache ไว้ ซึ่งเก่ากว่าราคาปัจจุบัน วัดจากข้อมูลชุดเดียวกันเคยต่างกันราว 3% ถ้าดึงราคาจากเน็ตไม่ได้ โปรแกรมจะถอยไปใช้ราคา cache ให้เอง พร้อมขึ้น banner เตือนบนหน้าเว็บและในเทอร์มินัล ไม่เงียบpath ที่เดาจากชื่อโฟลเดอร์จะติดป้ายเตือน กรณีที่หา
cwdในไฟล์ log ไม่เจอเลยทั้งโฟลเดอร์ จะถอยไป decode ชื่อโฟลเดอร์ซึ่งอาจได้ path ผิด — โปรเจกต์นั้นจะถูกมาร์กว่าไม่น่าเชื่อถือบนหน้าเว็บ
Status
| Milestone | สถานะ |
|---|---|
| M0 Scaffold | ✅ |
| M1 Collector (ดูดข้อมูลจาก ccusage) | ✅ |
| M2 Project index + join | ✅ |
| M3 Server + HTML | ✅ |
| M4 โหมดโปรเจกต์ (toggle + drill-in) | ✅ |
| M5 เก็บงาน (test / README / CI) | ✅ |
รายละเอียดขอบเขตงานและเหตุผลของแต่ละการตัดสินใจอยู่ใน PLAN.md
พัฒนาต่อ
npm ci
npm run build # tsc → dist/
npm test # 67 เคส (node:test) — อ่านจาก test/fixtures เท่านั้น ไม่แตะ ~/.claude จริง
npm run typecheck # tsc --noEmitเครดิต
ตัวเลขทั้งหมดมาจาก ccusage ของ @ryoppippi โดยตรง —
โปรเจกต์นี้ไม่ได้คำนวณราคาเอง แค่ต่อยอดเป็นการ map session → โปรเจกต์ แล้ว render เป็น dashboard
License
MIT
