From 89eb5e382bacab373445bbe8fa26c55038fee566 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath Date: Sat, 21 Feb 2026 12:23:08 -0800 Subject: [PATCH] Reorganize CLI commands into groups using commander v14, upgrade commander to 14.0.3 --- bun.lock | 4 +- package.json | 2 +- src/cli.ts | 108 ++++++++++++++++++++------------------------------- 3 files changed, 45 insertions(+), 69 deletions(-) diff --git a/bun.lock b/bun.lock index 64dc8db..fc87f84 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "sandlot", "dependencies": { - "commander": "^13.1.0", + "commander": "^14.0.3", }, "devDependencies": { "@types/bun": "^1.3.9", @@ -19,7 +19,7 @@ "bun-types": ["bun-types@1.3.9", "https://npm.nose.space/bun-types/-/bun-types-1.3.9.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], - "commander": ["commander@13.1.0", "https://npm.nose.space/commander/-/commander-13.1.0.tgz", {}, "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw=="], + "commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="], "undici-types": ["undici-types@5.26.5", "https://npm.nose.space/undici-types/-/undici-types-5.26.5.tgz", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], } diff --git a/package.json b/package.json index a28a82d..dbe4a3e 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "sandlot": "./src/cli.ts" }, "dependencies": { - "commander": "^13.1.0" + "commander": "^14.0.3" }, "scripts": { "test:markdown": "bun src/test-markdown.ts" diff --git a/src/cli.ts b/src/cli.ts index 35a018d..73a5a38 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -27,7 +27,13 @@ const program = new Command() program.name("sandlot").description("Branch-based development with git worktrees and Apple Container").version(pkg.version) -// ── sandlot new ────────────────────────────────────────────────────── +// ── Sessions ──────────────────────────────────────────────────────── + +program + .command("list") + .description("Show all active sessions") + .option("--json", "Output as JSON") + .action(listAction) program .command("new") @@ -38,16 +44,6 @@ program .description("Create a new session and launch Claude") .action(newAction) -// ── sandlot list ───────────────────────────────────────────────────── - -program - .command("list") - .description("Show all active sessions (◌ idle · ◯ working · ◎ unsaved · ● saved)") - .option("--json", "Output as JSON") - .action(listAction) - -// ── sandlot open ───────────────────────────────────────────────────── - program .command("open") .argument("", "branch name") @@ -57,25 +53,6 @@ program .description("Re-enter an existing session") .action(openAction) -// ── sandlot review ─────────────────────────────────────────────────── - -program - .command("review") - .argument("", "branch name") - .option("-p, --print", "print the review to stdout instead of launching interactive mode") - .description("Launch an interactive grumpy code review for a branch") - .action(reviewAction) - -// ── sandlot shell ──────────────────────────────────────────────────── - -program - .command("shell") - .argument("[branch]", "branch name (omit for a plain VM shell)") - .description("Open a shell in the VM (at the session's worktree if branch given)") - .action(shellAction) - -// ── sandlot close ──────────────────────────────────────────────────── - program .command("close") .argument("", "branch name") @@ -90,31 +67,27 @@ program .description("Remove a session (alias for close)") .action((branch: string, opts: { force?: boolean }) => closeAction(branch, opts)) -// ── sandlot merge ──────────────────────────────────────────────────── +// ── Branch ────────────────────────────────────────────────────────── + +program.commandsGroup("Branch Commands:") program - .command("merge") + .command("diff") .argument("", "branch name") - .description("Merge a branch into main and close the session") - .action(mergeAction) - -// ── sandlot squash ─────────────────────────────────────────────────── + .description("Show uncommitted changes, or full branch diff vs main") + .action(diffAction) program - .command("squash") + .command("log") .argument("", "branch name") - .description("Squash-merge a branch into main and close the session") - .action(squashAction) - -// ── sandlot rebase ─────────────────────────────────────────────────── + .description("Show commits on a branch that are not on main") + .action(logAction) program - .command("rebase") + .command("show") .argument("", "branch name") - .description("Rebase a branch onto the latest main") - .action(rebaseAction) - -// ── sandlot save ───────────────────────────────────────────────────── + .description("Show the prompt and full diff for a branch") + .action(showAction) program .command("save") @@ -123,31 +96,36 @@ program .description("Stage all changes and commit") .action(saveAction) -// ── sandlot diff ───────────────────────────────────────────────────── +program + .command("merge") + .argument("", "branch name") + .description("Merge a branch into main and close the session") + .action(mergeAction) program - .command("diff") + .command("squash") .argument("", "branch name") - .description("Show uncommitted changes, or full branch diff vs main") - .action(diffAction) - -// ── sandlot show ───────────────────────────────────────────────────── + .description("Squash-merge a branch into main and close the session") + .action(squashAction) program - .command("show") + .command("rebase") .argument("", "branch name") - .description("Show the prompt and full diff for a branch (for code review)") - .action(showAction) - -// ── sandlot log ────────────────────────────────────────────────────── + .description("Rebase a branch onto the latest main") + .action(rebaseAction) program - .command("log") + .command("review") .argument("", "branch name") - .description("Show commits on a branch that are not on main") - .action(logAction) + .option("-p, --print", "print the review to stdout instead of launching interactive mode") + .description("Launch an interactive grumpy code review for a branch") + .action(reviewAction) -// ── sandlot dir ────────────────────────────────────────────────────── +program + .command("shell") + .argument("[branch]", "branch name (omit for a plain VM shell)") + .description("Open a shell in the VM") + .action(shellAction) program .command("dir") @@ -155,19 +133,17 @@ program .description("Print the worktree path for a session") .action(dirAction) -// ── sandlot cleanup ────────────────────────────────────────────────── +// ── Admin ─────────────────────────────────────────────────────────── + +program.commandsGroup("Admin Commands:") program .command("cleanup") .description("Remove stale sessions whose worktrees no longer exist") .action(cleanupAction) -// ── sandlot vm ─────────────────────────────────────────────────────── - registerVmCommands(program) -// ── sandlot completions ────────────────────────────────────────────── - program .command("completions") .option("--install", "Output a shell script that installs the completions file")