opentmux 1.5.1 → 1.5.4
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/dist/bin/opentmux.js +69 -35
- package/package.json +1 -1
package/dist/bin/opentmux.js
CHANGED
|
@@ -575,18 +575,14 @@ function spawnPluginUpdater() {
|
|
|
575
575
|
const updaterPath = join3(__dirname2, "../scripts/update-plugins.js");
|
|
576
576
|
if (!existsSync2(updaterPath)) return;
|
|
577
577
|
try {
|
|
578
|
-
const child = spawn(
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
{
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
env: {
|
|
585
|
-
...process.env,
|
|
586
|
-
OPENCODE_TMUX_UPDATE: "1"
|
|
587
|
-
}
|
|
578
|
+
const child = spawn(process.execPath, [updaterPath], {
|
|
579
|
+
stdio: "ignore",
|
|
580
|
+
detached: true,
|
|
581
|
+
env: {
|
|
582
|
+
...process.env,
|
|
583
|
+
OPENCODE_TMUX_UPDATE: "1"
|
|
588
584
|
}
|
|
589
|
-
);
|
|
585
|
+
});
|
|
590
586
|
child.unref();
|
|
591
587
|
} catch (error) {
|
|
592
588
|
}
|
|
@@ -598,13 +594,19 @@ function findOpencodeBin() {
|
|
|
598
594
|
const currentScript = argv[1];
|
|
599
595
|
for (const bin of output) {
|
|
600
596
|
const normalizedBin = bin.trim();
|
|
601
|
-
if (normalizedBin.includes("opentmux") || normalizedBin === currentScript)
|
|
597
|
+
if (normalizedBin.includes("opentmux") || normalizedBin === currentScript)
|
|
598
|
+
continue;
|
|
602
599
|
if (normalizedBin) return normalizedBin;
|
|
603
600
|
}
|
|
604
601
|
} catch (e) {
|
|
605
602
|
}
|
|
606
603
|
const commonPaths = [
|
|
607
|
-
join3(
|
|
604
|
+
join3(
|
|
605
|
+
homedir(),
|
|
606
|
+
".opencode",
|
|
607
|
+
"bin",
|
|
608
|
+
platform2 === "win32" ? "opencode.exe" : "opencode"
|
|
609
|
+
),
|
|
608
610
|
join3(homedir(), "AppData", "Local", "opencode", "bin", "opencode.exe"),
|
|
609
611
|
"/usr/local/bin/opencode",
|
|
610
612
|
"/usr/bin/opencode"
|
|
@@ -639,9 +641,9 @@ async function isOpencodeHealthy(port) {
|
|
|
639
641
|
const timeout = setTimeout(() => controller.abort(), HEALTH_TIMEOUT_MS);
|
|
640
642
|
const healthUrl = `http://127.0.0.1:${port}/health`;
|
|
641
643
|
try {
|
|
642
|
-
const response = await fetch(healthUrl, {
|
|
643
|
-
|
|
644
|
-
);
|
|
644
|
+
const response = await fetch(healthUrl, {
|
|
645
|
+
signal: controller.signal
|
|
646
|
+
}).catch(() => null);
|
|
645
647
|
return response?.ok ?? false;
|
|
646
648
|
} catch {
|
|
647
649
|
return false;
|
|
@@ -731,19 +733,35 @@ async function tryReclaimPort(port, tmuxPanePids) {
|
|
|
731
733
|
);
|
|
732
734
|
if (command && command.includes("opencode")) {
|
|
733
735
|
if (inTmux) {
|
|
734
|
-
log2(
|
|
736
|
+
log2(
|
|
737
|
+
"Port owned by tmux process, skipping:",
|
|
738
|
+
port.toString(),
|
|
739
|
+
pid.toString()
|
|
740
|
+
);
|
|
735
741
|
continue;
|
|
736
742
|
}
|
|
737
743
|
if (hasTtyPeers) {
|
|
738
|
-
log2(
|
|
744
|
+
log2(
|
|
745
|
+
"Port owned by active tty process, skipping:",
|
|
746
|
+
port.toString(),
|
|
747
|
+
pid.toString()
|
|
748
|
+
);
|
|
739
749
|
continue;
|
|
740
750
|
}
|
|
741
751
|
if (isForegroundProcess(pid)) {
|
|
742
|
-
log2(
|
|
752
|
+
log2(
|
|
753
|
+
"Port owned by potentially busy foreground process, skipping:",
|
|
754
|
+
port.toString(),
|
|
755
|
+
pid.toString()
|
|
756
|
+
);
|
|
743
757
|
continue;
|
|
744
758
|
}
|
|
745
759
|
}
|
|
746
|
-
log2(
|
|
760
|
+
log2(
|
|
761
|
+
"Attempting to stop stale or non-opencode process:",
|
|
762
|
+
port.toString(),
|
|
763
|
+
pid.toString()
|
|
764
|
+
);
|
|
747
765
|
attemptedKill = true;
|
|
748
766
|
try {
|
|
749
767
|
process.kill(pid, "SIGTERM");
|
|
@@ -754,7 +772,11 @@ async function tryReclaimPort(port, tmuxPanePids) {
|
|
|
754
772
|
await new Promise((resolve) => setTimeout(resolve, 700));
|
|
755
773
|
for (const pid of pids) {
|
|
756
774
|
if (isProcessAlive(pid)) {
|
|
757
|
-
log2(
|
|
775
|
+
log2(
|
|
776
|
+
"Process still alive, sending SIGKILL:",
|
|
777
|
+
port.toString(),
|
|
778
|
+
pid.toString()
|
|
779
|
+
);
|
|
758
780
|
try {
|
|
759
781
|
process.kill(pid, "SIGKILL");
|
|
760
782
|
} catch {
|
|
@@ -786,8 +808,7 @@ function hasTmux() {
|
|
|
786
808
|
}
|
|
787
809
|
async function main() {
|
|
788
810
|
const isRuntime = /\/?(node|bun)(\.exe)?$/i.test(argv[0]);
|
|
789
|
-
const
|
|
790
|
-
const args = isRuntime && isScriptFile ? argv.slice(2) : argv.slice(1);
|
|
811
|
+
const args = isRuntime ? argv.slice(2) : argv.slice(1);
|
|
791
812
|
if (args.includes("--reap") || args.includes("-reap")) {
|
|
792
813
|
await ZombieReaper.reapAll();
|
|
793
814
|
exit(0);
|
|
@@ -827,7 +848,8 @@ async function main() {
|
|
|
827
848
|
"-h"
|
|
828
849
|
];
|
|
829
850
|
const isCliCommand = args.length > 0 && NON_TUI_COMMANDS.includes(args[0]);
|
|
830
|
-
|
|
851
|
+
const isInteractiveMode = args.length === 0;
|
|
852
|
+
if (isCliCommand || isInteractiveMode) {
|
|
831
853
|
const opencodeBin2 = findOpencodeBin();
|
|
832
854
|
if (!opencodeBin2) {
|
|
833
855
|
console.error(
|
|
@@ -862,7 +884,9 @@ async function main() {
|
|
|
862
884
|
const opencodeBin = findOpencodeBin();
|
|
863
885
|
log2("Found opencode binary:", opencodeBin);
|
|
864
886
|
if (!opencodeBin) {
|
|
865
|
-
console.error(
|
|
887
|
+
console.error(
|
|
888
|
+
'Error: Could not find "opencode" binary in PATH or common locations.'
|
|
889
|
+
);
|
|
866
890
|
log2("ERROR: opencode binary not found");
|
|
867
891
|
exit(1);
|
|
868
892
|
}
|
|
@@ -891,7 +915,9 @@ async function main() {
|
|
|
891
915
|
}
|
|
892
916
|
if (oldestPid && targetPort !== -1) {
|
|
893
917
|
log2("Rotating port:", targetPort, "Killing oldest PID:", oldestPid);
|
|
894
|
-
console.log(
|
|
918
|
+
console.log(
|
|
919
|
+
`\u267B\uFE0F Port rotation: Killing oldest session (PID ${oldestPid}) on port ${targetPort} to make room...`
|
|
920
|
+
);
|
|
895
921
|
safeKill(oldestPid, "SIGTERM");
|
|
896
922
|
await waitForProcessExit(oldestPid, 2e3);
|
|
897
923
|
if (isProcessAlive(oldestPid)) {
|
|
@@ -902,17 +928,25 @@ async function main() {
|
|
|
902
928
|
port = targetPort;
|
|
903
929
|
log2("Port reclaimed successfully:", port);
|
|
904
930
|
} else {
|
|
905
|
-
console.error(
|
|
931
|
+
console.error(
|
|
932
|
+
`\u26A0\uFE0F Failed to reclaim port ${targetPort} even after killing PID ${oldestPid}.`
|
|
933
|
+
);
|
|
906
934
|
exit(1);
|
|
907
935
|
}
|
|
908
936
|
} else {
|
|
909
|
-
console.error(
|
|
937
|
+
console.error(
|
|
938
|
+
"Error: Could not find any valid OpenCode sessions to rotate."
|
|
939
|
+
);
|
|
910
940
|
exit(1);
|
|
911
941
|
}
|
|
912
942
|
} else {
|
|
913
|
-
console.error(
|
|
943
|
+
console.error(
|
|
944
|
+
`Error: No available ports found in range ${OPENCODE_PORT_START2}-${OPENCODE_PORT_MAX}.`
|
|
945
|
+
);
|
|
914
946
|
console.error('Tip: Run "opentmux -reap" to clean up stuck sessions.');
|
|
915
|
-
console.error(
|
|
947
|
+
console.error(
|
|
948
|
+
' Or enable "rotate_port": true in config to automatically recycle oldest sessions.'
|
|
949
|
+
);
|
|
916
950
|
log2("ERROR: No available ports");
|
|
917
951
|
exit(1);
|
|
918
952
|
}
|
|
@@ -928,7 +962,10 @@ async function main() {
|
|
|
928
962
|
log2("Tmux available?", tmuxAvailable);
|
|
929
963
|
if (inTmux || !tmuxAvailable) {
|
|
930
964
|
log2("Running directly (in tmux or no tmux available)");
|
|
931
|
-
const child = spawn(opencodeBin, childArgs, {
|
|
965
|
+
const child = spawn(opencodeBin, childArgs, {
|
|
966
|
+
stdio: "inherit",
|
|
967
|
+
env: env2
|
|
968
|
+
});
|
|
932
969
|
child.on("error", (err) => {
|
|
933
970
|
log2("ERROR spawning child:", err.message);
|
|
934
971
|
});
|
|
@@ -950,10 +987,7 @@ async function main() {
|
|
|
950
987
|
});
|
|
951
988
|
const shellCommand = `${escapedBin} ${escapedArgs.join(" ")} || { echo "Exit code: $?"; echo "Press Enter to close..."; read; }`;
|
|
952
989
|
log2("Shell command for tmux:", shellCommand);
|
|
953
|
-
const tmuxArgs = [
|
|
954
|
-
"new-session",
|
|
955
|
-
shellCommand
|
|
956
|
-
];
|
|
990
|
+
const tmuxArgs = ["new-session", shellCommand];
|
|
957
991
|
log2("Tmux args:", JSON.stringify(tmuxArgs));
|
|
958
992
|
const child = spawn("tmux", tmuxArgs, { stdio: "inherit", env: env2 });
|
|
959
993
|
child.on("error", (err) => {
|
package/package.json
CHANGED