claude-sessions spawn: add --headless/--create for non-interactive use

Claude-Session: https://claude.ai/code/session_01JXneLTuvb5Gxim3DTN2tQa
This commit is contained in:
Paul O'Reilly
2026-10-26 00:26:51 +13:00
parent c32ea467e4
commit d23778942d
3 changed files with 42 additions and 8 deletions

View File

@@ -6,7 +6,7 @@ Commands:
(no args) Interactive menu (new session: folder browser + unique topic)
list Show live Claude tmux sessions and resumable registry entries
recover [--days N] Detect sessions active before a restart
spawn <project> Spawn a new session (wraps claude-tmux)
spawn <project> Spawn a new session (wraps claude-tmux); --headless for scripted use
resume <session-id> Resume a past session by conversation ID
register Record a new session in the registry (called by claude-tmux)
gc [--days N] Prune stale entries and backfill session IDs
@@ -650,13 +650,39 @@ def cmd_spawn(args) -> None:
claude_tmux = subprocess.run(["which", "claude-tmux"], capture_output=True, text=True).stdout.strip()
if not claude_tmux:
die("claude-tmux not found in PATH")
cmd = [claude_tmux, args.project]
project = args.project
name = args.name
if getattr(args, "headless", False):
# Non-interactive: no prompts, no attach. Errors exit non-zero instead of asking.
folder = resolve_project_dir(project)
if folder is None and args.create:
folder = Path(project).expanduser()
if not folder.is_absolute():
die(f"--create needs an absolute path (got {project!r})")
try:
folder.mkdir(parents=True)
except OSError as e:
die(f"Could not create {folder}: {e}")
folder = folder.resolve()
if folder is None:
die(f"Folder not found: {project} (use --create with an absolute path to make it)")
name = name or title_case(folder.name)
if topic_in_use(name, list_tmux_sessions()):
print(f"{RED}Error:{NC} topic '{name}' is already in use — pass a unique --name", file=sys.stderr)
sys.exit(2)
if any(c in name for c in ".:"):
die("Topic must not contain '.' or ':' (tmux rewrites them)")
project = str(folder)
args.attach = False
cmd = [claude_tmux, project]
if args.mode:
cmd += ["--mode", args.mode]
if args.profile:
cmd += ["--profile", args.profile]
if args.name:
cmd += ["--name", args.name]
if name:
cmd += ["--name", name]
if args.attach:
cmd += ["--attach"]
os.execvp(claude_tmux, cmd)
@@ -919,6 +945,10 @@ def main() -> None:
sp.add_argument("--profile", default=None)
sp.add_argument("--name", default=None)
sp.add_argument("--attach", action="store_true")
sp.add_argument("--headless", action="store_true",
help="Non-interactive: never prompt or attach; fail (exit 2) if the topic is in use")
sp.add_argument("--create", action="store_true",
help="With --headless: create the folder (absolute path) if it does not exist")
rsp = sub.add_parser("resume", help="Resume a past conversation by session ID")
rsp.add_argument("session_id", help="Session UUID or prefix")