@termhub/agent 0.1.5 → 0.1.6

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.
Files changed (2) hide show
  1. package/dist/cli.js +50 -35
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -750,16 +750,49 @@ function createDispatcher(deps) {
750
750
  }
751
751
 
752
752
  // src/pty.ts
753
+ import fs3 from "fs";
754
+ import path3 from "path";
755
+
756
+ // src/pty-health.ts
753
757
  import fs2 from "fs";
754
758
  import path2 from "path";
759
+ import { createRequire } from "module";
760
+ function findSpawnHelper(resolveFrom = import.meta.url) {
761
+ let pkgJson;
762
+ try {
763
+ pkgJson = createRequire(resolveFrom).resolve("node-pty/package.json");
764
+ } catch {
765
+ return null;
766
+ }
767
+ const root = path2.dirname(pkgJson);
768
+ const candidates = [
769
+ path2.join(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
770
+ path2.join(root, "build", "Release", "spawn-helper")
771
+ ];
772
+ return candidates.find((p) => fs2.existsSync(p)) ?? null;
773
+ }
774
+ var EXEC_BITS = 73;
775
+ function ensureSpawnHelperExecutable(helper = findSpawnHelper()) {
776
+ if (!helper) return { path: null, executable: true, repaired: false };
777
+ try {
778
+ const mode = fs2.statSync(helper).mode;
779
+ if (mode & EXEC_BITS) return { path: helper, executable: true, repaired: false };
780
+ fs2.chmodSync(helper, (mode | 493) & 4095);
781
+ return { path: helper, executable: true, repaired: true };
782
+ } catch (err) {
783
+ return { path: helper, executable: false, repaired: false, error: err instanceof Error ? err.message : String(err) };
784
+ }
785
+ }
786
+
787
+ // src/pty.ts
755
788
  function expandHome2(rawCwd, home) {
756
789
  if (rawCwd === "~") return home;
757
- if (rawCwd.startsWith("~/")) return path2.join(home, rawCwd.slice(2));
790
+ if (rawCwd.startsWith("~/")) return path3.join(home, rawCwd.slice(2));
758
791
  return rawCwd;
759
792
  }
760
793
  function existsDir(p) {
761
794
  try {
762
- return fs2.statSync(p).isDirectory();
795
+ return fs3.statSync(p).isDirectory();
763
796
  } catch {
764
797
  return false;
765
798
  }
@@ -769,6 +802,9 @@ function resolveCwd(rawCwd) {
769
802
  const expanded = expandHome2(rawCwd, home);
770
803
  return existsDir(expanded) ? expanded : home;
771
804
  }
805
+ function isSpawnHelperFailure(err) {
806
+ return /posix_spawnp failed/.test(err instanceof Error ? err.message : String(err));
807
+ }
772
808
  function isEnoent(err) {
773
809
  const e = err;
774
810
  if (e?.code === "ENOENT") return true;
@@ -778,6 +814,7 @@ function isEnoent(err) {
778
814
  function createPtyManager(deps) {
779
815
  const procs = /* @__PURE__ */ new Map();
780
816
  const tmux = deps.tmuxPath ?? tmuxPath();
817
+ const repairSpawnHelper = deps.repairSpawnHelper ?? (() => ensureSpawnHelperExecutable());
781
818
  let spawnFn = deps.spawn;
782
819
  async function resolveSpawn() {
783
820
  if (!spawnFn) {
@@ -804,7 +841,16 @@ function createPtyManager(deps) {
804
841
  TERMHUB_SESSION: params.session
805
842
  };
806
843
  const spawn = await resolveSpawn();
807
- proc = spawn(tmux, ["-u", "new-session", "-A", "-s", params.session, "-c", cwd], { name: "xterm-256color", cols, rows, cwd, env });
844
+ const spawnTmux = () => spawn(tmux, ["-u", "new-session", "-A", "-s", params.session, "-c", cwd], { name: "xterm-256color", cols, rows, cwd, env });
845
+ try {
846
+ proc = spawnTmux();
847
+ } catch (err) {
848
+ if (!isSpawnHelperFailure(err)) throw err;
849
+ const helper = repairSpawnHelper();
850
+ if (!helper.repaired) throw err;
851
+ deps.log("spawn-helper exec bit repaired on open", { path: helper.path });
852
+ proc = spawnTmux();
853
+ }
808
854
  } catch (err) {
809
855
  deps.log("pty open failed", { ch, session: params.session, tmux, cwd: params.cwd, error: err instanceof Error ? err.message : String(err) });
810
856
  socket.sendControl({
@@ -888,37 +934,6 @@ function createPtyManager(deps) {
888
934
  };
889
935
  }
890
936
 
891
- // src/pty-health.ts
892
- import fs3 from "fs";
893
- import path3 from "path";
894
- import { createRequire } from "module";
895
- function findSpawnHelper(resolveFrom = import.meta.url) {
896
- let pkgJson;
897
- try {
898
- pkgJson = createRequire(resolveFrom).resolve("node-pty/package.json");
899
- } catch {
900
- return null;
901
- }
902
- const root = path3.dirname(pkgJson);
903
- const candidates = [
904
- path3.join(root, "prebuilds", `${process.platform}-${process.arch}`, "spawn-helper"),
905
- path3.join(root, "build", "Release", "spawn-helper")
906
- ];
907
- return candidates.find((p) => fs3.existsSync(p)) ?? null;
908
- }
909
- var EXEC_BITS = 73;
910
- function ensureSpawnHelperExecutable(helper = findSpawnHelper()) {
911
- if (!helper) return { path: null, executable: true, repaired: false };
912
- try {
913
- const mode = fs3.statSync(helper).mode;
914
- if (mode & EXEC_BITS) return { path: helper, executable: true, repaired: false };
915
- fs3.chmodSync(helper, (mode | 493) & 4095);
916
- return { path: helper, executable: true, repaired: true };
917
- } catch (err) {
918
- return { path: helper, executable: false, repaired: false, error: err instanceof Error ? err.message : String(err) };
919
- }
920
- }
921
-
922
937
  // src/rpc/ai.ts
923
938
  async function credential(params) {
924
939
  let prefix;
@@ -1227,7 +1242,7 @@ async function status(deps = {}) {
1227
1242
  }
1228
1243
 
1229
1244
  // src/version.ts
1230
- var AGENT_VERSION = "0.1.5";
1245
+ var AGENT_VERSION = "0.1.6";
1231
1246
 
1232
1247
  // src/run.ts
1233
1248
  function detectOs(platform = process.platform) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@termhub/agent",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Agente do termhub: conecta esta máquina ao servidor por WebSocket de saída (sem SSH) e expõe os terminais tmux no navegador.",
5
5
  "license": "MIT",
6
6
  "private": false,