KIRO_TERMINAL_AWAKE ทำงานอย่างไร

บทความ เริ่มต้นใช้งาน บอกวิธีติดตั้งและใช้งาน บทความนี้เจาะลึกว่าข้างในทำงานอย่างไร — ทำไมถึงใช้ launchd แทน daemon ที่รันค้าง ทำไม AppleScript ที่วางข้อความถึงเขียนแบบเฉพาะเจาะจง และแอปนี้ทำอะไรบ้างเพื่อไม่ให้ผูกติดกับเครื่องใดเครื่องหนึ่ง
ทำไมยิงครั้งเดียวแล้วเลิก ไม่ใช่ daemon ที่รันค้าง
เมื่อกด “ตั้ง AWAKE” แอปเขียน LaunchAgent plist ใหม่ที่มี StartCalendarInterval ตรงชั่วโมง/นาทีที่เลือก และ RunAtLoad: false — บอก launchd ให้ยิงแค่ครั้งเดียวตรงเวลานั้น ไม่ใช่ตอนเปิดเครื่อง จากนั้นโหลดเข้าระบบด้วย launchctl bootstrap gui/<uid> <plist>
จุดที่ตั้งใจคือ helper script ที่ launchd เรียกจะ unload ตัวเองทันทีหลังส่งข้อความสำเร็จ (launchctl bootout + ลบไฟล์ plist) — ถ้าไม่ทำแบบนี้ StartCalendarInterval แบบระบุ Hour/Minute จะยิงซ้ำทุกวันตรงเวลานั้นตลอดไป ซึ่งไม่ใช่พฤติกรรมที่ต้องการ (ตั้งครั้งเดียว ใช้ครั้งเดียว ไม่ใช่นาฬิกาปลุกรายวัน) ก่อนตั้งเวลาใหม่ทุกครั้ง แอปจะเรียก stopLoadedJobs() เพื่อเคลียร์ job เก่าที่อาจค้างอยู่ก่อนเสมอ
ข้อสำคัญ: การ unload ตัวเองเกิดขึ้นเฉพาะเส้นทางที่สำเร็จ — ในสคริปต์ cleanup_job ถูกเรียกที่บรรทัดสุดท้ายเท่านั้น ส่วนเส้นทาง error จบด้วย exit 1 โดยไม่เรียก cleanup และไม่มี trap ... EXIT มารับ ผลคือถ้ารอบนั้นส่งไม่สำเร็จ plist จะยังอยู่ และเพราะ StartCalendarInterval ระบุแค่ Hour/Minute ไม่ได้ระบุ Day launchd จะยิงซ้ำเวลาเดิมของวันถัดไปไปเรื่อยๆ จนกว่าจะสำเร็จหรือผู้ใช้กดยกเลิก — ตีความเป็น retry อัตโนมัติได้ แต่เป็นพฤติกรรมที่ผู้ใช้ควรรู้ เพราะกรณีล้มเหลวที่พบบ่อยที่สุด (ยังไม่ได้ให้สิทธิ์ Accessibility) มักเกิดตอนไม่มีใครอยู่เห็น notification พอดี
เส้นทางของการส่งข้อความหนึ่งครั้ง
launchd (ตรงเวลาที่ตั้งไว้)
│
▼
awake_inject_kiro.sh
│ open -a Kiro, รอ 1.5 วินาที
▼
osascript (AppleScript ฝังในสคริปต์)
│ เก็บ clipboard เดิม → set clipboard เป็นข้อความ
│ activate Kiro → key code 9 (Cmd+V) → key code 36 (Return)
│ คืนค่า clipboard เดิมกลับ (สำเร็จหรือ error ก็คืนเสมอ)
▼
cleanup_job — bootout ตัวเอง + ลบ plist
การวางข้อความใช้ physical key code (key code 9 = ตำแหน่งปุ่ม V, key code 36 = ตำแหน่งปุ่ม Return) แทน keystroke "v" ที่ตีความตามตัวอักษรผ่าน input source ปัจจุบัน — ถ้าเครื่องเปลี่ยน input source ไปเป็นภาษาที่ไม่ใช่ภาษาอังกฤษ (เช่นสลับไปพิมพ์ไทยแล้วลืมสลับกลับ) keystroke "v" อาจ resolve ผิดตัวอักษรหรือพิมพ์อะไรแปลกๆ แทนที่จะกด Cmd+V จริง ส่วน physical key code ทำงานเหมือนกันเสมอไม่ว่า input source ที่ตั้งอยู่จะเป็นภาษาไหน
จุดที่ตั้งใจอีกอย่างคือ ไม่ส่ง Cmd+L ก่อน ทั้งที่ Kiro มีคำสั่ง kiroAgent.focusChatInput ผูกกับปุ่มนั้น — เพราะ Cmd+L จะพาโฟกัสไปที่ช่องแชทของ Kiro แทนที่จะเป็น terminal panel ซึ่งขัดกับจุดประสงค์จริงของเครื่องมือนี้ (สั่งงานต่อใน terminal ที่ agent กำลังทำงานอยู่ ไม่ใช่เปิดแชทใหม่) การออกแบบนี้จึงวางข้อความลง panel ที่ focus อยู่ ณ ตอนนั้นตรงๆ — ผู้ใช้ต้องเปิดและ focus ไว้ที่ terminal panel เองก่อนถึงเวลาที่ตั้งไว้
Timeout 8 วินาทีที่ตั้งใจ กับการแยกสาเหตุ error สองแบบ
AppleScript ทั้งก้อนอยู่ใน with timeout of 8 seconds อย่างชัดเจน — ถ้า System Events หรือ Kiro ไม่ตอบภายใน 8 วินาที จะ error ทันทีแทนที่จะปล่อยให้ค้างไปตาม default ของ macOS ที่ประมาณ 60-120 วินาทีต่อ AppleEvent ที่ไม่มีใครตอบ ทำให้ log บอกได้ชัดว่าเกิดอะไรขึ้นโดยไม่ต้องรอค้างนาน
สคริปต์แยกสาเหตุ error ออกเป็นสองแบบจาก error code ที่ osascript คืนมา:
-1712— timeout เกิดเพราะไม่มีใครอยู่กด Allow ตอน macOS ขอสิทธิ์ครั้งแรก (TCC prompt ต้องมีคนตอบ ไม่ตอบเองอัตโนมัติได้)1002หรือข้อความnot allowed to send keystrokes— ยังไม่ได้ให้สิทธิ์ Accessibility เลย
ทั้งสองกรณี log จะเขียน hint บอกตรงๆ ว่าต้องไปเปิดที่ System Settings → Privacy & Security → Accessibility ให้ osascript แล้วส่ง notification เตือนด้วย เพื่อให้ผู้ใช้เห็นทันทีว่าทำไมข้อความไม่ถูกส่ง แทนที่จะเงียบและดูเหมือนไม่มีอะไรเกิดขึ้น
ทำไมไม่ผูกกับเครื่องไหนเครื่องหนึ่ง
homeURL, appSupportURL, และ path ที่เกี่ยวข้องทั้งหมด resolve จาก FileManager.default.homeDirectoryForCurrentUser ที่ runtime เสมอ ไม่มี username หรือ absolute path เฉพาะเครื่องฝังอยู่ในซอร์สโค้ดเลย — helper ที่ build ได้ตัวเดียวใช้ได้กับ Mac เครื่องไหนก็ได้ทันทีหลัง clone
การ build ใช้ codesign --sign - (ad-hoc signing) ไม่ผูกกับ developer certificate ของใครเลย และ build สร้างเป็น universal binary (lipo รวม arm64 + x86_64) ในขั้นตอนเดียว ไม่ต้องเลือกสถาปัตยกรรมเอง
ทำไมเรื่องนี้ถึงสำคัญ
เครื่องมือ agent ส่วนใหญ่แก้ปัญหา “agent ทำอะไรได้บ้าง” แต่ปัญหาจริงบางทีเป็นเรื่องง่ายกว่านั้นมาก: agent ทำงานได้ปกติทุกอย่าง เพียงแต่ไม่มีใครไปกดปุ่มต่อให้ตอนที่ควรกด KIRO_TERMINAL_AWAKE ไม่ได้พยายามฉลาดขึ้นหรือเข้าใจบริบทงานเลยแม้แต่น้อย — มันแค่รับประกันว่าข้อความหนึ่งบรรทัดจะถูกส่งตรงเวลา แม่นยำ และได้แค่ครั้งเดียวตามที่ตั้งไว้ ซึ่งเพียงพอแล้วสำหรับปัญหาที่แก้อยู่
ความคิดเห็น
กำลังโหลดความคิดเห็น...