@pmate/cli 0.28.2 → 0.28.3

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/index.js +59 -25
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24420,33 +24420,70 @@ var HostCommandHandler = class {
24420
24420
  return;
24421
24421
  }
24422
24422
  const resolved = await client.resolveHostEnv(hostId);
24423
- const result = applyHostEnv(resolved.values);
24423
+ const result = await applyHostEnvRemote(hostId, resolved.values);
24424
24424
  if (args.json) ui.plain(JSON.stringify({ hostId, ...result }, null, 2));
24425
24425
  else ui.success(`Applied ${Object.keys(resolved.values).length} host env vars`, result.envFile);
24426
24426
  }
24427
24427
  };
24428
- function applyHostEnv(values, home = (0, import_node_os11.homedir)()) {
24429
- const hostDir = import_node_path30.default.join(home, ".pmate", "host");
24430
- const envFile = import_node_path30.default.join(hostDir, "host.env");
24431
- const tempFile = import_node_path30.default.join(hostDir, `.host.env.${process.pid}.tmp`);
24432
- const profileFile = import_node_path30.default.join(home, ".profile");
24433
- (0, import_node_fs25.mkdirSync)(hostDir, { recursive: true });
24434
- const content = Object.entries(values).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${normalizeEnvKey(key)}=${shellQuote3(value)}`).join("\n") + "\n";
24435
- (0, import_node_fs25.writeFileSync)(tempFile, content, { mode: 384 });
24436
- (0, import_node_fs25.chmodSync)(tempFile, 384);
24437
- (0, import_node_fs25.renameSync)(tempFile, envFile);
24438
- (0, import_node_fs25.chmodSync)(envFile, 384);
24439
- const existing = (0, import_node_fs25.existsSync)(profileFile) ? (0, import_node_fs25.readFileSync)(profileFile, "utf8") : "";
24440
- const blockPattern = new RegExp(`${escapeRegExp(BLOCK_START)}[\\s\\S]*?${escapeRegExp(BLOCK_END)}\\n?`, "g");
24441
- const withoutBlock = existing.replace(blockPattern, "").trimEnd();
24442
- const profileContent = `${withoutBlock}${withoutBlock ? "\n\n" : ""}${PROFILE_BLOCK}
24428
+ async function applyHostEnvRemote(host, values) {
24429
+ const target = `pmate@${normalizeHostId(host)}`;
24430
+ const content = serializeHostEnv(values);
24431
+ const script = buildRemoteApplyScript(Buffer.from(content, "utf8").toString("base64"));
24432
+ await new Promise((resolve, reject) => {
24433
+ const child = (0, import_node_child_process13.spawn)("ssh", [target, "bash -s"], { stdio: ["pipe", "pipe", "pipe"] });
24434
+ let stdout = "";
24435
+ let stderr = "";
24436
+ child.stdout.on("data", (chunk) => {
24437
+ stdout += chunk.toString();
24438
+ });
24439
+ child.stderr.on("data", (chunk) => {
24440
+ stderr += chunk.toString();
24441
+ });
24442
+ child.on("error", reject);
24443
+ child.on("close", (code) => {
24444
+ if (code === 0) resolve();
24445
+ else reject(new Error(`ssh to ${host} failed${stderr.trim() ? `: ${stderr.trim()}` : ` with code ${code}`}
24446
+ ${stdout.trim()}`.trim()));
24447
+ });
24448
+ child.stdin.end(script);
24449
+ });
24450
+ return {
24451
+ envFile: "~/.pmate/host/host.env",
24452
+ profileFile: "~/.profile",
24453
+ refreshed: true
24454
+ };
24455
+ }
24456
+ function buildRemoteApplyScript(contentBase64) {
24457
+ return `set -euo pipefail
24458
+ host_dir="$HOME/.pmate/host"
24459
+ env_file="$host_dir/host.env"
24460
+ profile_file="$HOME/.profile"
24461
+ mkdir -p "$host_dir"
24462
+ env_tmp="$(mktemp "$host_dir/.host.env.XXXXXX")"
24463
+ profile_tmp=""
24464
+ cleanup() { rm -f "$env_tmp"; [ -z "$profile_tmp" ] || rm -f "$profile_tmp"; }
24465
+ trap cleanup EXIT
24466
+ printf '%s' '${contentBase64}' | base64 --decode > "$env_tmp"
24467
+ chmod 600 "$env_tmp"
24468
+ mv "$env_tmp" "$env_file"
24469
+ touch "$profile_file"
24470
+ profile_tmp="$(mktemp "$HOME/.profile.XXXXXX")"
24471
+ awk '
24472
+ $0 == "${BLOCK_START}" { managed = 1; next }
24473
+ $0 == "${BLOCK_END}" { managed = 0; next }
24474
+ !managed { print }
24475
+ ' "$profile_file" > "$profile_tmp"
24476
+ while [ -s "$profile_tmp" ] && [ "$(tail -c 1 "$profile_tmp" | wc -l)" -eq 0 ]; do printf '\\n' >> "$profile_tmp"; done
24477
+ cat >> "$profile_tmp" <<'PMATE_PROFILE_BLOCK'
24478
+ ${PROFILE_BLOCK}
24479
+ PMATE_PROFILE_BLOCK
24480
+ mv "$profile_tmp" "$profile_file"
24481
+ bash -lc '. "$HOME/.profile"'
24482
+ printf 'applied %s\\n' "$env_file"
24443
24483
  `;
24444
- const profileTemp = `${profileFile}.${process.pid}.tmp`;
24445
- (0, import_node_fs25.writeFileSync)(profileTemp, profileContent);
24446
- (0, import_node_fs25.renameSync)(profileTemp, profileFile);
24447
- const check = (0, import_node_child_process13.spawnSync)("bash", ["-lc", `. ${shellQuote3(profileFile)}`], { cwd: home, env: { ...process.env, HOME: home }, encoding: "utf8" });
24448
- if (check.status !== 0) throw new Error(`Host env refresh validation failed: ${check.stderr.trim()}`);
24449
- return { envFile, profileFile, refreshed: true };
24484
+ }
24485
+ function serializeHostEnv(values) {
24486
+ return Object.entries(values).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => `${normalizeEnvKey(key)}=${shellQuote3(value)}`).join("\n") + "\n";
24450
24487
  }
24451
24488
  function normalizeHostId(value) {
24452
24489
  const normalized = value.trim();
@@ -24460,9 +24497,6 @@ function normalizeEnvKey(value) {
24460
24497
  function shellQuote3(value) {
24461
24498
  return `'${value.replace(/'/g, `'"'"'`)}'`;
24462
24499
  }
24463
- function escapeRegExp(value) {
24464
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
24465
- }
24466
24500
  function requireArg(value, name) {
24467
24501
  if (value === void 0) throw new Error(`Missing ${name}`);
24468
24502
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.28.2",
3
+ "version": "0.28.3",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {