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

มอด (mod) สำหรับ Claude Code: ตัวช่วยลดความเสี่ยงในการส่งข้อมูลส่วนบุคคลให้โมเดล (pdpa-thai) แถบแสดงการใช้ context (context-bar) แผงรายการ agent (agents-panel) และเวิร์กโฟลว์ multi-agent (boom-big-nose-workflow)
ไทย · 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-thai | 0.3.0 | `/pdpa-guard [redact\ | block\ | off], /pdpa-blur [on\ | off\ | record]` | ปกปิดข้อมูลส่วนบุคคลที่ตรวจพบก่อนส่งให้ Claude และพรางข้อมูลบนหน้าจอ (วางเมาส์เพื่อดู หรือวางเมาส์แล้วไม่แสดงค่าจริงในโหมดบันทึกหน้าจอ) |
context-bar | 0.4.0 | /context-bar | แถบเหนือช่องพิมพ์ แสดงการใช้ context window แยกตามหมวด และเวลาที่เหลือของ prompt cache | ||||
agents-panel | 0.1.0 | /agents-panel | แผงด้านข้างแสดง agent ของโปรเจกต์ ของผู้ใช้ และของปลั๊กอิน พร้อมปุ่มเรียกใช้ | ||||
boom-big-nose-workflow | 0.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
@ ไฟล์ CLAUDE.md และ context block อื่นมอดแก้ไขเฉพาะบล็อกข้อความ (text block) และข้อความในผลลัพธ์ของเครื่องมือ บล็อกชนิดอื่น เช่น รูปภาพหรือเอกสาร ถูกส่งไปตามเดิม
off หากการเรียกเครื่องมือของ Claude มีป้ายแทนค่าที่มอดสร้างขึ้นในเซสชัน (session) นี้ตรงตามรูปแบบเดิม มอดจะปฏิเสธการเรียกนั้นและแจ้งให้ Claude ขอค่าจริงจากผู้ใช้ ซึ่งช่วยลดโอกาสที่ป้ายแทนค่าจะถูกเขียนลงไฟล์หรือคำสั่งจริง การตรวจนี้จับไม่ได้หาก 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) ข้อจำกัดอื่นของการพรางในหัวข้อ ข้อจำกัด ยังคงมีผล
ก่อนบันทึกหรือแชร์หน้าจอ
redact หรือ block (/pdpa-guard redact)/pdpa-blur record และตรวจว่าแถบสถานะลงท้ายด้วย · RECการพรางนี้เป็นเพียงการปิดบังทางสายตา ไม่ใช่หลักประกัน
ข้อความที่ผู้ใช้พิมพ์ (ค่าจริงแสดงเป็นคำอธิบายในวงเล็บมุม):
ช่วยร่างอีเมลแจ้งลูกค้า เบอร์ <เบอร์มือถือ 10 หลัก> อีเมล <อีเมลของลูกค้า>
ข้อความที่ Claude ได้รับในโหมด redact:
ช่วยร่างอีเมลแจ้งลูกค้า เบอร์ [REDACTED:PHONE_1~k3x9q] อีเมล [REDACTED:EMAIL_1~k3x9q]
รูปแบบของป้ายแทนค่าคือ [REDACTED:<ชนิด>_<ลำดับ>~<ส่วนต่อท้ายประจำเซสชัน>]
PHONE_1 ในพรอมต์กับ PHONE_1 ในไฟล์ที่อ้างถึงด้วย @ หรือในผลลัพธ์ของเครื่องมือครั้งถัดไป อาจไม่ใช่หมายเลขเดียวกัน| ชนิด | สิ่งที่ตรวจ |
|---|---|
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
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 ส่งไปยังเซิร์ฟเวอร์ที่เชื่อมต่ออยู่จะไปถึงบริการเหล่านั้นfetch( หรือไม่ และการตรวจว่าการเรียกเอนจินทุกรายการในบรรทัด calls: ที่ claude plugin validate pdpa-thai แสดง เป็นการเรียกกลุ่ม state, ui, clock หรือ command เท่านั้น การตรวจทั้งสองไม่ได้พิสูจน์สิ่งใดเกี่ยวกับมอดอื่นหรือตัว Claude Code เอง รายละเอียดของการตรวจทั้งสองและสิ่งที่ไม่ครอบคลุมอธิบายไว้แห่งเดียวในหัวข้อ สิ่งที่ CI ตรวจSENSITIVE, ADDRESS, NAME) จะสิ้นสุดที่เครื่องหมายจุลภาค อัฒภาค เครื่องหมายคำพูด } หรือการขึ้นบรรทัดใหม่ที่พบก่อน ส่วนที่เหลือของที่อยู่หรือรายการจะถูกส่งไปตามที่เขียน ค่าหลังป้ายกำกับที่ขึ้นต้นด้วย [ หรือ { (อาร์เรย์หรืออ็อบเจกต์ JSON) จะไม่ตรงกับกฎกลุ่มนี้เลย มีเพียงกฎอื่น เช่น PHONE หรือ EMAIL ที่ยังอาจแทนค่าบางส่วนในนั้นได้@) ที่ Claude Code เก็บไว้ยังคงเป็นค่าเดิมในทรานสคริปต์ และการแสดงผลลัพธ์ของเครื่องมือบนหน้าจอไม่ถูกพรางPDPA: บนแถบสถานะ ให้ใช้ claude --debug เพื่อดูสาเหตุ ทั้งนี้การทำงานแบบ headless (เช่น claude -p) ไม่มีแถบสถานะ/pdpa-blur record) ไว้ ทั้งนี้โหมดบันทึกหน้าจอไม่ครอบคลุมช่องพรอมต์ก่อนกดส่ง ผลลัพธ์ของเครื่องมือหรือคำสั่ง และข้อความต้นฉบับที่แสดงอยู่ที่อื่น (ดูหัวข้อ การบันทึกหรือแชร์หน้าจอ) terminal ที่ปรับความต่างของสีอัตโนมัติ (เช่น terminal ใน VS Code ซึ่งเปิดการตั้งค่า minimum contrast ratio ไว้โดยค่าเริ่มต้น) อาจแสดงข้อความที่พรางไว้ให้อ่านได้ การพรางใช้ได้เฉพาะ terminal และแอปเดสก์ท็อป และไม่พรางข้อความที่ยาวเกิน 100,000 ตัวอักษรoff/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/pdpa-guard off หรือ claude plugin disable) จึงบังคับใช้จากส่วนกลางไม่ได้ และมอดไม่เก็บบันทึกการhooks/register.tsx 143 lines1import { 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}
143types/index.d.ts 17 lines1export 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