@termfleet/terminal 0.1.0 → 0.1.1

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
@@ -29,3 +29,7 @@ Created sessions can carry an app-namespaced ownership mark; discovery does not
29
29
  claim or terminate unmarked sessions. Terminal attachment is intentionally
30
30
  separate from session termination: disposing a viewer only detaches its
31
31
  ephemeral PTY client and releases all handles.
32
+
33
+ `createSession` accepts a structured `{ program, arguments }` command plus an
34
+ environment map. Arguments are passed directly without constructing a shell
35
+ command, and the credential bootstrap deletes itself before the command starts.
package/dist/tmux.d.ts CHANGED
@@ -9,7 +9,12 @@ export type TmuxWindowSize = {
9
9
  width: number;
10
10
  height: number;
11
11
  };
12
+ export type TmuxCommand = {
13
+ arguments?: string[];
14
+ program: string;
15
+ };
12
16
  export type CreateSessionOptions = {
17
+ command?: TmuxCommand;
13
18
  cwd?: string;
14
19
  env?: Record<string, string>;
15
20
  name: string;
@@ -21,7 +26,7 @@ export type CreateSessionOptions = {
21
26
  export declare function assertTmux(): void;
22
27
  export declare function targetForSession(sessionName: string): string;
23
28
  export declare function assertSession(name: string, socket?: string): void;
24
- export declare function createSession({ cwd, env, name, owner, ownerOption: ownershipOption, panes, socket }: CreateSessionOptions): Promise<{
29
+ export declare function createSession({ command, cwd, env, name, owner, ownerOption: ownershipOption, panes, socket }: CreateSessionOptions): Promise<{
25
30
  name: string;
26
31
  panes: number;
27
32
  }>;
package/dist/tmux.js CHANGED
@@ -40,7 +40,7 @@ export function assertSession(name, socket) {
40
40
  // createWindowSession), so every tmux invocation here uses runAsync (spawn, not
41
41
  // spawnSync) and the pane-ready poll below uses sleepAsync — see waitForPanesReady.
42
42
  // Nothing in this function may block the loop.
43
- export async function createSession({ cwd, env, name, owner, ownerOption: ownershipOption = ownerOption, panes, socket }) {
43
+ export async function createSession({ command, cwd, env, name, owner, ownerOption: ownershipOption = ownerOption, panes, socket }) {
44
44
  assertTmux();
45
45
  if (!name) {
46
46
  throw new Error("--name is required.");
@@ -48,6 +48,9 @@ export async function createSession({ cwd, env, name, owner, ownerOption: owners
48
48
  if (!Number.isInteger(panes) || panes < 1) {
49
49
  throw new Error("--panes must be a positive integer.");
50
50
  }
51
+ if (command !== undefined && !command.program) {
52
+ throw new Error("A command program is required.");
53
+ }
51
54
  // Global server options must be in place before the first pane spawns —
52
55
  // history-limit is read at pane creation. On a fresh dedicated `-L` socket no
53
56
  // server exists yet and `set-option -g` will NOT start one (only commands like
@@ -58,11 +61,13 @@ export async function createSession({ cwd, env, name, owner, ownerOption: owners
58
61
  const sessionEnv = env ?? {};
59
62
  const bootstrapDirectories = [];
60
63
  const paneBootstrapArgs = (pane) => {
64
+ const commandArgs = command === undefined ? [] : [command.program, ...(command.arguments ?? [])];
61
65
  if (Object.keys(sessionEnv).length === 0)
62
- return [];
66
+ return commandArgs;
63
67
  const directory = mkdtempSync(join(tmpdir(), "tmux-session-env-"));
64
68
  bootstrapDirectories.push(directory);
65
- return writeSessionEnvironmentBootstrap(directory, pane, sessionEnv);
69
+ const shell = process.env.SHELL ?? "/bin/sh";
70
+ return writeSessionEnvironmentBootstrap(directory, pane, sessionEnv, commandArgs.length === 0 ? [shell, "-l"] : commandArgs);
66
71
  };
67
72
  try {
68
73
  const startArgs = [...sessionServerOptionArgs(), "new-session", "-d", "-s", name];
@@ -271,10 +276,9 @@ function tmuxClientEnvironment(source = process.env) {
271
276
  }
272
277
  return environment;
273
278
  }
274
- function writeSessionEnvironmentBootstrap(directory, pane, environment) {
279
+ function writeSessionEnvironmentBootstrap(directory, pane, environment, command) {
275
280
  const environmentPath = join(directory, `pane-${pane}.env`);
276
281
  const wrapperPath = join(directory, `pane-${pane}.sh`);
277
- const shell = process.env.SHELL ?? "/bin/sh";
278
282
  const lines = Object.entries(environment).map(([name, value]) => {
279
283
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
280
284
  throw new Error(`Invalid session environment variable name: ${JSON.stringify(name)}.`);
@@ -284,15 +288,17 @@ function writeSessionEnvironmentBootstrap(directory, pane, environment) {
284
288
  writeFileSync(environmentPath, `${lines.join("\n")}\n`, { flag: "wx", mode: 0o600 });
285
289
  writeFileSync(wrapperPath, [
286
290
  "#!/bin/sh",
291
+ 'environment_path="$1"',
292
+ "shift",
287
293
  "set -a",
288
- '. "$1"',
294
+ '. "$environment_path"',
289
295
  "set +a",
290
- 'rm -f -- "$1" "$0"',
296
+ 'rm -f -- "$environment_path" "$0"',
291
297
  'rmdir -- "$(dirname -- "$0")" 2>/dev/null || true',
292
- 'exec "$2" -l',
298
+ 'exec "$@"',
293
299
  ""
294
300
  ].join("\n"), { flag: "wx", mode: 0o700 });
295
- return [wrapperPath, environmentPath, shell];
301
+ return [wrapperPath, environmentPath, ...command];
296
302
  }
297
303
  function shellQuote(value) {
298
304
  return `'${value.replaceAll("'", `'"'"'`)}'`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@termfleet/terminal",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Framework-neutral terminal transport and durable tmux session substrate extracted from Termfleet.",
5
5
  "keywords": [
6
6
  "pty",