farhand 0.2.8 → 0.2.11

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/README.md CHANGED
@@ -6,6 +6,21 @@ your platform. On first run it downloads
6
6
  verifies it against `SHA256SUMS`, and keeps it inside this package. The
7
7
  version of this package always equals the binary version it fetches.
8
8
 
9
+ Install it globally to set up an agent:
10
+
11
+ ```
12
+ npm i -g farhand
13
+ farhand install claude-code # or opencode, codex
14
+ ```
15
+
16
+ The agent's config then launches this package's entry (`bin/farhand.js`),
17
+ not the versioned binary, so `npm i -g farhand@latest` upgrades the agent
18
+ too; the first run after an upgrade downloads the new binary. The agent
19
+ needs `node` on its `PATH`. `npx farhand init` / `npx farhand check` work
20
+ for a try, but `farhand install` refuses to run from npx's cache (or
21
+ `pnpm dlx`, `bunx`): the agent would lose FarHand when the cache is
22
+ cleared.
23
+
9
24
  Everything else — what FarHand is, how to configure it, how it plugs into
10
25
  OpenCode, Claude Code and Codex — is in the
11
26
  [main README](https://github.com/CogFlux/farhand).
package/bin/farhand.js CHANGED
@@ -58,21 +58,34 @@ async function ensureBinary() {
58
58
  const actual = crypto.createHash("sha256").update(tarball).digest("hex");
59
59
  if (expected !== actual) throw new Error("checksum mismatch; refusing to install");
60
60
 
61
+ // Unpacked into a private folder and renamed into place, so an agent
62
+ // starting the server and its hook at once never runs a half-written
63
+ // binary; whichever process finishes second keeps the first one's copy.
61
64
  fs.mkdirSync(vendor, { recursive: true });
62
65
  const tmp = path.join(os.tmpdir(), `${name}-${process.pid}.tar.gz`);
66
+ const stage = fs.mkdtempSync(path.join(vendor, ".unpack-"));
63
67
  fs.writeFileSync(tmp, tarball);
64
68
  try {
65
- execFileSync("tar", ["-C", vendor, "-xzf", tmp]);
69
+ execFileSync("tar", ["-C", stage, "-xzf", tmp]);
70
+ fs.chmodSync(path.join(stage, name, "farhand"), 0o755);
71
+ try {
72
+ fs.renameSync(path.join(stage, name), path.join(vendor, name));
73
+ } catch (e) {
74
+ if (!fs.existsSync(bin)) throw e;
75
+ }
66
76
  } finally {
67
77
  fs.rmSync(tmp, { force: true });
78
+ fs.rmSync(stage, { recursive: true, force: true });
68
79
  }
69
- fs.chmodSync(bin, 0o755);
70
80
  return bin;
71
81
  }
72
82
 
73
83
  ensureBinary()
74
84
  .then((bin) => {
75
- const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
85
+ // `farhand install` writes this script, not the versioned binary, into
86
+ // the agent's config, so an upgrade does not leave it pointing nowhere.
87
+ const env = { ...process.env, FARHAND_LAUNCHER: fs.realpathSync(__filename) };
88
+ const r = spawnSync(bin, process.argv.slice(2), { stdio: "inherit", env });
76
89
  if (r.error) throw r.error;
77
90
  process.exit(r.status === null ? 1 : r.status);
78
91
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "farhand",
3
- "version": "0.2.8",
3
+ "version": "0.2.11",
4
4
  "description": "Remote hands for coding agents: run OpenCode / Claude Code / Codex work on a remote host over SSH, keep credentials local, audit everything",
5
5
  "license": "MIT",
6
6
  "repository": { "type": "git", "url": "https://github.com/CogFlux/farhand.git" },