--- issue: 52 issue_title: "Bash command arity table for smart approval pattern suggestions" --- # Bash command arity table for smart approval pattern suggestions ## Problem Statement When a user approves a bash command "for this session," the system suggests a wildcard pattern via `suggestBashPattern()`. Currently that function uses a naive first-word heuristic (`git status --short` → `git *`), which is too broad for commands like `git` where the subcommand is semantically significant. A curated arity dictionary would let us suggest `git checkout *` instead of `git *`, and `npm run dev*` instead of `npm *`. ## Goals - Add a curated arity dictionary mapping command prefixes to their token depth. - Expose a `prefix(tokens: string[]): string[]` function that returns the meaningful prefix for a tokenized command. - Replace the naive first-word heuristic in `suggestBashPattern()` with arity-aware logic. - Longest matching prefix wins; unknown commands default to arity 1. - Cover common CLI tools: git, npm, npx, pnpm, yarn, docker, cargo, pip, go, kubectl, etc. ## Non-Goals - Shell-quoting-aware tokenization (already handled by `src/input-normalizer.ts` / #72). - Persisting session approvals across sessions. - Changing how other surfaces (mcp, skill, tool) suggest patterns. - Comprehensive coverage of every CLI tool — the dictionary is extensible and good-enough coverage suffices. ## Background ### Current state `src/pattern-suggest.ts` contains `suggestBashPattern(command: string): string`: ```typescript const spaceIndex = trimmed.indexOf(" "); if (spaceIndex === -1) return trimmed; return `${trimmed.slice(0, spaceIndex)} *`; ``` This produces `git *` for any git command — overly permissive. ### Permission surface This change affects the **bash** surface only, specifically the pattern suggestion fed into session rules. It does not change permission evaluation, only what pattern is suggested to the user. ### References - `src/pattern-suggest.ts` — existing suggestion logic. - `src/session-rules.ts` — `SessionRules.approve()` stores the pattern. - OpenCode `packages/opencode/src/permission/arity.ts` — prior art with ~150 entries. ## Design Overview ### New module: `src/bash-arity.ts` ```typescript /** * Curated arity dictionary. * Keys are space-joined command prefixes; values are the arity (token count). * Multi-level entries allow `npm run` (arity 3) alongside `npm` (arity 2). */ const ARITY: Record = { "git": 2, // git * "npm run": 3, // npm run