| 164 | |
| 165 | |
| 166 | def _cli_main() -> None: |
| 167 | parser = argparse.ArgumentParser(prog="semble") |
| 168 | sub = parser.add_subparsers(dest="command") |
| 169 | |
| 170 | search_p = sub.add_parser("search", help="Search a codebase.") |
| 171 | search_p.add_argument("query", help="Natural language or code query.") |
| 172 | search_p.add_argument("path", nargs="?", default=".", help="Local path or git URL (default: current directory).") |
| 173 | search_p.add_argument("-k", "--top-k", type=int, default=5, help="Number of results (default: 5).") |
| 174 | search_p.add_argument( |
| 175 | "--max-snippet-lines", |
| 176 | type=int, |
| 177 | default=None, |
| 178 | metavar="N", |
| 179 | help="Lines of source per result (default: full chunk). 10 = signature + body, 0 = no code.", |
| 180 | ) |
| 181 | _add_content_args(search_p) |
| 182 | |
| 183 | clear_p = sub.add_parser("clear", help="Clear the index cache.") |
| 184 | clear_p.add_argument("type", choices=["all", "index", "savings"], help="Type of cache to clear.") |
| 185 | |
| 186 | related_p = sub.add_parser("find-related", help="Find code similar to a specific location.") |
| 187 | related_p.add_argument("file_path", help="File path as shown in search results.") |
| 188 | related_p.add_argument("line", type=int, help="Line number (1-indexed).") |
| 189 | related_p.add_argument("path", nargs="?", default=".", help="Local path or git URL (default: current directory).") |
| 190 | related_p.add_argument("-k", "--top-k", type=int, default=5, help="Number of results (default: 5).") |
| 191 | related_p.add_argument( |
| 192 | "--max-snippet-lines", |
| 193 | type=int, |
| 194 | default=None, |
| 195 | metavar="N", |
| 196 | help="Lines of source per result (default: full chunk). 10 = signature + body, 0 = no code.", |
| 197 | ) |
| 198 | _add_content_args(related_p) |
| 199 | |
| 200 | sub.add_parser("savings", help="Show token savings and usage stats.") |
| 201 | |
| 202 | sub.add_parser("install", help="Interactively configure semble across coding agents.") |
| 203 | sub.add_parser("uninstall", help="Interactively remove semble configuration from coding agents.") |
| 204 | |
| 205 | args = parser.parse_args() |
| 206 | |
| 207 | if args.command == "savings": |
| 208 | print(format_savings_report()) |
| 209 | elif args.command in ("install", "uninstall"): |
| 210 | from semble.installer import run |
| 211 | |
| 212 | run(args.command) |
| 213 | elif args.command == "clear": |
| 214 | _run_clear(args.type) |
| 215 | elif args.command == "search": |
| 216 | _run_search( |
| 217 | args.path, |
| 218 | args.query, |
| 219 | args.top_k, |
| 220 | _resolve_content(args.content, args.include_text_files), |
| 221 | args.max_snippet_lines, |
| 222 | ) |
| 223 | elif args.command == "find-related": |