169 lines
9.1 KiB
C++
169 lines
9.1 KiB
C++
#include "cli.h"
|
|
#include "version.hpp"
|
|
#include <cstdio>
|
|
#include <string>
|
|
namespace detz::cli {
|
|
std::string Parser::helpText() {
|
|
return std::string(
|
|
std::string(
|
|
"usage: tai [-h] [--profile PROFILE] [--yes] [--yolo] [--auto] [--continue]\n"
|
|
" [--debug [SINK]] [--debug-format FORMAT] [--env ENV]\n"
|
|
" [--no-opencode] [--update-models] [--eval-retrieval] [--stats-rag]\n"
|
|
" [--version] [--cap-manifest] [--cap-speak] [--cap-cwd DIR]\n"
|
|
" [--cap-model MODEL]\n"
|
|
" [--cap-permission-mode {none,confirm,interactive}]\n"
|
|
" [--cap-max-turns N] [--cap ...] [--serve-mcp KEY] [--mcp-port PORT]\n"
|
|
" [--mcp-bind HOST] [--telegram] [--scheduler] [--install]\n"
|
|
" [--install-telegram] [--uninstall-telegram] [--plexer-wrap]\n"
|
|
" [--mplex ...] [--demo] [--demo-shot] [--tui] [--tui-local]\n"
|
|
" [--theme NAME]\n"
|
|
" [prompt ...]\n"
|
|
"\n"
|
|
"single-file autonomous agent, standard library only\n"
|
|
"\n"
|
|
"positional arguments:\n"
|
|
" prompt\n"
|
|
"\n"
|
|
"options:\n"
|
|
" -h, --help show this help message and exit\n"
|
|
" --profile PROFILE\n"
|
|
" --yes\n"
|
|
" --yolo\n"
|
|
" --auto\n"
|
|
" --continue\n"
|
|
" --debug [SINK] extensive debug logging to <home>/debug.log (file),\n"
|
|
" stdout, or stderr, plus the vault logs table (see\n"
|
|
" logging.md)\n"
|
|
" --debug-format FORMAT\n"
|
|
" debug log line format, sentence or json (default\n"
|
|
" sentence, or TAI_DEBUG_FORMAT)\n"
|
|
" --env ENV\n"
|
|
" --no-opencode skip the opencode CLI backends for this run (same as\n"
|
|
" TAI_OPENCODE=0)\n"
|
|
" --update-models rediscover the free model lists of every provider,\n"
|
|
" drop models that are gone, and exit\n"
|
|
" --eval-retrieval score vault retrieval (Hit@K, MRR, nDCG, Context\n"
|
|
" Precision) on generated goldens plus implicit pairs,\n"
|
|
" print the report, and exit\n"
|
|
" --stats-rag print RAG usage and effectiveness stats (vault totals,\n"
|
|
" searches, reads, per-record context uses, retrieval\n"
|
|
" eval) and exit\n"
|
|
" --version\n"
|
|
" --cap-manifest print tai's CAP agent manifest (cap-agent.toml) and\n"
|
|
" exit\n"
|
|
" --cap-speak speak CAP stream-json on stdio as an agent (bulk\n"
|
|
" session config via CAP_SESSION_CONFIG)\n"
|
|
" --cap-cwd DIR speak session working directory (overrides\n"
|
|
" CAP_SESSION_CONFIG cwd)\n"
|
|
" --cap-model MODEL speak session model label (overrides\n"
|
|
" CAP_SESSION_CONFIG model)\n"
|
|
" --cap-permission-mode {none,confirm,interactive}\n"
|
|
" speak session permission mode (overrides\n"
|
|
" CAP_SESSION_CONFIG permission_mode)\n"
|
|
" --cap-max-turns N speak session turn cap (overrides CAP_SESSION_CONFIG\n"
|
|
" max_turns)\n"
|
|
" --cap ... orchestrator: resolve, chat or run fleet commands (see\n"
|
|
" cap.md)\n"
|
|
" --serve-mcp KEY serve MCP over HTTP (Streamable HTTP): all native\n"
|
|
" tools plus chat/completions, Bearer KEY required (see\n"
|
|
" mcp.md)\n"
|
|
" --mcp-port PORT serve-mcp port (default TAI_MCP_PORT else 8765)\n"
|
|
" --mcp-bind HOST serve-mcp bind address (default TAI_MCP_BIND else\n"
|
|
" 127.0.0.1)\n"
|
|
" --telegram\n"
|
|
" --scheduler\n"
|
|
" --install\n"
|
|
" --install-telegram\n"
|
|
" --uninstall-telegram\n"
|
|
" --plexer-wrap internal: invoked by the bashrc plexer hook, not meant\n"
|
|
" to be run by hand\n"
|
|
" --mplex ... terminal multiplexer: any mplex command (new-session,\n"
|
|
" attach-session, list-keys ...); bare --mplex starts a\n"
|
|
" session. Config: ~/.tai/mplex.toml\n"
|
|
" --demo run the fullscreen TUI framework showcase\n"
|
|
" --demo-shot print one composed demo frame as text and exit\n"
|
|
" --tui run the fullscreen grr client (bots, chats,\n"
|
|
" automations, library, projects, settings) against the\n"
|
|
" grr server; address in GRR_URL\n"
|
|
" --tui-local run the fullscreen Telegram-style chat UI on the local\n"
|
|
" vault, no server needed\n"
|
|
" --theme NAME TUI theme: dark, light, nord, gruvbox, ansi (or\n"
|
|
" TAI_THEME)\n")
|
|
+ std::string("\n version ") + std::string(kVersion) + std::string("\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
Options Parser::parseOpts(int argc, char** argv) {
|
|
Options o;
|
|
for (int i = 1; i < argc; ++i) {
|
|
std::string a = argv[i];
|
|
auto nxt = [&](std::optional<std::string>& f) { if (i+1 < argc) f = argv[++i]; };
|
|
if (a=="--profile") nxt(o.profile);
|
|
else if (a=="--yes") o.yes = true;
|
|
else if (a=="--yolo") o.yolo = true;
|
|
else if (a=="--auto") o.auto_ = true;
|
|
else if (a=="--continue") o.resume = true;
|
|
else if (a=="--debug") { o.debug = (i+1<argc && argv[i+1][0]!='-') ? argv[++i] : "file"; }
|
|
else if (a=="--debug-format") nxt(o.debug_format);
|
|
else if (a=="--env") nxt(o.env);
|
|
else if (a=="--no-opencode") o.no_opencode = true;
|
|
else if (a=="--update-models") o.update_models = true;
|
|
else if (a=="--eval-retrieval") o.eval_retrieval = true;
|
|
else if (a=="--stats-rag") o.stats_rag = true;
|
|
else if (a=="--version") o.version = true;
|
|
else if (a=="--cap-manifest") o.cap_manifest = true;
|
|
else if (a=="--cap-speak") o.cap_speak = true;
|
|
else if (a=="--cap-cwd") nxt(o.cap_cwd);
|
|
else if (a=="--cap-model") nxt(o.cap_model);
|
|
else if (a=="--cap-permission-mode") nxt(o.cap_permission_mode);
|
|
else if (a=="--cap-max-turns") { if (i+1<argc) o.cap_max_turns = std::stoi(argv[++i]); }
|
|
else if (a=="--cap") { o.cap = std::vector<std::string>{}; while (++i<argc) o.cap->push_back(argv[i]); break; }
|
|
else if (a=="--serve-mcp") nxt(o.serve_mcp);
|
|
else if (a=="--mcp-port") { if (i+1<argc) o.mcp_port = std::stoi(argv[++i]); }
|
|
else if (a=="--mcp-bind") nxt(o.mcp_bind);
|
|
else if (a=="--telegram") o.telegram = true;
|
|
else if (a=="--scheduler") o.scheduler = true;
|
|
else if (a=="--install") o.install = true;
|
|
else if (a=="--install-telegram") o.install_telegram = true;
|
|
else if (a=="--uninstall-telegram") o.uninstall_telegram = true;
|
|
else if (a=="--plexer-wrap") o.plexer_wrap = true;
|
|
else if (a=="--mplex") { o.mplex = std::vector<std::string>{}; while (++i<argc) o.mplex->push_back(argv[i]); break; }
|
|
else if (a=="--demo") o.demo = true;
|
|
else if (a=="--demo-shot") o.demo_shot = true;
|
|
else if (a=="--model") { if(i+1<argc) o.model=argv[++i]; }
|
|
else if (a=="--driver") { if(i+1<argc) o.driver=argv[++i]; }
|
|
else if (a=="--task") { if(i+1<argc) o.task=argv[++i]; }
|
|
else if (a=="--cwd") { if(i+1<argc) o.cwd=argv[++i]; }
|
|
else if (a=="--argv") { if(i+1<argc) o.argv=argv[++i]; }
|
|
else if (a=="--binary") { if(i+1<argc) o.binary=argv[++i]; }
|
|
else if (a=="--max-risk") { if(i+1<argc) o.max_risk=argv[++i]; }
|
|
else if (a=="--auto-answer") { if(i+1<argc) o.auto_answer=argv[++i]; }
|
|
else if (a=="--allow-tool") { if(i+1<argc) o.allow_tool.push_back(argv[++i]); }
|
|
else if (a=="--deny-tool") { if(i+1<argc) o.deny_tool.push_back(argv[++i]); }
|
|
else if (a=="--tui") o.tui = true;
|
|
else if (a=="--tui-local") o.tui_local = true;
|
|
else if (a=="--theme") nxt(o.theme);
|
|
else if (a=="--help"||a=="-h") o.help = true;
|
|
else if (!a.empty() && a[0]=='-') { /* unknown flag: ignore */ }
|
|
else o.prompt.push_back(a);
|
|
}
|
|
return o;
|
|
}
|
|
Command Parser::parse(int argc, char** argv) {
|
|
Command c; c.opts = parseOpts(argc, argv);
|
|
if (c.opts.help || argc<=1) c.name = "--help";
|
|
else if (c.opts.version) c.name = "--version";
|
|
else c.name = "run";
|
|
for (int i=1;i<argc;++i) c.args.emplace_back(argv[i]);
|
|
return c;
|
|
}
|
|
int Command::run() {
|
|
if (opts.version || name=="--version") { std::puts(("tai " + std::string(kVersion)).c_str()); return 0; }
|
|
std::fputs(Parser::helpText().c_str(), stdout);
|
|
return 0;
|
|
}
|
|
int DetzCli::run(int argc, char** argv) { return Parser{}.parse(argc, argv).run(); }
|
|
} // namespace detz::cli
|