SLOPSHOPPER

context-bar

Context window breakdown and prompt-cache countdown above the prompt; /context-bar toggles it.

newbandcommandprompttimer
★ 1v0.4.0MITupdated 2026-10-08Boom-Vitt/boombignose-mods/context-bar
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · context-bar
› fix the failing auth test and add an audit log call ⏺ Read(src/auth.ts) ⎿ Read 6 lines ⏺ Update(src/auth.ts) ⎿ Added 2 lines, removed 1 line ⏺ Bash(bun test) ⎿ 3 pass, 1 fail ● Done. refresh now rejects expired claims and logs an audit event. ✻ Worked for 42s · done 4:20 PM › /context-bar ⎿ context-bar: Context bar hidden. ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

boombignose-mods

มอด (mod) สำหรับ Claude Code: ตัวช่วยลดความเสี่ยงในการส่งข้อมูลส่วนบุคคลให้โมเดล (pdpa-thai) แถบแสดงการใช้ context (context-bar) แผงรายการ agent (agents-panel) และเวิร์กโฟลว์ multi-agent (boom-big-nose-workflow)

License: MIT tests For Claude Code

ไทย · English

ติดตั้ง · มอดในชุดนี้ · pdpa-thai · ข้อจำกัด · เชื่อถือได้แค่ไหน · คำถามที่พบบ่อย · PDPA กับมอดนี้ · กฎการตรวจจับ

ข้อควรทราบ โครงการนี้เป็นโครงการชุมชนที่ไม่เป็นทางการ และมีผู้ดูแลเพียงคนเดียว ไม่มีความเกี่ยวข้องกับ Anthropic, สำนักงานคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล (PDPC), สำนักงานพัฒนาธุรกรรมทางอิเล็กทรอนิกส์ (ETDA), สำนักงานพัฒนารัฐบาลดิจิทัล (DGA), กระทรวงดิจิทัลเพื่อเศรษฐกิจและสังคม (MDES) หรือหน่วยงานรัฐใดของไทย และไม่ได้รับการสนับสนุนหรือการรับรองจากองค์กรและหน่วยงานเหล่านี้ ชื่อ pdpa-thai คำสั่ง /pdpa-guard และข้อความ PDPA: <โหมด> ในแถบสถานะ อ้างถึงพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคลเพียงเพราะกฎการตรวจจับออกแบบตามชนิดข้อมูลที่กฎหมายนั้นคุ้มครอง ไม่ได้บ่งชี้ว่าปฏิบัติตามกฎหมายแล้ว ส่วน Claude และ Claude Code เป็นผลิตภัณฑ์ของ Anthropic การกล่าวถึงชื่อเหล่านี้มีไว้เพียงเพื่อบอกว่ามอดในชุดนี้ใช้งานร่วมกับผลิตภัณฑ์ใด

เอกสารนี้ไม่ใช่คำแนะนำทางกฎหมาย สำหรับคำถามทางกฎหมาย โปรดปรึกษาทนายความที่มีคุณสมบัติเหมาะสม หรือเจ้าหน้าที่คุ้มครองข้อมูลส่วนบุคคล (Data Protection Officer, DPO) ขององค์กร และติดตามการตีความอย่างเป็นทางการจาก PDPC ซอฟต์แวร์นี้ให้ใช้ตามสภาพ (as is) โดยไม่มีการรับประกันใด ๆ ตาม สัญญาอนุญาต MIT การตรวจจับใช้นิพจน์ปรกติ (regular expression) ซึ่งไม่รับประกันผล (best-effort) จึงจะมีข้อมูลที่ตรวจไม่พบ และจะมีข้อความทั่วไปบางส่วนถูกปกปิดโดยไม่จำเป็น

โครงการนี้คืออะไร และมีไว้ทำไม

ทุกอย่างในบทสนทนาของ Claude Code ถูกส่งไปให้โมเดลประมวลผล ได้แก่ ข้อความที่พิมพ์ ไฟล์ที่ให้ Claude อ่าน ผลลัพธ์ของคำสั่ง และไฟล์ CLAUDE.md ดังนั้นเมื่อทำงานกับข้อมูลลูกค้า ใบสมัครงาน หรือบันทึกของระบบ (log) ข้อมูลส่วนบุคคล เช่น เลขประจำตัวประชาชน หมายเลขโทรศัพท์ หรืออีเมล จึงอาจติดไปกับคำขอโดยไม่ได้ตั้งใจ

pdpa-thai ตรวจหาข้อมูลส่วนบุคคลรูปแบบที่พบบ่อย ทั้งรูปแบบเฉพาะของไทยและรูปแบบสากล โดยทำงานภายในโปรเซสของ Claude Code แล้วแทนค่าที่พบด้วยป้ายแทนค่า (placeholder) ก่อนที่ Claude Code จะส่งบทสนทนาออกไป มอดนี้ออกแบบมาเพื่อช่วยลดความเสี่ยงเท่านั้น การติดตั้งมอดนี้ไม่ได้ทำให้องค์กรปฏิบัติตามพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 (PDPA) หรือกฎหมายอื่นใด และไม่ทดแทนการประเมินโดยผู้เชี่ยวชาญ

มอดอื่นเป็นเครื่องมือช่วยงานทั่วไปที่ไม่เกี่ยวกับ PDPA

ติดตั้ง

ต้องใช้ Claude Code เวอร์ชันที่รองรับปลั๊กอินแบบ hook module ทดสอบแล้วกับ Claude Code 2.1.289 เท่านั้น API ของ hook ยังอยู่ในระยะทดลองใช้ (early access) ดังนั้นเวอร์ชันก่อนหน้าหรือใหม่กว่าอาจข้ามการป้องกันบางส่วนหรือทั้งหมดโดยไม่มีการแจ้งเตือน ส่วนป้าย (badge) ของ CI แสดงเพียงว่าชุดทดสอบหน่วย (unit test) ผ่านบน Claude Code เวอร์ชันล่าสุด

claude plugin marketplace add Boom-Vitt/boombignose-mods
claude plugin install pdpa-thai@boombignose-mods
claude plugin install context-bar@boombignose-mods
claude plugin install agents-panel@boombignose-mods
claude plugin install boom-big-nose-workflow@boombignose-mods

แต่ละมอดทำงานแยกกัน เลือกติดตั้งเฉพาะมอดที่ต้องการได้

ใน Codex ติดตั้งได้เฉพาะ boom-big-nose-workflow เพราะมอดอื่นใช้ความสามารถที่มีเฉพาะใน Claude Code:

codex plugin marketplace add Boom-Vitt/boombignose-mods
codex plugin add boom-big-nose-workflow@boombignose-mods

อัปเดตเป็นเวอร์ชันล่าสุด:

claude plugin marketplace update boombignose-mods
claude plugin update pdpa-thai@boombignose-mods

จากนั้นเริ่ม Claude Code ใหม่เพื่อให้การอัปเดตมีผล

ปิดการทำงานชั่วคราว หรือถอนการติดตั้ง:

claude plugin disable pdpa-thai@boombignose-mods
claude plugin uninstall pdpa-thai@boombignose-mods

มอดในชุดนี้

มอดเวอร์ชันคำสั่งหน้าที่
pdpa-thai0.3.0`/pdpa-guard [redact\block\off], /pdpa-blur [on\off\record]`ปกปิดข้อมูลส่วนบุคคลที่ตรวจพบก่อนส่งให้ Claude และพรางข้อมูลบนหน้าจอ (วางเมาส์เพื่อดู หรือวางเมาส์แล้วไม่แสดงค่าจริงในโหมดบันทึกหน้าจอ)
context-bar0.4.0/context-barแถบเหนือช่องพิมพ์ แสดงการใช้ context window แยกตามหมวด และเวลาที่เหลือของ prompt cache
agents-panel0.1.0/agents-panelแผงด้านข้างแสดง agent ของโปรเจกต์ ของผู้ใช้ และของปลั๊กอิน พร้อมปุ่มเรียกใช้
boom-big-nose-workflow0.5.0ไม่ต้องใช้คำสั่ง (บอกเป้าหมายได้เลย) หรือ /bbn-plan, /bbn-review, /bbn-merge และคำสั่ง /bbn-* อื่นเวิร์กโฟลว์ BBN แบบอัตโนมัติ: บอกเป้าหมายเป็นภาษาธรรมดา แล้ว Claude Opus/Sonnet/Haiku กับ Codex CLI วางแผน แยก worktree ต่อ stream เขียนโค้ด รีวิว และ merge เข้า base ในเครื่องผ่าน gate โดยไม่ต้องพิมพ์ slash command (README, แผนภาพ)

/context-bar และ /agents-panel เป็นคำสั่งสลับเปิดและปิด /pdpa-blur สลับเปิดและปิดได้เช่นกัน หรือรับ on, off หรือ record ส่วน /pdpa-guard รับชื่อโหมด

  • context-bar นับถอยหลังโดยถือว่า prompt cache มีอายุ 5 นาที (เป็นค่าคงที่ในโค้ด)
  • ปุ่ม ▶ run ของ agents-panel เริ่ม subagent ตัวนั้นด้วยพรอมต์ (prompt) คงที่ Run the <name> agent on the current project. subagent นั้นทำงานเหมือน agent ทั่วไป คือส่งบทสนทนาไปยังผู้ให้บริการโมเดลที่ตั้งค่าไว้ (โดยค่าเริ่มต้นคือ Anthropic) และทำงานกับโปรเจกต์ได้ภายใต้สิทธิ์ (permission) ที่ตั้งไว้ตามปกติ

ประวัติการเปลี่ยนแปลงของแต่ละมอดอยู่ใน CHANGELOG.md

pdpa-thai

กลไกการทำงาน 3 ชั้น

  1. ตัวป้องกันขาออก (outbound guard) ตรวจและปกปิดข้อมูลก่อนส่งให้โมเดล ครอบคลุม
  2. พรอมต์ที่ผู้ใช้พิมพ์
  3. ข้อความที่บทสนทนาเก็บไว้ (conversation row) เช่น ข้อความในผลลัพธ์ของเครื่องมือ (tool result) และ context ที่ hook อื่นเพิ่มเข้ามา
  4. ข้อความที่แนบไปกับคำขอ เช่น ไฟล์ที่อ้างถึงด้วย @ ไฟล์ CLAUDE.md และ context block อื่น

มอดแก้ไขเฉพาะบล็อกข้อความ (text block) และข้อความในผลลัพธ์ของเครื่องมือ บล็อกชนิดอื่น เช่น รูปภาพหรือเอกสาร ถูกส่งไปตามเดิม

  1. การปฏิเสธการเรียกเครื่องมือ (tool call) ขณะที่โหมดไม่ใช่ off หากการเรียกเครื่องมือของ Claude มีป้ายแทนค่าที่มอดสร้างขึ้นในเซสชัน (session) นี้ตรงตามรูปแบบเดิม มอดจะปฏิเสธการเรียกนั้นและแจ้งให้ Claude ขอค่าจริงจากผู้ใช้ ซึ่งช่วยลดโอกาสที่ป้ายแทนค่าจะถูกเขียนลงไฟล์หรือคำสั่งจริง การตรวจนี้จับไม่ได้หาก Claude ดัดแปลงป้ายแทนค่า หรือป้ายแทนค่ามาจากเซสชันก่อนหน้า
  2. การพรางบนหน้าจอ (hover blur) ข้อมูลที่ตรวจพบซึ่งยังแสดงอยู่ในข้อความของผู้ใช้และของ Claude จะแสดงเป็นแถบสีเทา วางเมาส์เพื่อดูค่าจริง ในโหมด redact พรอมต์ของผู้ใช้แสดงเป็นป้ายแทนค่าอยู่แล้ว บทสนทนาเก็บเฉพาะพรอมต์ที่ปกปิดแล้ว และมอดไม่ได้เก็บสำเนาค่าเดิมไว้ การพรางจึงมีผลหลักกับข้อความของ Claude และข้อความที่ส่งขณะปิดการป้องกัน (off) การพรางเปิดใช้งานโดยค่าเริ่มต้น และทำงานเฉพาะบน terminal และแอปเดสก์ท็อป สำหรับการบันทึกหน้าจอหรือแชร์หน้าจอ ใช้ /pdpa-blur record เพื่อคงการพรางไว้และหยุดการแสดงค่าจริงเมื่อวางเมาส์ ดูหัวข้อ การบันทึกหรือแชร์หน้าจอ

โหมด

โหมดการทำงาน
redact (ค่าเริ่มต้น)แทนค่าที่ตรวจพบด้วยป้ายแทนค่าก่อนส่งให้ Claude
blockไม่ส่งพรอมต์ที่มีข้อมูลส่วนบุคคลที่ตรวจพบ ให้แก้ไขพรอมต์โดยนำข้อมูลนั้นออกแล้วส่งใหม่ ส่วนผลลัพธ์ของเครื่องมือ ไฟล์แนบ และ context ยังถูกปกปิดเหมือนโหมด redact
offปิดทั้งการปกปิดและการปฏิเสธการเรียกเครื่องมือ (การพรางบนหน้าจอควบคุมแยกด้วย /pdpa-blur)

โหมดและการตั้งค่าการพรางไม่ได้บันทึกลงดิสก์ และจะเริ่มที่โหมด redact พร้อมเปิดการพรางและปิดโหมดบันทึกหน้าจอทุกครั้งที่เริ่ม Claude Code ส่วน /clear จะคงโหมดปัจจุบันไว้หรือไม่นั้น ผู้ดูแลโครงการยังไม่ได้ตรวจสอบ (ดูโหมดปัจจุบันได้โดยใช้ /pdpa-guard โดยไม่ระบุอาร์กิวเมนต์ หรือดูที่แถบสถานะ)

คำสั่ง

/pdpa-guard           แสดงโหมดปัจจุบัน
/pdpa-guard redact    ปกปิดก่อนส่ง (ค่าเริ่มต้น)
/pdpa-guard block     ไม่ส่งพรอมต์ที่มีข้อมูลส่วนบุคคลที่ตรวจพบ
/pdpa-guard off       ปิดการป้องกัน
/pdpa-blur            สลับการพรางบนหน้าจอ (เปิดหากปิดอยู่ ปิดหากเปิดอยู่หรืออยู่ในโหมดบันทึกหน้าจอ)
/pdpa-blur on         เปิดการพราง วางเมาส์เพื่อดูค่าจริง
/pdpa-blur off        ปิดการพราง
/pdpa-blur record     โหมดบันทึกหน้าจอ: เปิดการพราง และวางเมาส์แล้วไม่แสดงค่าจริง

อาร์กิวเมนต์อื่นของ /pdpa-blur จะไม่เปลี่ยนการตั้งค่าใด และแสดงเพียงบรรทัดวิธีใช้ (usage)

แถบสถานะ (status line) แสดง PDPA: <โหมด> และต่อท้ายด้วย · REC เมื่ออยู่ในโหมดบันทึกหน้าจอ (เช่น PDPA: redact · REC) และเมื่อมอดปกปิดพรอมต์หรือข้อความที่บทสนทนาเก็บไว้ หรือไม่ส่งพรอมต์ จะมีข้อความแจ้งเตือน (toast) บอกจำนวนรายการที่พบ ส่วนการปกปิดใน CLAUDE.md, context block อื่น และไฟล์แนบ เช่น ไฟล์ที่อ้างถึงด้วย @ จะไม่มีการแจ้งเตือน ข้อความแจ้งเตือนนับเฉพาะรายการที่ตรงกับกฎ การไม่มีข้อความแจ้งเตือนไม่ได้หมายความว่าไม่มีข้อมูลส่วนบุคคลถูกส่งออกไป และการมีข้อความแจ้งเตือนก็ไม่ได้หมายความว่าข้อความนั้นไม่มีข้อมูลส่วนบุคคลเหลืออยู่แล้ว

ตรวจสอบว่ามอดทำงานอยู่ หลังเริ่ม Claude Code แถบสถานะควรแสดง PDPA: redact หรือ PDPA: block หากไม่แสดง แสดงว่ามอดไม่ได้โหลดและไม่มีการปกปิดใด ๆ ให้ใช้ claude --debug เพื่อดูสาเหตุ การทำงานแบบไม่มีหน้าจอโต้ตอบ (headless) เช่น claude -p ไม่มีแถบสถานะ จึงควรตรวจผลลัพธ์ของ debug ก่อนพึ่งพาการป้องกันในกรณีนั้น

การบันทึกหรือแชร์หน้าจอ

/pdpa-blur record เปิดโหมดบันทึกหน้าจอ (recording mode) สำหรับการบันทึกวิดีโอหน้าจอและการแชร์หน้าจอ การพรางยังเปิดอยู่ และการวางเมาส์จะไม่เปิดค่าที่พรางไว้ตลอดเวลาที่อยู่ในโหมดนี้ โหมดนี้ใช้ได้เฉพาะบน terminal และแอปเดสก์ท็อปเช่นเดียวกับการพรางแบบปกติ ไม่ได้บันทึกลงดิสก์ และทุกครั้งที่เริ่ม Claude Code การพรางจะเปิดอยู่และโหมดบันทึกหน้าจอจะปิดอยู่ ออกจากโหมดนี้ด้วย /pdpa-blur on หรือ /pdpa-blur off ควรหยุดบันทึกก่อนออกจากโหมดนี้ เพราะ /pdpa-blur on จะกลับมาแสดงค่าจริงเมื่อวางเมาส์ และ /pdpa-blur โดยไม่ระบุอาร์กิวเมนต์จะปิดการพราง นอกจากนี้เมื่อเริ่ม Claude Code ใหม่ โหมดบันทึกหน้าจอจะปิดอยู่ จึงควรตรวจแถบสถานะทุกครั้งหลังเริ่มใหม่หรือกลับมาทำงานต่อ (resume)

โหมดบันทึกหน้าจอพรางเฉพาะค่าที่ตรวจพบในข้อความของผู้ใช้และข้อความของ Claude ส่วนสิ่งอื่นที่ Claude Code แสดง เช่น การเรียกเครื่องมือ (tool call) และผลลัพธ์ ส่วนต่างของไฟล์ (diff) การคิดของโมเดล (thinking) ข้อความแจ้งเตือน และแผงอื่น จะแสดงตามปกติ

โหมดบันทึกหน้าจอไม่ครอบคลุม

  • ข้อมูลส่วนบุคคลที่กฎตรวจไม่พบ เช่น ชื่อที่ไม่มีป้ายกำกับหรือคำนำหน้าชื่อ (ดูหัวข้อ ข้อจำกัด) ซึ่งจะแสดงตามจริงโดยไม่ถูกพราง
  • ข้อความที่กำลังพิมพ์ในช่องพรอมต์ก่อนกดส่ง (ตัวป้องกันแทนค่าเมื่อกดส่งเท่านั้น)
  • การเรียกเครื่องมือ ผลลัพธ์ของเครื่องมือ และผลลัพธ์ของคำสั่งบนหน้าจอ
  • ข้อความต้นฉบับที่ปรากฏบนหน้าจอด้วยเหตุอื่น เช่น ไฟล์ที่เปิดอยู่ในหน้าต่างอื่น
  • การเลือกข้อความ ซึ่งอาจทำให้ข้อความที่พรางไว้อ่านได้บนหน้าจอ และการคัดลอกซึ่งยังได้ข้อความจริง

ในโหมด redact พรอมต์ที่ผู้ใช้ส่งแล้วแสดงเป็นป้ายแทนค่าอยู่แล้ว การพรางจึงมีผลหลักกับข้อความของ Claude และข้อความที่ส่งขณะปิดการป้องกัน (off) ข้อจำกัดอื่นของการพรางในหัวข้อ ข้อจำกัด ยังคงมีผล

ก่อนบันทึกหรือแชร์หน้าจอ

  1. ตั้งตัวป้องกันเป็นโหมด redact หรือ block (/pdpa-guard redact)
  2. สั่ง /pdpa-blur record และตรวจว่าแถบสถานะลงท้ายด้วย · REC
  3. ตรวจวิดีโอที่บันทึกไว้ก่อนแชร์

การพรางนี้เป็นเพียงการปิดบังทางสายตา ไม่ใช่หลักประกัน

ตัวอย่างก่อนและหลัง

ข้อความที่ผู้ใช้พิมพ์ (ค่าจริงแสดงเป็นคำอธิบายในวงเล็บมุม):

ช่วยร่างอีเมลแจ้งลูกค้า เบอร์ <เบอร์มือถือ 10 หลัก> อีเมล <อีเมลของลูกค้า>

ข้อความที่ Claude ได้รับในโหมด redact:

ช่วยร่างอีเมลแจ้งลูกค้า เบอร์ [REDACTED:PHONE_1~k3x9q] อีเมล [REDACTED:EMAIL_1~k3x9q]

รูปแบบของป้ายแทนค่าคือ [REDACTED:<ชนิด>_<ลำดับ>~<ส่วนต่อท้ายประจำเซสชัน>]

  • ชนิดข้อมูลบอก Claude ว่าตำแหน่งนั้นเป็นข้อมูลชนิดใด Claude จึงยังเขียนคำตอบที่อ้างถึงป้ายแทนค่าได้
  • ค่าเดียวกันที่ปรากฏซ้ำในข้อความชุดเดียวกัน (พรอมต์ ผลลัพธ์ของเครื่องมือหนึ่งรายการ ไฟล์แนบหนึ่งไฟล์ หรือกลุ่ม context block) ได้ป้ายแทนค่าเดียวกัน ลำดับเริ่มนับใหม่ในแต่ละชุด ดังนั้น PHONE_1 ในพรอมต์กับ PHONE_1 ในไฟล์ที่อ้างถึงด้วย @ หรือในผลลัพธ์ของเครื่องมือครั้งถัดไป อาจไม่ใช่หมายเลขเดียวกัน
  • ส่วนต่อท้ายประจำเซสชัน (session suffix) 5 อักขระช่วยให้มอดแยกป้ายแทนค่าที่มอดสร้างขึ้นจริงในเซสชันนี้ ออกจากข้อความที่เพียงกล่าวถึงรูปแบบของป้ายแทนค่า เช่น เอกสารฉบับนี้
  • การปกปิดย้อนกลับไม่ได้ มอดไม่มีตารางสำหรับแปลงป้ายแทนค่ากลับเป็นค่าเดิม

ข้อมูลที่ตรวจจับ

ชนิดสิ่งที่ตรวจ
THAI_IDเลขประจำตัวประชาชน 13 หลักซึ่งมีหลักตรวจสอบ (check digit) ถูกต้องตามสูตร mod 11
CARDเลขบัตรชำระเงิน (payment card) 13-19 หลักที่ผ่านการตรวจแบบ Luhn
PHONEหมายเลขโทรศัพท์มือถือและโทรศัพท์พื้นฐานของไทย รวมถึงรูปแบบ +66 และ 0066
EMAILที่อยู่อีเมล ยกเว้นอีเมลที่ใช้โดเมน example.com, example.org หรือ example.net โดยตรง (อีเมลที่ใช้โดเมนย่อยของโดเมนเหล่านี้ยังถูกปกปิด)
IPที่อยู่ IPv4 ยกเว้น 127.x.x.x และ 0.0.0.0
SECRETโทเค็น (token) ที่ขึ้นต้นด้วยคำนำหน้า (prefix) ที่รู้จัก ค่าหลัง Bearer และค่าหลังป้ายกำกับ (label) เช่น password, secret, token, api_key, รหัสผ่าน ทั้งนี้มอดนี้ไม่ใช่เครื่องมือสแกนความลับ (secret scanner) ตรวจพบเฉพาะรูปแบบที่ระบุไว้ใน DETECTION และข้ามค่าที่มีลักษณะเป็นโค้ด
PASSPORTเลขหนังสือเดินทางที่อยู่ถัดจากป้ายกำกับ เช่น passport, เลขที่หนังสือเดินทาง, พาสปอร์ต
BANK_ACCOUNTตัวเลข 10-15 หลักที่อยู่ถัดจากป้ายกำกับ เช่น เลขที่บัญชี, บัญชี, account no., พร้อมเพย์, PromptPay
DOBวันที่แบบตัวเลข (คั่นด้วย / . หรือ -) ที่อยู่ถัดจากป้ายกำกับ เช่น วันเกิด, date of birth, DOB ส่วนวันที่ที่เขียนชื่อเดือนเป็นตัวอักษรจะตรวจไม่พบ
SENSITIVEค่าหลังป้ายกำกับของหมวดข้อมูลอ่อนไหวส่วนใหญ่ตามมาตรา 26 เฉพาะเมื่อเขียนในรูป ป้ายกำกับ: ค่า เป็นภาษาไทยหรืออังกฤษ เช่น ศาสนา, ข้อมูลสุขภาพ, ประวัติอาชญากรรม ทั้งนี้ไม่ครอบคลุมถ้อยคำรูปแบบอื่น และไม่ครอบคลุมข้อมูลอื่นที่คณะกรรมการคุ้มครองข้อมูลส่วนบุคคลอาจประกาศกำหนด
ADDRESSค่าที่เขียนในรูป ป้ายกำกับ: ค่า โดยใช้ป้ายกำกับ ที่อยู่, home address หรือ mailing address (ป้ายกำกับ address: อย่างเดียวจะตรวจไม่พบ)
NAMEค่าที่เขียนในรูป ป้ายกำกับ: ค่า โดยใช้ป้ายกำกับ เช่น ชื่อ, นามสกุล, full name, surname รวมถึงชื่อที่ตามหลังคำนำหน้าชื่อ นาย, นาง, นางสาว, น.ส., ด.ช., ด.ญ., Mr, Mrs, Ms, Miss, Dr

สำหรับ SENSITIVE, ADDRESS และ NAME รูป ป้ายกำกับ: ค่า รวมถึง ป้ายกำกับ = ค่า เครื่องหมายทวิภาคแบบเต็มความกว้าง (:) และคีย์ JSON ในเครื่องหมายคำพูด เช่น "label": "value" ค่าหลังป้ายกำกับจะสิ้นสุดที่เครื่องหมายจุลภาค (,) อัฒภาค (;) เครื่องหมายคำพูด } หรือการขึ้นบรรทัดใหม่ที่พบก่อน ส่วนที่เหลือของที่อยู่หรือรายการจะถูกส่งไปตามที่เขียน และค่าที่ขึ้นต้นด้วย [ หรือ { (อาร์เรย์หรืออ็อบเจกต์ JSON) จะไม่ตรงกับกฎกลุ่มนี้เลย จึงไม่มีส่วนใดในค่านั้นถูกแทนค่า เว้นแต่กฎอื่น เช่น PHONE หรือ EMAIL ตรวจพบ

ทุกกฎอ่านเลขไทย (๐-๙) เหมือนเลขอารบิก

หมวดข้อมูลอ่อนไหวอ้างอิงมาตรา 26 แห่งพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. 2562 (ฉบับ PDF ที่ PDPC เผยแพร่, ตรวจสอบเมื่อ 4 ตุลาคม 2569) รายการป้ายกำกับทั้งหมด ข้อยกเว้น และการตรวจจับผิด (false positive) ที่ทราบ อยู่ใน docs/DETECTION.md

ข้อมูลของผู้ใช้ไปที่ใด

  • การตรวจจับและการปกปิดทำงานภายในโปรเซสของ Claude Code (บนเครื่องของผู้ใช้เมื่อใช้งานในเครื่อง หรือบนเครื่องที่เซสชันคลาวด์หรือเซสชันระยะไกลทำงานอยู่) ในเซสชันคลาวด์หรือเซสชันระยะไกล ค่าเดิมอยู่บนเครื่องนั้นแล้วก่อนที่มอดจะตรวจ มอดเปลี่ยนเฉพาะสิ่งที่ส่งต่อจากเครื่องนั้นไปให้โมเดล
  • pdpa-thai และ context-bar ไม่เรียกเครือข่าย โปรเซสภายนอก โมเดล หรือ MCP ด้วยตัวเอง ส่วน agents-panel เริ่ม subagent ผ่าน $.agent.spawn เฉพาะเมื่อผู้ใช้กดปุ่ม ▶ run และ subagent นั้นทำงานเหมือน agent ทั่วไป
  • boom-big-nose-workflow ไม่มีโค้ดฮุก คำสั่งของมอดรันสคริปต์ของมอดเอง (git, node, claude mcp list และ gh สำหรับการตรวจการล็อกอินใน /bbn-doctor และ /bbn-merge --apply --pr) เริ่ม subagent ในบทบาทเขียนโค้ด รวมโค้ด และรีวิว ซึ่งทำงานเหมือน agent ทั่วไป ถ้าติดตั้ง Codex CLI ไว้ bbn-codex.sh จะรัน Codex CLI ของผู้ใช้ ซึ่งเรียก OpenAI ด้วยการล็อกอินของผู้ใช้เอง และเพิ่มเซิร์ฟเวอร์ MCP ระยะไกล 2 ตัว คือ Context7 (https://mcp.context7.com/mcp) และ Perplexity (https://api.perplexity.ai/mcp ต้อง sign in ก่อน) คำค้นที่ agent ส่งไปยังเซิร์ฟเวอร์ที่เชื่อมต่ออยู่จะไปถึงบริการเหล่านั้น
  • ทุกครั้งที่มีการ push และ pull request CI จะทำการตรวจเฉพาะในเครื่อง (local-only) 2 รายการ ได้แก่ การค้นหาข้อความในโค้ดฮุกของทุกมอดว่ามีการเรียกเครือข่าย โปรเซส โมเดล หรือ MCP หรือ fetch( หรือไม่ และการตรวจว่าการเรียกเอนจินทุกรายการในบรรทัด calls: ที่ claude plugin validate pdpa-thai แสดง เป็นการเรียกกลุ่ม state, ui, clock หรือ command เท่านั้น การตรวจทั้งสองไม่ได้พิสูจน์สิ่งใดเกี่ยวกับมอดอื่นหรือตัว Claude Code เอง รายละเอียดของการตรวจทั้งสองและสิ่งที่ไม่ครอบคลุมอธิบายไว้แห่งเดียวในหัวข้อ สิ่งที่ CI ตรวจ
  • บทสนทนาที่ปกปิดแล้วยังถูกส่งไปยังผู้ให้บริการโมเดลที่ตั้งค่าไว้ (โดยค่าเริ่มต้นคือ Anthropic หรือผู้ให้บริการอื่น เช่น Amazon Bedrock หรือ Google Cloud Vertex AI) เช่นเดียวกับบทสนทนา Claude Code ทั่วไป
  • มอดนี้ไม่ได้เปลี่ยนวิธีที่ผู้ให้บริการโมเดลที่ตั้งค่าไว้ (โดยค่าเริ่มต้นคือ Anthropic) จัดเก็บ เก็บรักษา หรือใช้ข้อมูลที่ได้รับ ซึ่งเป็นไปตามข้อตกลงและการตั้งค่าระหว่างผู้ใช้หรือองค์กรกับผู้ให้บริการนั้น
  • การปกปิดมีผลกับสำเนาที่โมเดลอ่าน ค่าที่ตรวจพบแต่ละจุดถูกแทนด้วยป้ายแทนค่าก่อนส่งให้โมเดล แต่ค่าเดียวกันอาจยังถูกส่งออกไปหากปรากฏในส่วนที่มอดไม่ได้แก้ไข (ดูหัวข้อ ข้อจำกัด) และข้อมูลที่กฎตรวจไม่พบจะถูกส่งไปตามเดิม
  • การปกปิดไม่ใช่การทำให้เป็นข้อมูลนิรนาม (anonymisation) บทสนทนาที่ปกปิดแล้วอาจยังระบุตัวบุคคลได้ทั้งทางตรงหรือทางอ้อม ซึ่งเป็นลักษณะของข้อมูลส่วนบุคคลตามนิยามในมาตรา 6 ของ PDPA (ฉบับ PDF ที่ PDPC เผยแพร่, ตรวจสอบเมื่อ 4 ตุลาคม 2569) จึงอาจยังเป็นข้อมูลส่วนบุคคล และประเด็น เช่น ฐานทางกฎหมายในการประมวลผลและการส่งหรือโอนข้อมูลไปยังต่างประเทศ อาจยังต้องพิจารณา ควรปรึกษาทนายความที่มีคุณสมบัติเหมาะสมหรือ DPO ขององค์กร
  • มอดนี้แก้ไขเฉพาะสิ่งที่ Claude Code ส่งให้โมเดล ช่องทางอื่นเป็นช่องทางแยกต่างหาก ไม่อยู่ในขอบเขตของมอด และอาจได้รับค่าเดิม ได้แก่ Remote Control (ซึ่งส่งต่อผ่านบริการของ Anthropic ไปยัง claude.ai หรือแอป Claude) hook แบบคำสั่ง (command hook) ในการตั้งค่าของผู้ใช้ ระบบรวบรวม telemetry ที่องค์กรตั้งค่าไว้ และรายงานที่ผู้ใช้ส่งให้ Anthropic

ข้อจำกัด

  • กฎทั้งหมดเป็นนิพจน์ปรกติที่ไม่รับประกันผล จะมีข้อมูลที่ตรวจไม่พบ และจะมีข้อความทั่วไปบางส่วนถูกปกปิด
  • มอดนี้ไม่ใช่เครื่องมือสแกนความลับ (secret scanner) ตรวจพบเฉพาะรูปแบบโทเค็นและป้ายกำกับที่ระบุไว้ใน DETECTION และข้ามค่าที่มีลักษณะเป็นโค้ด จึงไม่ควรนำความลับเข้ามาในเซสชัน และควรใช้เครื่องมือสแกนความลับโดยเฉพาะ
  • ค่าหลังป้ายกำกับ (SENSITIVE, ADDRESS, NAME) จะสิ้นสุดที่เครื่องหมายจุลภาค อัฒภาค เครื่องหมายคำพูด } หรือการขึ้นบรรทัดใหม่ที่พบก่อน ส่วนที่เหลือของที่อยู่หรือรายการจะถูกส่งไปตามที่เขียน ค่าหลังป้ายกำกับที่ขึ้นต้นด้วย [ หรือ { (อาร์เรย์หรืออ็อบเจกต์ JSON) จะไม่ตรงกับกฎกลุ่มนี้เลย มีเพียงกฎอื่น เช่น PHONE หรือ EMAIL ที่ยังอาจแทนค่าบางส่วนในนั้นได้
  • ชื่อและที่อยู่ที่ไม่มีป้ายกำกับหรือคำนำหน้าชื่อ เช่น ชื่อที่ปรากฏกลางประโยค จะตรวจไม่พบ
  • ไม่ตรวจเนื้อหาในรูปภาพและเอกสารที่แนบเป็นบล็อกแยก
  • Claude Code ไม่เปิดให้มอดแก้ไขเนื้อหาบางส่วน จึงไม่มีการปกปิดในส่วนนั้น ได้แก่ กระบวนการคิดของโมเดล (thinking) และค่าที่ Claude ส่งให้เครื่องมือ (tool_use input)
  • ประวัติการสนทนาที่เปิดต่อ (resume) และทรานสคริปต์ (transcript) ของ subagent ที่บันทึกไว้แล้ว มอดจะไม่ตรวจซ้ำ ส่วนที่ไม่ได้ปกปิดในขณะบันทึกจะถูกส่งไปตามเดิม
  • ผลลัพธ์ของเครื่องมือแบบมีโครงสร้างและเนื้อหาของไฟล์แนบ (เช่น ไฟล์ที่อ้างถึงด้วย @) ที่ Claude Code เก็บไว้ยังคงเป็นค่าเดิมในทรานสคริปต์ และการแสดงผลลัพธ์ของเครื่องมือบนหน้าจอไม่ถูกพราง
  • ประวัติพรอมต์ของ Claude Code เอง (ที่เรียกกลับด้วยปุ่มลูกศรขึ้น) อยู่นอกการควบคุมของมอด และอาจเก็บข้อความที่ผู้ใช้พิมพ์ไว้บนเครื่องโดยไม่ปกปิด
  • ไม่ตรวจพรอมต์ระบบ (system prompt) เช่น ข้อมูลสภาพแวดล้อม คำแนะนำของเซิร์ฟเวอร์ MCP และส่วนที่ปลั๊กอินอื่นเพิ่มเข้าไป รวมถึงคำอธิบายของเครื่องมือและ skill
  • ไม่มีการปกปิดใน 3 ส่วนต่อไปนี้ ได้แก่ คำตอบของ Claude ข้อความสรุปที่ได้จากการบีบอัดบทสนทนา (compaction) และข้อความแจ้งจากระบบ (notice)
  • ค่าที่ถูกแบ่งไว้ในหลายข้อความอาจหลุดการตรวจจับ
  • หาก hook ของมอดเกิดข้อผิดพลาด (throw) หรือใช้เวลาเกินที่ Claude Code กำหนดต่อ hook หนึ่งตัว Claude Code จะข้าม hook นั้นและส่งข้อความไปตามเดิมโดยไม่ปกปิดและไม่มีการแจ้งเตือน (fail-open)
  • หากมอดไม่ได้โหลด จะไม่มีการปกปิดใด ๆ และสัญญาณเดียวคือไม่มีรายการ PDPA: บนแถบสถานะ ให้ใช้ claude --debug เพื่อดูสาเหตุ ทั้งนี้การทำงานแบบ headless (เช่น claude -p) ไม่มีแถบสถานะ
  • API ของ hook ยังอยู่ในระยะทดลองใช้ (early access) มอดนี้ทดสอบแล้วกับ Claude Code 2.1.289 เท่านั้น เวอร์ชันก่อนหน้าหรือใหม่กว่าอาจข้ามการป้องกันบางส่วนหรือทั้งหมดโดยไม่มีการแจ้งเตือน และป้าย (badge) ของ CI แสดงเพียงว่าชุดทดสอบหน่วย (unit test) ผ่านบน Claude Code เวอร์ชันล่าสุด
  • hook ของปลั๊กอินอื่นที่ทำงานก่อนมอดนี้อาจเห็นข้อความต้นฉบับ
  • ผลลัพธ์ของเครื่องมือและข้อความอื่นในบทสนทนาอาจแสดงในรูปแบบเดิมชั่วครู่ก่อนถูกปกปิด ทั้งบนหน้าจอของผู้ใช้และปลายทางที่เซสชันถูกส่งต่อไปแสดง เช่น Remote Control (ซึ่งส่งต่อผ่านบริการของ Anthropic ไปยัง claude.ai หรือแอป Claude) หรือ SDK stream
  • มอดนี้แก้ไขเฉพาะสิ่งที่ Claude Code ส่งให้โมเดล ช่องทางอื่นเป็นช่องทางแยกต่างหาก ไม่อยู่ในขอบเขตของมอด และอาจได้รับค่าเดิม ได้แก่ Remote Control (ซึ่งส่งต่อผ่านบริการของ Anthropic ไปยัง claude.ai หรือแอป Claude) hook แบบคำสั่ง (command hook) ในการตั้งค่าของผู้ใช้ ระบบรวบรวม telemetry ที่องค์กรตั้งค่าไว้ และรายงานที่ผู้ใช้ส่งให้ Anthropic
  • การพรางบนหน้าจอเป็นเพียงการปิดบังด้วยสี การคัดลอก การเลือกข้อความ โปรแกรมอ่านหน้าจอ การค้นหาใน terminal และการบันทึกหรือ log ของ terminal (เช่น tmux หรือ asciinema) ยังได้ค่าจริง ส่วนวิดีโอบันทึกหน้าจอจะเห็นค่าจริงเมื่อวางเมาส์บนข้อความนั้น เว้นแต่เปิดโหมดบันทึกหน้าจอ (/pdpa-blur record) ไว้ ทั้งนี้โหมดบันทึกหน้าจอไม่ครอบคลุมช่องพรอมต์ก่อนกดส่ง ผลลัพธ์ของเครื่องมือหรือคำสั่ง และข้อความต้นฉบับที่แสดงอยู่ที่อื่น (ดูหัวข้อ การบันทึกหรือแชร์หน้าจอ) terminal ที่ปรับความต่างของสีอัตโนมัติ (เช่น terminal ใน VS Code ซึ่งเปิดการตั้งค่า minimum contrast ratio ไว้โดยค่าเริ่มต้น) อาจแสดงข้อความที่พรางไว้ให้อ่านได้ การพรางใช้ได้เฉพาะ terminal และแอปเดสก์ท็อป และไม่พรางข้อความที่ยาวเกิน 100,000 ตัวอักษร
  • การปฏิเสธการเรียกเครื่องมือจับเฉพาะป้ายแทนค่าของเซสชันนี้ที่เขียนตรงตามรูปแบบเดิม และไม่ทำงานในโหมด off
  • ข้อความแจ้งเตือนนับเฉพาะรายการที่ตรงกับกฎ การไม่มีข้อความแจ้งเตือนไม่ได้หมายความว่าไม่มีข้อมูลส่วนบุคคลถูกส่งออกไป และการมีข้อความแจ้งเตือนก็ไม่ได้หมายความว่าข้อความนั้นไม่มีข้อมูลส่วนบุคคลเหลืออยู่แล้ว
  • Claude เห็นเพียงป้ายแทนค่า จึงใช้ค่าจริงทำงานไม่ได้ และการปกปิดย้อนกลับไม่ได้ การปิดการป้องกันจึงไม่ได้คืนค่าที่ถูกปกปิดไปแล้ว หากงานต้องใช้ค่าจริง ให้ใช้ /pdpa-guard off แล้วส่งค่าจริงอีกครั้ง และเปิดกลับด้วย /pdpa-guard redact เมื่องานนั้นเสร็จ ระหว่างที่ปิดอยู่ มอดจะไม่ปฏิเสธการเรียกเครื่องมือที่มีป้ายแทนค่าเดิม จึงควรตรวจสิ่งที่ Claude เขียนลงไฟล์
  • ข้อมูลที่ส่งออกไประหว่างปิดการป้องกัน (off) จะคงอยู่ในบทสนทนาตามเดิม การเปิดการป้องกันกลับไม่ได้ปกปิดย้อนหลัง และข้อมูลนั้นจะถูกส่งซ้ำไปกับทุกคำขอถัดไปในบทสนทนาเดียวกัน หากต้องการตัดออก ให้ใช้ /clear หรือเริ่มเซสชันใหม่
  • CLAUDE.md, context block อื่น และไฟล์แนบ จะคงผลจากครั้งแรกที่ Claude Code เตรียมเนื้อหานั้นไว้ การเปลี่ยนโหมดภายหลังจึงไม่มีผลกับเนื้อหาที่เตรียมไว้แล้ว ทั้งนี้ context block จะถูกเตรียมใหม่หลังใช้ /clear หรือหลังการบีบอัดบทสนทนา
  • CLAUDE.md และ context block อื่นถูกปกปิดด้วย Claude จึงไม่เห็นค่าจริงที่ผู้ใช้ตั้งใจเขียนไว้ เช่น อีเมลของผู้ใช้ใน CLAUDE.md
  • ข้อมูลที่เปิดเผยต่อสาธารณะอยู่แล้ว เช่น หมายเลขโทรศัพท์ติดต่อของหน่วยงาน ก็ถูกปกปิดหากตรงกับรูปแบบ
  • มอดนี้ช่วยลดข้อมูลที่ถูกส่งออกไป แต่ไม่ได้ทำให้ Claude Code หยุดส่งบทสนทนา (ที่ปกปิดแล้ว) ไปยังผู้ให้บริการโมเดลที่ตั้งค่าไว้ (โดยค่าเริ่มต้นคือ Anthropic)
  • มอดทำงานแยกตามผู้ใช้และตามเครื่อง และผู้ใช้ปิดได้ทุกเมื่อ (/pdpa-guard off หรือ claude plugin disable) จึงบังคับใช้จากส่วนกลางไม่ได้ และมอดไม่เก็บบันทึกการ
Source 2 files
hooks/register.tsx 143 lines
1import { atom, read, update } from 'claude-code'
2import type { EngineInterface, Register } from 'claude-code'
3
4import type { Fill } from '../types'
5
6const fill = atom({ plugin: 'context-bar', key: 'fill' } as const, null)
7const isHidden = atom({ plugin: 'context-bar', key: 'isHidden' } as const, false)
8const cache = atom({ plugin: 'context-bar', key: 'cache' } as const, null)
9// in $.state, not a module variable: a hot reload would lose it and freeze the countdown
10const endsAt = atom({ plugin: 'context-bar', key: 'endsAt' } as const, null)
11
12// ponytail: fixed 5-minute prompt-cache TTL; set 3_600_000 if the session uses the 1h cache
13const TTL_MS = 5 * 60 * 1000
14
15const fmt = (n: number) =>
16  n >= 1e6 ? `${+(n / 1e6).toFixed(1)}M` : n >= 1e4 ? `${Math.round(n / 1e3)}k` : n >= 1e3 ? `${(n / 1e3).toFixed(1)}k` : `${n}`
17
18const SHORT: Record<string, string> = {
19  'system prompt': 'prompt',
20  'system tools': 'tools',
21  'mcp tools': 'mcp',
22  'mcp server instructions': 'mcp instr',
23  'custom agents': 'agents',
24  'memory files': 'memory',
25  messages: 'msgs',
26  'autocompact buffer': 'buffer',
27  'free space': 'free',
28}
29
30const mmss = (s: number) => `${Math.floor(s / 60)}:${String(s % 60).padStart(2, '0')}`
31
32async function refresh($: EngineInterface) {
33  try {
34    const { context } = await $.session.usage({ breakdown: 'summary' })
35    const b = context.breakdown
36    const cats = (b?.categories ?? [])
37      .filter(c => !c.isDeferred)
38      .map(({ name, tokens, color, kind }) => ({ name, tokens, color, kind }))
39    const buffer = cats.find(c => c.kind === 'buffer')
40    const next: Fill | null = b
41      ? {
42          cats,
43          total: b.totalTokens,
44          window: b.rawMaxTokens,
45          pct: b.percentage,
46          compactAt: buffer ? b.rawMaxTokens - buffer.tokens : null,
47        }
48      : null
49    await update($, fill, () => next)
50  } catch {
51    // no usage before the session binds; the next turn.complete retries
52  }
53}
54
55export const register: Register = on => {
56  on('session.start', async ($, e, next) => {
57    await $.command.register({
58      name: 'context-bar',
59      description: 'Show or hide the context window breakdown above the prompt',
60    })
61    await refresh($)
62    $.clock.every(1000, async () => {
63      const end = await read($, endsAt)
64      if (end === null) return
65      const left = Math.max(0, Math.ceil((end - (await $.clock.now())) / 1000))
66      await update($, cache, () => left)
67      if (left === 0) await update($, endsAt, () => null) // cold: stop redrawing every second
68    })
69    return next(e)
70  })
71
72  on('prompt.submit', async ($, e, next) => {
73    await update($, endsAt, () => null)
74    await update($, cache, () => 'live' as const)
75    return next(e)
76  })
77
78  on('turn.complete', async ($, e, next) => {
79    const end = (await $.clock.now()) + TTL_MS
80    await update($, endsAt, () => end)
81    await update($, cache, () => TTL_MS / 1000)
82    await refresh($)
83    return next(e)
84  })
85
86  on('command.run', { command: 'context-bar' }, async $ => {
87    const wasHidden = await read($, isHidden)
88    await update($, isHidden, () => !wasHidden)
89    if (wasHidden) await refresh($)
90    return { text: wasHidden ? 'Context bar shown.' : 'Context bar hidden.' }
91  })
92
93  on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
94    const f = await read($, fill)
95    if (e.props.hasSurvey || f === null || (await read($, isHidden))) return next(e)
96
97    const c = await read($, cache)
98    const { Box, Text } = $.ui.resolve(e)
99    // the box the band draws into (narrower than the viewport beside a docked pane)
100    const width = Math.max(24, (e.props.bodyColumns ?? 80) - 2)
101    const sum = f.cats.reduce((a, k) => a + k.tokens, 0) || 1
102    // ponytail: fixed 70/85 thresholds, make them options if they need tuning
103    const tone = f.pct >= 85 ? 'red' : f.pct >= 70 ? 'yellow' : 'green'
104    const cacheTone = c === 'live' || (c !== null && c > 60) ? 'green' : c === 0 ? 'red' : 'yellow'
105
106    return (
107      <Box flexDirection="column" width={width}>
108        <Box width={width} flexWrap="wrap" justifyContent="space-between">
109          <Box>
110            <Text bold>◆ context</Text>
111            {c !== null && (
112              <Text color={cacheTone}>  ⏱ cache {c === 'live' ? 'live' : c === 0 ? 'cold' : mmss(c)}</Text>
113            )}
114          </Box>
115          <Box>
116            <Text bold>{fmt(f.total)}</Text>
117            <Text dimColor> of {fmt(f.window)}</Text>
118            {f.compactAt !== null && <Text dimColor> · compacts at {fmt(f.compactAt)} </Text>}
119            <Text color={tone} inverse bold> {Math.round(f.pct)}% </Text>
120          </Box>
121        </Box>
122        {/* colour blocks sized by flex, not by glyph count: a glyph's advance differs per surface */}
123        <Box width={width} height={1} overflow="hidden">
124          {f.cats
125            .filter(k => k.tokens > 0)
126            .map(k => (
127              <Box key={k.name} flexGrow={Math.max(1, Math.round((k.tokens / sum) * 1000))} minWidth={1} height={1} backgroundColor={k.color} />
128            ))}
129        </Box>
130        <Box width={width} flexWrap="wrap">
131          {f.cats.map(k => (
132            <Box key={k.name} marginRight={2}>
133              <Text color={k.color}>■ </Text>
134              <Text dimColor>{SHORT[k.name.toLowerCase()] ?? k.name.toLowerCase()} </Text>
135              <Text bold>{fmt(k.tokens)}</Text>
136            </Box>
137          ))}
138        </Box>
139      </Box>
140    )
141  })
142}
143
types/index.d.ts 17 lines
1export type Cat = { name: string; tokens: number; color: string; kind: string }
2export type Fill = {
3  cats: Cat[]
4  total: number
5  window: number
6  pct: number
7  compactAt: number | null
8}
9// seconds of prompt cache left; 'live' while a turn runs; null before the first turn
10export type Cache = number | 'live' | null
11
12declare module 'claude-code' {
13  interface PluginState {
14    'context-bar': { fill: Fill | null; isHidden: boolean; cache: Cache; endsAt: number | null }
15  }
16}
17