SLOPSHOPPER

agent-tips-th

ทิปสั่ง Claude Code วันละข้อ พร้อม template prompt ที่ใช้ได้จริง ค้นหา บันทึกเป็นรายการโปรด และเติมลงช่องพิมพ์ให้ทันที

newcommandtoast
A shopper browsing a rack in a slop shop
Preview · a replayed session in a sandbox
claude · ~/work/app · agent-tips-th
› fix the failing auth test and add an audit log call ╭────────────────────────────────────────────╮ │ agent-tips-th │ ⏺ Read(src/auth.ts) │ 💡 ทิปวันนี้: บอกให้ชัดว่า "เสร็จ" │ ⎿ Read 6 lines │ หน้าตาเป็นยังไง (/agenttips) │ ⏺ 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 › /agenttips ⎿ agent-tips-th: 📅 ทิปวันนี้ ⎿ agent-tips-th: 💡 [พื้นฐาน] บอกให้ชัดว่า "เสร็จ" หน้าตาเป็นยังไง ⎿ agent-tips-th: แทน "ทำหน้า login" ให้บอก "หน้า login มี email+password, กด Enter ส่งได้, ผิดแล้วขึ้นข้อความสีแดง, มีเทสต์ครอบ ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── › ? for shortcuts
README

Mod 32: Agent Tips TH

ทิปสั่ง Claude Code วันละข้อ (แสดงตอนเปิด Claude Code ครั้งแรกของวัน) 20 ข้อใน 6 หมวด เฉพาะฟีเจอร์ที่มีจริง พร้อม template prompt 8 แบบ (แก้บั๊ก ฟีเจอร์ใหม่ refactor รีวิว เขียนเทสต์ อธิบายโค้ด commit หาจุดช้า) เลือกแล้วเติมลงช่องพิมพ์ให้ทันที

คำสั่ง

คำสั่งทำอะไร
/agenttipsทิปวันนี้
/agenttips random / allสุ่ม / ดูทั้งหมด
/agenttips cat <หมวด>ทิปตามหมวด
/agenttips search <คำ>ค้นทิป
/agenttips fav [id]รายการโปรด
/agenttips template [ชื่อ]เติม template ลงช่องพิมพ์

ติดตั้ง

/plugin install agent-tips-th --marketplace tksoft11/claude-code-mods-th

ต้องตั้ง CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 ก่อนเปิด claude (ดู README หลัก)

โค้ดสอนอะไร

เปิด hooks/register.tsx แล้วอ่านตามบทที่เขียนไว้ในคอมเมนต์:

  1. คลังทิป
  2. template prompt ที่มี {ช่องว่าง} ให้เติม
  3. คำสั่ง /agenttips และการเติมช่องพิมพ์ด้วย $.prompt.fill

หมายเหตุ

ใช้ชื่อ /agenttips เพราะ /tips เป็นของ Mod 03 และ /prompt เป็นของ Mod 11

Source 1 files
hooks/register.tsx 155 lines
1/**
2 * ============================================================================
3 * MOD 32: Agent Tips TH - ทิปสั่ง Claude Code วันละข้อ + template prompt (ฉบับสอนทำ)
4 * ============================================================================
5 * แรงบันดาลใจจาก: Claude Code best practices และ prompt engineering guide ของ Anthropic
6 *
7 * หน้าที่ของ Mod นี้:
8 * 1. ทิปประจำวัน (เปลี่ยนทุกวัน) แสดงตอนเปิด Claude Code ครั้งแรกของวัน
9 * 2. ค้นทิปตามหมวดหรือคำค้น, สุ่ม, บันทึกเป็นรายการโปรด
10 * 3. Template prompt ที่ใช้บ่อย (แก้บั๊ก ฟีเจอร์ใหม่ refactor รีวิวโค้ด เขียนเทสต์ ฯลฯ)
11 *    เลือกแล้วเติมลงช่องพิมพ์ให้ทันที ($.prompt.fill) แก้นิดหน่อยแล้วกด Enter ได้เลย
12 *
13 * หมายเหตุ: ใช้ชื่อ /agenttips เพราะ /tips เป็นของ Mod 03 และ /prompt เป็นของ Mod 11
14 */
15
16import type { Register } from 'claude-code'
17
18interface Tip {
19  id: string
20  category: 'พื้นฐาน' | 'บริบท' | 'วางแผน' | 'ตรวจสอบ' | 'ประหยัด' | 'ทีม'
21  title: string
22  body: string
23}
24
25// ==========================================================================
26// บทที่ 1: คลังทิป - เฉพาะฟีเจอร์ที่มีจริงใน Claude Code
27// ==========================================================================
28const TIPS: Tip[] = [
29  { id: 'mention', category: 'บริบท', title: 'ใช้ @ ชี้ไฟล์', body: 'พิมพ์ @ แล้วเลือกไฟล์ Claude จะอ่านไฟล์นั้นทันที ไม่ต้องเสียเวลาเดาว่าอยู่ตรงไหน' },
30  { id: 'specific', category: 'พื้นฐาน', title: 'บอกให้ชัดว่า "เสร็จ" หน้าตาเป็นยังไง', body: 'แทน "ทำหน้า login" ให้บอก "หน้า login มี email+password, กด Enter ส่งได้, ผิดแล้วขึ้นข้อความสีแดง, มีเทสต์ครอบ" ยิ่งชัดยิ่งไม่ต้องแก้ซ้ำ' },
31  { id: 'plan', category: 'วางแผน', title: 'งานใหญ่ให้วางแผนก่อน', body: 'กด Shift+Tab จนขึ้น plan mode Claude จะสำรวจโค้ดและเสนอแผนก่อนแก้ไฟล์ ตรวจแผนแล้วค่อยให้ลงมือ' },
32  { id: 'read-first', category: 'วางแผน', title: 'ให้อ่านก่อนแก้', body: 'ขึ้นต้นด้วย "อ่าน src/auth ก่อน ยังไม่ต้องแก้ อธิบายว่า flow ทำงานยังไง" จะได้รู้ว่า Claude เข้าใจตรงกับเราไหม' },
33  { id: 'claude-md', category: 'บริบท', title: 'มี CLAUDE.md ในโปรเจกต์', body: 'รัน /init ให้ Claude สร้าง CLAUDE.md สรุปคำสั่ง build/test และกฎของโปรเจกต์ ทุก session จะอ่านไฟล์นี้ก่อนเสมอ' },
34  { id: 'tests', category: 'ตรวจสอบ', title: 'ให้ Claude รันเทสต์ยืนยันเอง', body: 'ใส่ประโยค "รันเทสต์ให้ผ่านก่อนบอกว่าเสร็จ" หรือ "เขียนเทสต์ที่ fail ก่อน แล้วค่อยแก้โค้ด" ผลจะเชื่อถือได้กว่ามาก' },
35  { id: 'esc', category: 'พื้นฐาน', title: 'กด Esc หยุดได้ทุกเมื่อ', body: 'เห็น Claude เริ่มไปผิดทาง กด Esc หยุดแล้วบอกทางที่ถูก ไม่ต้องรอให้ทำจนเสร็จ' },
36  { id: 'esc-esc', category: 'พื้นฐาน', title: 'กด Esc สองครั้ง ย้อนไปแก้ข้อความก่อนหน้า', body: 'สั่งผิดหรืออยากเปลี่ยนคำสั่ง กด Esc สองครั้งเพื่อเลือกข้อความเก่ามาแก้แล้วส่งใหม่' },
37  { id: 'bang', category: 'พื้นฐาน', title: 'ขึ้นต้นด้วย ! เพื่อรันคำสั่ง shell เอง', body: 'พิมพ์ !git status ผลลัพธ์จะเข้าไปอยู่ในบทสนทนาให้ Claude เห็นด้วย' },
38  { id: 'image', category: 'บริบท', title: 'วางรูปหน้าจอได้', body: 'แคปหน้าจอ UI ที่พัง หรือ error ในเบราว์เซอร์ แล้ววางในช่องพิมพ์ Claude อ่านรูปได้' },
39  { id: 'compact', category: 'ประหยัด', title: '/compact เมื่อคุยยาว', body: 'บทสนทนายาวทำให้แต่ละรอบช้าและแพงขึ้น /compact จะสรุปบริบทให้สั้นลงแต่ยังจำเรื่องเดิมได้' },
40  { id: 'clear', category: 'ประหยัด', title: '/clear เมื่อเปลี่ยนเรื่อง', body: 'เปลี่ยนไปทำงานคนละเรื่องให้ /clear เริ่มใหม่ บริบทเก่าที่ไม่เกี่ยวจะไม่มารบกวน' },
41  { id: 'model', category: 'ประหยัด', title: 'เลือก model ให้เหมาะกับงาน', body: 'งานเล็ก (เปลี่ยนชื่อ แปล สรุป) ใช้ model เล็กที่เร็วและถูกกว่าได้ งานยากค่อยใช้ตัวใหญ่ เปลี่ยนด้วย /model' },
42  { id: 'small-steps', category: 'วางแผน', title: 'แบ่งงานเป็นชิ้นเล็ก', body: 'แทนสั่งทีเดียว "ทำระบบสมาชิก" ให้ทำทีละขั้น: model ข้อมูล → API → หน้าจอ → เทสต์ ตรวจทีละขั้นง่ายกว่ามาก' },
43  { id: 'subagent', category: 'วางแผน', title: 'ให้ใช้ subagent สำรวจ', body: 'งานค้นหาทั่วโปรเจกต์ บอกว่า "ใช้ subagent ไปหาว่า..." บริบทหลักจะไม่ถูกผลค้นหาจำนวนมากกินที่' },
44  { id: 'why', category: 'ตรวจสอบ', title: 'ถามว่า "ทำไม" ก่อนยอมรับ', body: 'ไม่แน่ใจโค้ดที่ได้ ถาม "ทำไมเลือกวิธีนี้ มีทางอื่นไหม ข้อเสียคืออะไร" จะเห็นจุดที่ Claude อาจมองข้าม' },
45  { id: 'diff', category: 'ตรวจสอบ', title: 'ดู diff ก่อน commit เสมอ', body: 'สั่ง "สรุปสิ่งที่เปลี่ยนใน git diff" หรือดูเองด้วย !git diff ก่อน commit ทุกครั้ง' },
46  { id: 'permissions', category: 'ทีม', title: 'ตั้งสิทธิ์คำสั่งที่ใช้บ่อย', body: 'ใช้ /permissions อนุญาตคำสั่งปลอดภัยที่ใช้บ่อย (เช่น npm test) จะไม่ต้องกดอนุญาตซ้ำทุกครั้ง' },
47  { id: 'resume', category: 'พื้นฐาน', title: 'กลับมาคุยต่อได้', body: 'ปิดไปแล้วอยากคุยต่อ ใช้ claude --continue (ล่าสุด) หรือ /resume เลือก session เก่า' },
48  { id: 'examples', category: 'บริบท', title: 'ให้ตัวอย่างที่มีอยู่แล้ว', body: '"เขียน API ใหม่ให้หน้าตาเหมือน src/api/users.ts" Claude จะทำตามสไตล์ของโปรเจกต์โดยไม่ต้องอธิบายยาว' },
49]
50
51// ==========================================================================
52// บทที่ 2: Template prompt - {ช่องว่าง} คือส่วนที่ต้องเติมเอง
53// ==========================================================================
54const TEMPLATES: Record<string, { name: string; text: string }> = {
55  bug: { name: 'แก้บั๊ก', text: 'บั๊ก: {อาการที่เห็น}\nขั้นตอนทำให้เกิด: {1. ... 2. ...}\nที่ควรเป็น: {ผลที่ถูกต้อง}\n\nหาสาเหตุก่อน อธิบายให้ฟังว่าเกิดจากอะไร แล้วค่อยแก้ เขียนเทสต์ที่จับบั๊กนี้ได้ และรันเทสต์ให้ผ่าน' },
56  feature: { name: 'ฟีเจอร์ใหม่', text: 'อยากเพิ่ม: {ฟีเจอร์}\nผู้ใช้คือ: {ใคร} และใช้ทำ: {เพื่ออะไร}\nถือว่าเสร็จเมื่อ:\n- {เงื่อนไข 1}\n- {เงื่อนไข 2}\n\nวางแผนก่อน บอกไฟล์ที่จะแก้ แล้วรอผมยืนยันก่อนลงมือ' },
57  refactor: { name: 'Refactor', text: 'Refactor {ไฟล์หรือฟังก์ชัน} ให้ {อ่านง่ายขึ้น / แยกส่วน / ลดโค้ดซ้ำ}\nห้ามเปลี่ยนพฤติกรรมที่ผู้ใช้เห็น รันเทสต์ก่อนและหลังให้ผลเหมือนกัน แก้ทีละขั้นเล็กๆ' },
58  review: { name: 'รีวิวโค้ด', text: 'รีวิว git diff ปัจจุบัน หาบั๊ก, edge case ที่พลาด, ปัญหาความปลอดภัย และจุดที่อ่านยาก เรียงจากสำคัญมากไปน้อย อ้างบรรทัดด้วย ยังไม่ต้องแก้' },
59  test: { name: 'เขียนเทสต์', text: 'เขียนเทสต์ให้ {ไฟล์/ฟังก์ชัน} ครอบกรณีปกติ กรณีขอบ (ค่าว่าง ค่าติดลบ ข้อมูลใหญ่) และกรณี error ใช้ framework เดียวกับเทสต์ที่มีอยู่ แล้วรันให้ผ่าน' },
60  explain: { name: 'อธิบายโค้ด', text: 'อธิบาย {ไฟล์/โฟลเดอร์} ให้ Dev ใหม่เข้าใจ: ทำหน้าที่อะไร ข้อมูลไหลยังไง จุดที่ต้องระวังคืออะไร ตอบเป็นภาษาไทย ยังไม่ต้องแก้อะไร' },
61  commit: { name: 'ข้อความ commit', text: 'ดู git diff ที่ staged อยู่ แล้วเขียน commit message: บรรทัดแรกสั้นไม่เกิน 60 ตัว บอกว่าเปลี่ยนอะไร ย่อหน้าถัดไปบอกว่าทำไม' },
62  perf: { name: 'หาจุดช้า', text: '{หน้า/ฟังก์ชัน} ช้า ({ตัวเลขที่วัดได้ ถ้ามี}) หาว่าช้าตรงไหน วัดให้เห็นก่อนแก้ แล้วเสนอวิธีแก้ที่คุ้มที่สุด 2-3 ทาง' },
63}
64
65const CATEGORIES = [...new Set(TIPS.map(t => t.category))]
66let favorites: string[] = []
67
68function format(t: Tip): string {
69  return `💡 [${t.category}] ${t.title}\n${t.body}`
70}
71
72// ทิปประจำวัน: เลือกจากลำดับวันในปี ได้ทิปเดิมทั้งวัน
73function tipOfDay(now: number): Tip {
74  const d = new Date(now)
75  const day = Math.floor((d.getTime() - new Date(d.getFullYear(), 0, 1).getTime()) / 86_400_000)
76  return TIPS[day % TIPS.length] ?? TIPS[0]!
77}
78
79const HELP = `💡 Agent Tips TH (Mod 32)
80========================================
81/agenttips                ทิปวันนี้
82/agenttips random | all
83/agenttips cat <หมวด>     หมวด: ${CATEGORIES.join(', ')}
84/agenttips search <คำ>
85/agenttips fav [id]       ดู/เพิ่ม/เอาออกจากรายการโปรด
86/agenttips template [ชื่อ]   ${Object.entries(TEMPLATES).map(([k, t]) => `${k}=${t.name}`).join(' ')}
87   เลือกแล้วเติมลงช่องพิมพ์ให้ แก้ {ช่องว่าง} แล้วกด Enter`
88
89export const register: Register = on => {
90  on('session.start', async ($, e, next) => {
91    const saved = await $.store.get('favorites')
92    favorites = Array.isArray(saved) ? (saved as string[]) : []
93    // ทิปวันนี้แสดงครั้งแรกของวันเท่านั้น
94    const now = await $.clock.now()
95    const today = new Date(now).toDateString()
96    if ((await $.store.get('shownOn')) !== today) {
97      $.ui.toast(`💡 ทิปวันนี้: ${tipOfDay(now).title} (/agenttips)`, { timeoutMs: 8000 })
98      await $.store.set('shownOn', today)
99    }
100    await $.command.register({ name: 'agenttips', description: 'ทิปสั่ง Claude Code วันละข้อ + template prompt (/agenttips help)', argumentHint: 'random|cat|search|fav|template' })
101    return next(e)
102  })
103
104  // ==========================================================================
105  // บทที่ 3: คำสั่ง /agenttips
106  // ==========================================================================
107  on('command.run', { command: 'agenttips' }, async ($, e) => {
108    const [sub = '', ...rest] = e.args.trim().split(/\s+/).filter(Boolean)
109    const arg = rest.join(' ')
110    switch (sub) {
111      case '':
112      case 'today':
113        return { text: `📅 ทิปวันนี้\n${format(tipOfDay(await $.clock.now()))}` }
114      case 'random':
115        return { text: format(TIPS[Math.floor(Math.random() * TIPS.length)] ?? TIPS[0]!) }
116      case 'all':
117        return { text: CATEGORIES.map(c => `${c}\n${TIPS.filter(t => t.category === c).map(t => `  ${t.id.padEnd(12)} ${t.title}`).join('\n')}`).join('\n') }
118      case 'cat': {
119        const list = TIPS.filter(t => t.category === arg)
120        return { text: list.length ? list.map(format).join('\n\n') : `หมวดที่มี: ${CATEGORIES.join(', ')}` }
121      }
122      case 'search': {
123        const q = arg.toLowerCase()
124        const list = TIPS.filter(t => `${t.title} ${t.body} ${t.id}`.toLowerCase().includes(q))
125        return { text: list.length ? list.map(format).join('\n\n') : `ไม่พบทิปที่มีคำว่า "${arg}"` }
126      }
127      case 'fav': {
128        if (!arg) return { text: favorites.length ? ['⭐ ทิปโปรด', ...favorites.map(id => TIPS.find(t => t.id === id)).filter((t): t is Tip => Boolean(t)).map(format)].join('\n\n') : 'ยังไม่มีทิปโปรด /agenttips fav <id> (ดู id ด้วย /agenttips all)' }
129        if (!TIPS.some(t => t.id === arg)) return { text: `ไม่มีทิป id "${arg}"` }
130        favorites = favorites.includes(arg) ? favorites.filter(f => f !== arg) : [...favorites, arg]
131        await $.store.set('favorites', favorites)
132        return { text: favorites.includes(arg) ? `⭐ เพิ่ม "${arg}" แล้ว` : `☆ เอา "${arg}" ออกแล้ว` }
133      }
134      case 'template': {
135        const t = TEMPLATES[arg]
136        if (!t) return { text: ['📝 Template', ...Object.entries(TEMPLATES).map(([k, v]) => `  ${k.padEnd(9)} ${v.name}`), '', 'เลือกด้วย /agenttips template bug'].join('\n') }
137        // เติมลงช่องพิมพ์ (ไม่ส่งเอง) ให้ผู้ใช้แก้ส่วนที่อยู่ใน {} ก่อน
138        const filled = await $.prompt.fill({ text: t.text, mode: 'replace' }).catch(() => ({ isFilled: false }))
139        return { text: filled.isFilled ?`📝 เติม template "${t.name}" ลงช่องพิมพ์แล้ว แก้ {ช่องว่าง} แล้วกด Enter` : `📝 ${t.name} (copy ไปใช้ได้)\n\n${t.text}` }
140      }
141      default:
142        return { text: HELP }
143    }
144  })
145}
146
147/**
148 * ========================================================================
149 * การบ้าน / ต่อยอด
150 * ========================================================================
151 * 1. เพิ่ม template ของทีม เช่น รูปแบบ PR, checklist ก่อน deploy
152 * 2. ดัก prompt.submit: ถ้า prompt สั้นเกิน 5 คำ แนะนำทิป "บอกให้ชัด"
153 * 3. ให้ Claude ปรับ prompt ของผู้ใช้ให้ชัดขึ้นก่อนส่ง ด้วย $.model.complete
154 */
155