LidRun CLI: giữ Mac không ngủ ngay từ terminal

Công cụ dòng lệnh lidrun đưa toàn bộ khả năng giữ Mac không ngủ của LidRun vào thẳng terminal của bạn: lidrun status cho biết trạng thái hiện tại, lidrun start và stop bật/tắt tính năng này, còn lidrun -- <command> bọc một lệnh duy nhất trong một phiên giữ-thức kéo dài đúng bằng thời gian lệnh đó chạy. Đây là thứ gần với caffeinate nhất mà LidRun có, và bài này sẽ đi qua toàn bộ các lệnh thật sự tồn tại, cách cài đặt, hai cách đưa nó vào script — và nói thẳng — phần nào của một phiên lidrun được các lớp bảo vệ pin và nhiệt độ của LidRun che chắn, phần nào chạy trần trụi giống hệt caffeinate.
lidrun CLI thực chất là gì
lidrun không phải một chương trình riêng biệt với logic của chính nó — nó là một script wrapper nhỏ, được cài vào ~/.local/bin/lidrun hoặc /usr/local/bin/lidrun, chạy chính binary LidRun.app mà bạn đã có sẵn, chỉ khác là được gọi bằng cờ --cli thay vì double-click. Nếu sau này bạn chuyển app từ Downloads sang Applications, wrapper vẫn không hỏng, vì nó được tạo ra để trỏ đến đúng vị trí app bundle thực sự nằm tại thời điểm cài đặt.


Bên dưới, nó chia thành hai hành vi thật sự khác nhau, và lẫn lộn hai thứ này là cách dễ nhất để hiểu sai một lệnh đang làm gì. lidrun -- <command> tự thân độc lập: nó mở một power assertion ngắn hạn riêng cho tiến trình con và giải phóng nó ngay khi tiến trình đó kết thúc, không cần app LidRun đang mở. Mọi lệnh khác — status, start, stop, autowatch, watch, unwatch, patterns, timer, notify — đều dựa vào daemon: nó mở một kết nối Unix socket cục bộ tới app đang chạy và yêu cầu app đổi trạng thái. Nếu app chưa mở, các lệnh đó sẽ báo lỗi thẳng thừng, chứ không âm thầm không làm gì cả.
Sự khác biệt này quan trọng cho phần sau của bài, khi nói đến việc "được kiểm soát an toàn" thực sự có nghĩa là gì — nó không giống nhau ở mọi lệnh, và giả vờ như thể giống nhau là kiểu tuyên bố chỉ đứng vững cho tới khi có ai đó để Mac cạn pin trong balo.
Cách miễn phí: caffeinate và pmset
Trước khi tìm đến bất kỳ công cụ nào, macOS đã sẵn có hai cách làm việc này ngay từ terminal, và cần nói thẳng là — chúng thực sự có năng lực, không phải giải pháp tạm bợ. caffeinate -i your-command, hoặc chạy caffeinate -i một mình trong một tab dự phòng, giữ một idle-sleep assertion suốt thời gian tiện ích đó chạy. Không cần cài đặt, không cần tin tưởng thêm gì, và nó đã là một phần của macOS hơn một thập kỷ rồi — rất nhiều người từng làm việc này đã quen tay với nó.


Riêng với trường hợp đóng nắp máy, pmset disablesleep 1 báo cho macOS bỏ qua mọi tác nhân gây ngủ trên toàn hệ thống, kể cả công tắc nắp máy — chính là cơ chế mà Closed-Lid mode của LidRun dùng bên dưới, đó cũng là lý do LidRun luôn cẩn thận ghép một disablesleep 1 với một disablesleep 0 tương ứng khi phiên clamshell kết thúc: lúc dừng, lúc thoát, và lại một lần nữa khi khởi động phòng trường hợp lần chạy trước chưa dọn sạch. Chạy tay, đây đúng là một dòng lệnh gọn cho các bản build đóng nắp mà không cần cài gì cả.
Với một lệnh đơn lẻ mà bạn đang ngồi canh trước máy, caffeinate -i npm run build thành thật mà nói cũng tốt ngang bất cứ thứ gì ở đây, kể cả LidRun.
Hướng dẫn liên quanChạy một lệnh dài, xong thì để Mac ngủ lạiGiới hạn của caffeinate và pmset
Khoảng trống lộ ra khi không còn ai canh phiên làm việc đó nữa. Cả hai công cụ đều không biết phần trăm pin còn lại hay Mac đang nóng đến mức nào — chúng chỉ giữ đúng cái được yêu cầu giữ, trong đúng khoảng thời gian được yêu cầu, chấm hết.
disablesleep là phiên bản rủi ro sắc hơn, vì đây là một thiết lập toàn hệ thống, không giới hạn trong một tab terminal. Nếu script chạy pmset disablesleep 1 bị crash, bị kill trước khi kịp chạy tới lệnh 0 tương ứng, hoặc phiên SSH rớt giữa chừng, Mac sẽ bị kẹt ở trạng thái từ chối ngủ — nắp đóng, không ai theo dõi, dù đang nóng đến đâu — cho đến khi có người nhận ra và tự tay dọn lại. Chính kiểu lỗi này là lý do LidRun luôn ghép disablesleep một cách phòng thủ ở ba nơi riêng biệt thay vì chỉ một.
Rủi ro phía caffeinate thì âm thầm hơn nhưng không kém phần thật: một tiến trình caffeinate -i chạy nền từ ba lần deploy trước, vẫn còn sống trong một tab terminal chẳng ai đóng, khiến pin laptop cứ thế cạn dần trong balo mà không ai kiểm tra. Không công cụ nào sai khi hoạt động theo kiểu này — caffeinate làm đúng một việc, gọn gàng, theo đúng thiết kế. Chỉ là nó không phải một ngưỡng chặn pin hay nhiệt độ, và nó cũng chưa từng có ý định trở thành như vậy.
Cài đặt lidrun CLI
CLI không phải một bản tải riêng. Mở LidRun, vào Settings, rồi Command Line, và bấm Install lidrun CLI… — thao tác này ghi ra script wrapper đã mô tả ở trên và cho bạn chọn phạm vi cài đặt.
Cài vào ~/.local/bin/lidrun không cần mật khẩu admin chút nào; bạn có thể cần thêm ~/.local/bin vào PATH một lần duy nhất nếu nó chưa có sẵn — điều này chính hộp thoại cài đặt cũng nói rõ. Cài vào /usr/local/bin/lidrun sẽ đưa lidrun vào PATH cho mọi shell mà không cần bước thêm đó, nhưng cần một lần nhập mật khẩu admin, vì ghi vào đó cần quyền root.
lidrun --version xác nhận build nào đang thực sự chạy — nó đọc đúng số phiên bản của chính app, nên CLI không thể âm thầm lệch pha với giao diện đồ họa — còn lidrun help in ra toàn bộ danh sách lệnh mà không cần rời khỏi terminal.
Toàn bộ lệnh mà lidrun CLI thực sự có
lidrun status là lệnh đáng chạy đầu tiên và chạy nhiều nhất. Ở trạng thái nguội, nó in ra Mode: Awake Off, Assertion: inactive, Clamshell: off; chạy lại sau lidrun start thì Mode sẽ hiện Awake On với Assertion active — nó còn thêm dòng Battery và Thermal bất cứ khi nào Mac có pin và có trạng thái nhiệt đáng hiển thị. lidrun start và lidrun stop là cặp bật/tắt tường minh, còn lidrun -- <command> là wrapper, giữ trạng thái không ngủ đúng bằng vòng đời của một tiến trình đó và trả lại đúng exit code thật của nó khi xong — kiểm tra $? sau đó là bạn đang đọc kết quả của chính lệnh được bọc, không phải của lidrun.


Một điều cần đính chính rõ ràng: không hề có lidrun on, lidrun off, hay lidrun toggle trần trụi. Những từ đó chỉ tồn tại như tham số của autowatch — lidrun autowatch on, off, hoặc toggle bật/tắt Auto Mode, chế độ chỉ giữ Mac không ngủ khi một tên tiến trình đang được theo dõi thực sự đang chạy, và tự buông ra ngay khi tiến trình đó không còn chạy nữa. lidrun watch <pattern> và lidrun unwatch <pattern> thêm hoặc bỏ một tên khỏi danh sách theo dõi đó, còn lidrun patterns liệt kê những gì đang có trong danh sách.
Còn hai lệnh nữa để đầy đủ: lidrun timer 3600 giữ Mac không ngủ trong một số giây cố định rồi tự giải phóng khi hết giờ, và lidrun notify "Build done" "exit 0" bắn ra một thông báo cục bộ và push qua đúng kênh mà các cảnh báo của app vẫn dùng — một dòng kết hợp lý ở cuối một script được bọc.
Hai kiểu dùng trong script, và một cái bẫy về dấu ngoặc kép
Với một script trọn vẹn gồm nhiều bước, hãy đóng khung nó: lidrun start ở đầu, lidrun stop ở cuối, mọi thứ ở giữa chạy y hệt như khi không có LidRun tham gia. Vì cả hai đều là lệnh daemon trả về ngay lập tức, không quan trọng script đang chạy ở terminal foreground hay chạy headless qua SSH — app mới là nơi giữ trạng thái thật.


Rủi ro thật sự của cách đóng khung này giống hệt caffeinate và disablesleep: nếu một bước trước đó thất bại và script thoát trước khi chạy tới lidrun stop, Mac sẽ bị kẹt dưới một trạng thái giữ-thức vĩnh viễn mà chẳng ai nhớ để dọn. Cách khắc phục chuẩn là một dòng trap ở đầu script — trap 'lidrun stop' EXIT — chạy lidrun stop bất kể script thoát kiểu gì, kể cả khi crash.
Với một bước đơn lẻ, dạng wrapper né hẳn nhu cầu dùng trap: lidrun -- ./build.sh giữ assertion đúng bằng vòng đời của một tiến trình đó và giải phóng ngay khi nó kết thúc, dù thành công hay thất bại — cùng hình dạng với caffeinate ./build.sh.
Một chi tiết nên biết trước khi nó khiến bạn bất ngờ: lidrun -- chạy các tham số được nối lại qua một login shell thật sự, nên các toán tử shell nằm trong một chuỗi có dấu ngoặc kép sẽ hoạt động đúng như mong đợi. lidrun -- "npm run build && npm test" giữ một phiên không-ngủ xuyên suốt cả hai bước. Bỏ dấu ngoặc kép và viết lidrun -- npm run build && npm test thay vào đó, shell bên ngoài của bạn sẽ parse && trước — chỉ npm run build được truyền cho lidrun, còn npm test chạy sau đó, không được bọc, một khi lidrun đã thoát rồi. Vì chạy qua login shell, các mục PATH từ Homebrew, pyenv, hay nvm cũng được phân giải giống hệt như trong một terminal tương tác, nhờ đó né được một cái bẫy thường gặp với các công cụ shell-out trực tiếp.
Các lớp bảo vệ an toàn của LidRun thực sự bao phủ những gì trong một phiên CLI
Đây là phần cần nói cho thật chính xác, vì câu trả lời trung thực phụ thuộc vào bạn đã dùng lệnh nào, chứ không phải "CLI" như một khối thống nhất. Lớp bảo vệ pin và nhiệt của LidRun nằm trong chính cơ chế theo dõi trạng thái của app đang chạy, chứ không nằm trong bản thân một power assertion trần trụi — nên một phiên lidrun được bảo vệ đến đâu phụ thuộc vào việc app có đang theo dõi đúng assertion đó hay không.
lidrun start, cùng với timer và autowatch, giữ một assertion mà app đang chủ động theo dõi. Theo mặc định, nếu pin tụt xuống dưới 20% trong khi một trong số này đang hoạt động, app sẽ tự giải phóng — giống hệt việc lidrun stop sẽ làm — để Mac có thể ngủ bình thường trước khi mọi thứ trở nên gấp gáp. Đó chính là ngưỡng chặn mềm mà nút Always On trên menu bar cũng có, vì bên dưới đều là cùng một trạng thái được theo dõi.
lidrun -- <command> không có ngưỡng chặn mềm đó, vì assertion của nó nằm trong chính tiến trình ngắn hạn của CLI, nằm ngoài mọi thứ app đang theo dõi — không có trạng thái nào để app giải phóng sớm cả. Nếu app LidRun tình cờ đang mở cùng lúc, điều khá thường gặp vì đây là một tiện ích menu bar, thì ngưỡng chặn khẩn cấp cứng của nó vẫn áp dụng trên toàn hệ thống: mặc định gần 4% pin (có thể chỉnh trong khoảng 4% đến 8%), LidRun gọi trực tiếp pmset sleepnow, buộc toàn bộ Mac phải ngủ bất kể ai đang giữ assertion, kể cả assertion của chính lệnh được bọc. Nếu app hoàn toàn không chạy, sẽ không có gì can thiệp, và lidrun -- <command> hoạt động y hệt một phiên caffeinate -i <command> trần trụi: không ngưỡng pin, không kiểm tra nhiệt, chỉ đơn thuần ngăn ngủ-do-rảnh trong suốt thời gian tiến trình chạy.
Trên thực tế, đó là một đánh đổi ổn với một lần build hay test mà bạn đang ngồi canh trước máy — chính bạn là lớp kiểm tra an toàn ở đó. Còn với một lần chạy qua đêm thực sự không ai canh, nơi ngưỡng pin cần có giá trị xuyên suốt, thì lidrun start đi kèm lidrun stop, hoặc Auto Mode, với app đang mở, mới là phiên bản được theo dõi liên tục, chứ không chỉ được chặn lại khi mọi thứ đã tới mức nguy cấp.
CI trên laptop, các lần chạy không ai canh, và vị trí của CLI bên cạnh mọi công cụ khác
Lý do thực sự để dùng đến bất kỳ thứ gì trong bài này là một self-hosted runner hoặc một job chạy đêm trên một chiếc Mac đang thật sự nằm trên bàn ở đâu đó — kiểu máy không ai canh, tự ngủ do rảnh, khác hẳn một VM CI đám mây dùng xong là mất. Bọc job bằng lidrun -- ./nightly.sh, hoặc đóng khung nó bằng start và stop, giữ cho Mac không tự ngủ giữa chừng.
CLI chỉ là một mảnh ghép trong một bộ công cụ nhỏ cố tình chồng lấn lên nhau. Auto Mode (lidrun autowatch on) chỉ giữ Mac thức khi một tên tiến trình đang được theo dõi thực sự đang chạy, không có gì phải nhớ để cân bằng lại sau đó. Màn hình Run Command trong giao diện đồ họa làm đúng việc mà lidrun -- <command> làm, chỉ khác là từ một cửa sổ thay vì terminal, và hiển thị exit code cùng thời lượng chạy khi xong — đúng thông tin mà $? cho CLI. Chọn cái nào phần lớn phụ thuộc vào job bắt đầu từ đâu: một script thì tìm đến CLI, một lần chạy tay thì tìm đến giao diện đồ họa.
Nếu toàn bộ workflow chỉ gói gọn trong một nút bật/tắt trên menu bar thay vì một script, Amphetamine, KeepingYouAwake, Lungo, và Caffeine là những công cụ đã được kiểm chứng, thực sự có năng lực, với các quy tắc kích hoạt riêng — mở app, mạng Wi-Fi, khung giờ trong ngày. Chúng không được xây dựng chủ yếu quanh một workflow terminal có thể script hóa và nhận biết exit code như lidrun -- và caffeinate, nên nếu job bắt đầu từ một script hay một Makefile thay vì một cú click, các công cụ CLI mới là lựa chọn hợp hơn cho đúng công việc đó.
Những lưu ý tương tự ở mọi nơi khác vẫn áp dụng ở đây: một mặt phẳng cứng, thoáng khí và nguồn điện lưới là thiết lập đúng cho bất cứ thứ gì chạy lâu, và CLI giúp giảm bớt sự lích kích khi giữ Mac không ngủ ngay từ terminal. Nó không thay thế việc thật sự kiểm tra lại chiếc máy mà bạn đã để chạy không ai canh suốt đêm.
LidRun giữ công việc của bạn chạy tiếp khi đóng nắp, với cơ chế bảo vệ pin và nhiệt tích hợp sẵn.
Đã có LidRun? Đọc hướng dẫn thiết lập →
Mới biết đến LidRun? Xem bảng giá →
Câu hỏi thường gặp
lidrun status, start, stop, autowatch [on|off|toggle], watch <pattern>, unwatch <pattern>, patterns, timer <seconds>, và notify "<title>" ["<body>"], cộng với wrapper lidrun -- <command>, --version, và help. Không hề có lidrun on, off, hay toggle trần trụi — những từ đó chỉ tồn tại như tham số của autowatch.
Không. Nó tự thân độc lập — mở một power assertion ngắn hạn riêng cho lệnh được bọc và giải phóng khi lệnh đó kết thúc, không phụ thuộc vào app. status, start, stop, và các lệnh daemon khác thì thật sự cần app đang mở; chúng nói chuyện với app qua một socket cục bộ và báo lỗi nếu app chưa mở.
Còn tùy lệnh nào. start, timer, và autowatch giữ một assertion mà app chủ động theo dõi, bao gồm cả việc tự dừng ở 20% pin theo mặc định. lidrun -- <command> giữ một assertion riêng mà app không thể giải phóng sớm — nếu app đang mở, ngưỡng chặn khẩn cấp cứng hơn ở gần 4% pin vẫn buộc toàn bộ Mac phải ngủ bất kể ai đang giữ assertion; nếu app không chạy, sẽ không có gì can thiệp và nó hoạt động như một phiên caffeinate trần trụi.
lidrun -- your-command. Nó chờ lệnh đó chạy xong, giải phóng trạng thái giữ-thức, rồi trả lại đúng exit code của chính lệnh đó — $? sau lidrun -- npm test phản ánh kết quả của npm test, không phải của lidrun.
Không, với cách cài mặc định thì không. Settings, Command Line, Install lidrun CLI… có thể ghi vào ~/.local/bin/lidrun mà không cần xin quyền admin — chỉ cần thêm thư mục đó vào PATH một lần. Cài toàn hệ thống vào /usr/local/bin/lidrun sẽ hỏi mật khẩu admin một lần duy nhất, vì ghi vào đó cần quyền root.
Về mặt cơ chế, lidrun -- <command> và caffeinate <command> làm gần như cùng một việc — giữ một idle-sleep assertion trong suốt vòng đời tiến trình. Sự khác biệt nằm ở phần còn lại của CLI: start, stop, timer, và autowatch được gắn liền với cùng một app, cùng ngưỡng pin, trạng thái nhiệt, và thông báo vốn đã hiển thị trên menu bar, nên một script và giao diện đồ họa đang đọc chung một trạng thái, thay vì hai công cụ chẳng liên quan gì đến nhau.
Có — đó chính là trường hợp sử dụng thực tế chính: một self-hosted runner hoặc job chạy đêm trên một chiếc Mac mà nếu không có gì can thiệp sẽ tự ngủ do rảnh. Bọc job đó hoặc đóng khung bằng start và stop, và đối xử với nó như bất kỳ lần chạy không ai canh nào khác — thoáng khí, cắm điện lưới, và dùng lidrun start thay vì wrapper trần trụi nếu ngưỡng pin cần có hiệu lực suốt cả quá trình, chứ không chỉ như phương án cuối cùng.