This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

pty send: reject unknown flags (closes #20)

Previously `pty send <name> "text" --enter` exited 0 and silently
dropped --enter, so the text landed at the prompt but never executed.
The --seq branch already rejected unknown args; the positional branch
now mirrors that strictness.

Typos --enter / --newline / --return / --cr additionally print a hint
pointing at --seq "text" --seq key:return, which is the real syntax.

Nathan Herald (Apr 19, 2026, 3:32 PM +0200) 04c038a3 336902ba

+62
+1
CHANGELOG.md
··· 4 4 5 5 ### Send 6 6 - Add `pty send --paste` (and `paste: true` on `SendOptions` / `SendDataOptions`) to wrap the entire payload in bracketed-paste markers (CSI 200 ~ … CSI 201 ~). The receiving TUI treats everything between the markers as one paste event rather than a sequence of keystrokes — intended for injecting multi-line prompts into agent sessions (claude, aider, etc.) without premature submission when the payload contains newlines. Works with positional text, `--seq` sequences, and composes with `--with-delay`. Flag position-independent. 7 + - **Behaviour change:** `pty send` now errors on unknown trailing flags after positional text instead of silently dropping them. Previously `pty send <name> "text" --enter` exited 0 and sent only `"text"` — the `--enter` was swallowed and the text never executed because no Enter was appended. Now: exits non-zero with `Unexpected argument: --enter`. The common typos `--enter` / `--newline` / `--return` / `--cr` additionally print a hint pointing at the real syntax `--seq "<text>" --seq key:return`. Mirrors the strictness of the `--seq` parsing branch. (closes #20 — thanks @schickling-assistant) 7 8 8 9 ### Client API 9 10 - Add `env?: Record<string, string>` to `SpawnDaemonOptions` and `ServerOptions` — use this to spawn a session child with a verbatim environment (no inheritance from the daemon's `process.env`, no allow-list). `PTY_SESSION` is always injected on top so nesting detection and `pty exec` keep working. Mutually exclusive with `isolateEnv` / `extraEnv` (throws at daemon startup if both are passed). Requested by the pty-layout dev to spawn a launcher shell with a shim `tmux` on `PATH`, a custom `TMUX` marker, and a filter-tag env var.
+17
src/cli.ts
··· 439 439 process.exit(1); 440 440 } 441 441 442 + // Common typos for "send a return key" — accepted nowhere; suggest 443 + // the real syntax so agents / humans don't silently lose a keystroke. 444 + const ENTER_TYPOS = new Set(["--enter", "--newline", "--return", "--cr"]); 445 + for (const a of sendArgs) { 446 + if (ENTER_TYPOS.has(a)) { 447 + console.error(`Unknown flag "${a}". Use \`--seq "<text>" --seq key:return\` to send text followed by Enter.`); 448 + process.exit(1); 449 + } 450 + } 451 + 442 452 let data: string[]; 443 453 if (hasSeq) { 444 454 data = []; ··· 456 466 } 457 467 } 458 468 } else if (hasPositional) { 469 + // Mirror the --seq branch's strictness: reject any trailing args 470 + // after the positional text so unknown flags (e.g. --enter) no 471 + // longer get silently dropped on the floor (closes #20). 472 + if (sendArgs.length > 1) { 473 + console.error(`Unexpected argument: ${sendArgs[1]}`); 474 + process.exit(1); 475 + } 459 476 data = [sendArgs[0]]; 460 477 } else { 461 478 console.error("Nothing to send.");
+44
tests/send-paste.test.ts
··· 217 217 expect((received.match(/\x1b\[201~/g) ?? []).length).toBe(1); 218 218 }, 15_000); 219 219 }); 220 + 221 + // Arg-parsing validation runs before any socket connection, so these 222 + // tests don't need a daemon — just spawn the CLI and check stderr/exit. 223 + describe("pty send strict flag parsing (#20)", () => { 224 + it("rejects an unknown flag after positional text", () => { 225 + const dir = makeSessionDir(); 226 + const r = runCli(dir, "send", "somename", "hello world", "--bogus"); 227 + expect(r.status).not.toBe(0); 228 + expect(r.stderr).toContain("Unexpected argument"); 229 + expect(r.stderr).toContain("--bogus"); 230 + }, 10_000); 231 + 232 + it("suggests --seq key:return when --enter is used", () => { 233 + const dir = makeSessionDir(); 234 + const r = runCli(dir, "send", "somename", "sudo cmd", "--enter"); 235 + expect(r.status).not.toBe(0); 236 + expect(r.stderr).toContain("--enter"); 237 + expect(r.stderr).toContain("--seq"); 238 + expect(r.stderr).toContain("key:return"); 239 + }, 10_000); 240 + 241 + it("suggests the real syntax for --newline and --return aliases too", () => { 242 + const dir = makeSessionDir(); 243 + for (const flag of ["--newline", "--return", "--cr"]) { 244 + const r = runCli(dir, "send", "somename", "text", flag); 245 + expect(r.status).not.toBe(0); 246 + expect(r.stderr).toContain(flag); 247 + expect(r.stderr).toContain("key:return"); 248 + } 249 + }, 15_000); 250 + 251 + it("plain positional text still works (regression guard)", async () => { 252 + const dir = makeSessionDir(); 253 + const name = uniqueName(); 254 + const dump = path.join(dir, "dump.bin"); 255 + await startDumpSession(dir, name, dump); 256 + 257 + const r = runCli(dir, "send", name, "still-works"); 258 + expect(r.status).toBe(0); 259 + 260 + const received = await waitForDump(dump, "still-works".length, 3000); 261 + expect(received).toBe("still-works"); 262 + }, 15_000); 263 + });