@nomac/cli 0.11.2 → 0.11.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomac/cli",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "Cloud Mac sessions over SSH and HTTPS, plus iOS builds and publishing — built for agents.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -4,7 +4,7 @@ import { join, resolve } from "node:path";
4
4
  import { parseArgs } from "node:util";
5
5
  import { api, CliError } from "./api.mjs";
6
6
  import { sessionStore } from "./session-store.mjs";
7
- import { forwardingArg, runProcess, sshArgs, workspaceCommand } from "./session-ssh.mjs";
7
+ import { forwardingArg, isShellLine, runProcess, sshArgs, workspaceCommand } from "./session-ssh.mjs";
8
8
  import { pullProject, syncProject } from "./session-transfer.mjs";
9
9
  import { macRequest, sessionId, transportOptions } from "./mac-transport.mjs";
10
10
  import { copyToClipboard, desktop, DESKTOP_HELP, screenSharing } from "./desktop.mjs";
@@ -386,7 +386,7 @@ export async function hostedSessionCommand(command, argv, { store = sessionStore
386
386
  // A command may run an hour (the gateway's limit); waiting can cover all of it.
387
387
  const waitFor = integer(values.wait, 30, 0, 3600);
388
388
  const timeout = integer(values.timeout, values["request-key"] === undefined ? Math.max(300, waitFor) : 600, 1, 3600);
389
- method = "POST"; path = `${base}/jobs`; params = { requestKey: values["request-key"] ?? `cli-${randomUUID()}`, body: { argv: positionals, timeout_seconds: timeout } };
389
+ method = "POST"; path = `${base}/jobs`; params = { requestKey: values["request-key"] ?? `cli-${randomUUID()}`, body: { argv: isShellLine(positionals) ? ["/bin/bash", "-lc", positionals[0]] : positionals, timeout_seconds: timeout } };
390
390
  } else {
391
391
  if (positionals.length !== 1 || !/^job_[a-f0-9]{40}$/.test(positionals[0])) throw new CliError("Supply the existing job ID.");
392
392
  path = `${base}/jobs/${positionals[0]}`;
@@ -127,8 +127,14 @@ export async function prepareWorkspace(session, options) {
127
127
  return { workspace, capabilities: { os: "macOS", version: osVersion, architecture, administrator: admin, available_disk_bytes: Number(availableKb) * 1024 } };
128
128
  }
129
129
 
130
+ /**
131
+ * One argument with spaces or shell syntax is a shell command line, as ssh host 'a; b' runs it;
132
+ * several are a program and its arguments, passed exactly.
133
+ */
134
+ export const isShellLine = (args) => args.length === 1 && /[\s;&|<>()$`*?{}~#'"\\]/.test(args[0]);
135
+
130
136
  export function workspaceCommand(session, args = []) {
131
- const command = args.length ? args.map(shellQuote).join(" ") : '"$SHELL" -l';
137
+ const command = !args.length ? '"$SHELL" -l' : isShellLine(args) ? `"$SHELL" -lc ${shellQuote(args[0])}` : args.map(shellQuote).join(" ");
132
138
  return `cd ${shellQuote(validateWorkspace(session.workspace))} && exec ${command}`;
133
139
  }
134
140