claude-threads 1.25.0 → 1.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.25.1] - 2026-08-20
9
+
10
+ ### Fixed
11
+ - **Keep-alive inhibitors no longer outlive the bot process.** (#480, thanks @Jadefalkner) The sleep-prevention child processes are now tied to the bot's lifetime at the OS level: on Linux `systemd-inhibit` runs `cat` on a pipe held by the bot (EOF on bot death releases the lock, even after SIGKILL), on macOS `caffeinate -w <pid>` watches the bot pid natively, and the xdg-screensaver/PowerShell fallbacks poll the parent pid. Previously a hard death of the bot (SIGKILL, crashed test runner) orphaned `systemd-inhibit sleep infinity` processes to init, permanently blocking system sleep/hibernate until they were killed by hand.
12
+
8
13
  ## [1.25.0] - 2026-08-19
9
14
 
10
15
  ### Added
package/dist/index.js CHANGED
@@ -58788,7 +58788,48 @@ import { existsSync as existsSync13 } from "fs";
58788
58788
  init_logger();
58789
58789
  import { spawn as spawn2 } from "child_process";
58790
58790
  var log17 = createLogger("keepalive");
58791
-
58791
+ function keepAliveSpawnSpec(platform, parentPid) {
58792
+ switch (platform) {
58793
+ case "darwin":
58794
+ return {
58795
+ command: "caffeinate",
58796
+ args: ["-s", "-i", "-w", String(parentPid)],
58797
+ stdio: "ignore"
58798
+ };
58799
+ case "linux":
58800
+ return {
58801
+ command: "systemd-inhibit",
58802
+ args: [
58803
+ "--what=sleep:idle:handle-lid-switch",
58804
+ "--why=Claude Code session active",
58805
+ "--mode=block",
58806
+ "cat"
58807
+ ],
58808
+ stdio: ["pipe", "ignore", "ignore"]
58809
+ };
58810
+ default:
58811
+ return null;
58812
+ }
58813
+ }
58814
+ function linuxFallbackScript(parentPid) {
58815
+ return `while kill -0 ${parentPid} 2>/dev/null; do xdg-screensaver reset 2>/dev/null || true; sleep 60; done`;
58816
+ }
58817
+ function windowsScript(parentPid) {
58818
+ return `
58819
+ Add-Type -TypeDefinition @"
58820
+ using System;
58821
+ using System.Runtime.InteropServices;
58822
+ public class PowerState {
58823
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
58824
+ public static extern uint SetThreadExecutionState(uint esFlags);
58825
+ }
58826
+ "@
58827
+ # ES_CONTINUOUS | ES_SYSTEM_REQUIRED
58828
+ [PowerState]::SetThreadExecutionState(0x80000001) | Out-Null
58829
+ # Keep running until killed or the parent process exits
58830
+ while (Get-Process -Id ${parentPid} -ErrorAction SilentlyContinue) { Start-Sleep -Seconds 60 }
58831
+ `;
58832
+ }
58792
58833
  class KeepAliveManager {
58793
58834
  activeSessionCount = 0;
58794
58835
  keepAliveProcess = null;
@@ -58865,8 +58906,11 @@ class KeepAliveManager {
58865
58906
  }
58866
58907
  startMacOSKeepAlive() {
58867
58908
  try {
58868
- this.keepAliveProcess = spawn2("caffeinate", ["-s", "-i"], {
58869
- stdio: "ignore",
58909
+ const spec = keepAliveSpawnSpec("darwin", process.pid);
58910
+ if (!spec)
58911
+ return;
58912
+ this.keepAliveProcess = spawn2(spec.command, spec.args, {
58913
+ stdio: spec.stdio,
58870
58914
  detached: false
58871
58915
  });
58872
58916
  this.keepAliveProcess.on("error", (err) => {
@@ -58886,14 +58930,11 @@ class KeepAliveManager {
58886
58930
  }
58887
58931
  startLinuxKeepAlive() {
58888
58932
  try {
58889
- this.keepAliveProcess = spawn2("systemd-inhibit", [
58890
- "--what=sleep:idle:handle-lid-switch",
58891
- "--why=Claude Code session active",
58892
- "--mode=block",
58893
- "sleep",
58894
- "infinity"
58895
- ], {
58896
- stdio: "ignore",
58933
+ const spec = keepAliveSpawnSpec("linux", process.pid);
58934
+ if (!spec)
58935
+ return;
58936
+ this.keepAliveProcess = spawn2(spec.command, spec.args, {
58937
+ stdio: spec.stdio,
58897
58938
  detached: false
58898
58939
  });
58899
58940
  this.keepAliveProcess.on("error", (err) => {
@@ -58915,10 +58956,7 @@ class KeepAliveManager {
58915
58956
  }
58916
58957
  startLinuxKeepAliveFallback() {
58917
58958
  try {
58918
- this.keepAliveProcess = spawn2("bash", [
58919
- "-c",
58920
- `while true; do xdg-screensaver reset 2>/dev/null || true; sleep 60; done`
58921
- ], {
58959
+ this.keepAliveProcess = spawn2("bash", ["-c", linuxFallbackScript(process.pid)], {
58922
58960
  stdio: "ignore",
58923
58961
  detached: false
58924
58962
  });
@@ -58936,20 +58974,7 @@ class KeepAliveManager {
58936
58974
  }
58937
58975
  startWindowsKeepAlive() {
58938
58976
  try {
58939
- const script = `
58940
- Add-Type -TypeDefinition @"
58941
- using System;
58942
- using System.Runtime.InteropServices;
58943
- public class PowerState {
58944
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
58945
- public static extern uint SetThreadExecutionState(uint esFlags);
58946
- }
58947
- "@
58948
- # ES_CONTINUOUS | ES_SYSTEM_REQUIRED
58949
- [PowerState]::SetThreadExecutionState(0x80000001) | Out-Null
58950
- # Keep running until killed
58951
- while ($true) { Start-Sleep -Seconds 60 }
58952
- `;
58977
+ const script = windowsScript(process.pid);
58953
58978
  this.keepAliveProcess = spawn2("powershell", ["-NoProfile", "-Command", script], {
58954
58979
  stdio: "ignore",
58955
58980
  detached: false,
@@ -55395,7 +55395,48 @@ function formatReleaseNotes(notes, formatter) {
55395
55395
  // src/utils/keep-alive.ts
55396
55396
  import { spawn } from "child_process";
55397
55397
  var log5 = createLogger("keepalive");
55398
-
55398
+ function keepAliveSpawnSpec(platform, parentPid) {
55399
+ switch (platform) {
55400
+ case "darwin":
55401
+ return {
55402
+ command: "caffeinate",
55403
+ args: ["-s", "-i", "-w", String(parentPid)],
55404
+ stdio: "ignore"
55405
+ };
55406
+ case "linux":
55407
+ return {
55408
+ command: "systemd-inhibit",
55409
+ args: [
55410
+ "--what=sleep:idle:handle-lid-switch",
55411
+ "--why=Claude Code session active",
55412
+ "--mode=block",
55413
+ "cat"
55414
+ ],
55415
+ stdio: ["pipe", "ignore", "ignore"]
55416
+ };
55417
+ default:
55418
+ return null;
55419
+ }
55420
+ }
55421
+ function linuxFallbackScript(parentPid) {
55422
+ return `while kill -0 ${parentPid} 2>/dev/null; do xdg-screensaver reset 2>/dev/null || true; sleep 60; done`;
55423
+ }
55424
+ function windowsScript(parentPid) {
55425
+ return `
55426
+ Add-Type -TypeDefinition @"
55427
+ using System;
55428
+ using System.Runtime.InteropServices;
55429
+ public class PowerState {
55430
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
55431
+ public static extern uint SetThreadExecutionState(uint esFlags);
55432
+ }
55433
+ "@
55434
+ # ES_CONTINUOUS | ES_SYSTEM_REQUIRED
55435
+ [PowerState]::SetThreadExecutionState(0x80000001) | Out-Null
55436
+ # Keep running until killed or the parent process exits
55437
+ while (Get-Process -Id ${parentPid} -ErrorAction SilentlyContinue) { Start-Sleep -Seconds 60 }
55438
+ `;
55439
+ }
55399
55440
  class KeepAliveManager {
55400
55441
  activeSessionCount = 0;
55401
55442
  keepAliveProcess = null;
@@ -55472,8 +55513,11 @@ class KeepAliveManager {
55472
55513
  }
55473
55514
  startMacOSKeepAlive() {
55474
55515
  try {
55475
- this.keepAliveProcess = spawn("caffeinate", ["-s", "-i"], {
55476
- stdio: "ignore",
55516
+ const spec = keepAliveSpawnSpec("darwin", process.pid);
55517
+ if (!spec)
55518
+ return;
55519
+ this.keepAliveProcess = spawn(spec.command, spec.args, {
55520
+ stdio: spec.stdio,
55477
55521
  detached: false
55478
55522
  });
55479
55523
  this.keepAliveProcess.on("error", (err) => {
@@ -55493,14 +55537,11 @@ class KeepAliveManager {
55493
55537
  }
55494
55538
  startLinuxKeepAlive() {
55495
55539
  try {
55496
- this.keepAliveProcess = spawn("systemd-inhibit", [
55497
- "--what=sleep:idle:handle-lid-switch",
55498
- "--why=Claude Code session active",
55499
- "--mode=block",
55500
- "sleep",
55501
- "infinity"
55502
- ], {
55503
- stdio: "ignore",
55540
+ const spec = keepAliveSpawnSpec("linux", process.pid);
55541
+ if (!spec)
55542
+ return;
55543
+ this.keepAliveProcess = spawn(spec.command, spec.args, {
55544
+ stdio: spec.stdio,
55504
55545
  detached: false
55505
55546
  });
55506
55547
  this.keepAliveProcess.on("error", (err) => {
@@ -55522,10 +55563,7 @@ class KeepAliveManager {
55522
55563
  }
55523
55564
  startLinuxKeepAliveFallback() {
55524
55565
  try {
55525
- this.keepAliveProcess = spawn("bash", [
55526
- "-c",
55527
- `while true; do xdg-screensaver reset 2>/dev/null || true; sleep 60; done`
55528
- ], {
55566
+ this.keepAliveProcess = spawn("bash", ["-c", linuxFallbackScript(process.pid)], {
55529
55567
  stdio: "ignore",
55530
55568
  detached: false
55531
55569
  });
@@ -55543,20 +55581,7 @@ class KeepAliveManager {
55543
55581
  }
55544
55582
  startWindowsKeepAlive() {
55545
55583
  try {
55546
- const script = `
55547
- Add-Type -TypeDefinition @"
55548
- using System;
55549
- using System.Runtime.InteropServices;
55550
- public class PowerState {
55551
- [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
55552
- public static extern uint SetThreadExecutionState(uint esFlags);
55553
- }
55554
- "@
55555
- # ES_CONTINUOUS | ES_SYSTEM_REQUIRED
55556
- [PowerState]::SetThreadExecutionState(0x80000001) | Out-Null
55557
- # Keep running until killed
55558
- while ($true) { Start-Sleep -Seconds 60 }
55559
- `;
55584
+ const script = windowsScript(process.pid);
55560
55585
  this.keepAliveProcess = spawn("powershell", ["-NoProfile", "-Command", script], {
55561
55586
  stdio: "ignore",
55562
55587
  detached: false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-threads",
3
- "version": "1.25.0",
3
+ "version": "1.25.1",
4
4
  "description": "Run Claude Code from Slack or Mattermost. Sessions stream live into threads where your whole team can watch and steer.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",