#include "../src/cli/cli.h" #include "../src/shell/sandbox.h" #include "../src/shell/session.h" #include "../src/shell/pty.h" #include "../src/shell/spinner.h" #include "../src/shell/livestream.h" #include "../src/shell/lanes.h" #include "../src/llm/llm.h" #include "../src/util/ansi.h" #include "../src/util/text.h" #include "../src/config/config.h" #include "../src/config/consts.h" #include #include #include using detz::llm::ChatClient; using detz::llm::ChatRequest; int main() { detz::cli::Parser p; const char* a0 = "detz"; auto c = p.parse(1, (char**)&a0); assert(c.name == "--help"); assert(c.run() == 0); // shell detz::shell::Sandbox sb("/tmp", {"echo"}); auto r = sb.run("echo hi"); assert(r.code == 0 && r.out.find("hi") != std::string::npos); auto denied = sb.run("rm -rf /"); assert(denied.code == 126); assert(!detz::shell::curl_hint("http://x").empty()); detz::shell::ShellSession sh; auto e = sh.exec("echo ok"); assert(e.out.find("ok") != std::string::npos); assert(sh.target_paths("a:b").size() == 2); assert(sh.segment_targets({"a"}).size() == 1); detz::shell::PtyProc pty; assert(pty.spawn("echo pty") && pty.read_all().find("pty") != std::string::npos); detz::shell::Spinner sp("x"); sp.tick(); sp.done(); assert(sp.ticks() == 2); detz::shell::LiveStream ls; ls.push("a"); ls.push("b"); assert(ls.joined() == "ab"); int n = 0; ls.drain([&](const std::string&) { ++n; return true; }); assert(n == 2); detz::shell::LaneBoard lb; lb.set("a", "1"); lb.set("a", "2"); assert(lb.size() == 1 && lb.render().find("2") != std::string::npos); assert(!detz::shell::Glow::highlight("t").empty()); assert(detz::shell::speak_text("hi") == "hi"); // llm mocked transport auto mock = [](const std::string&, const std::string&, const std::map&) { return std::string("{\"content\":\"hello\"}"); }; ChatClient cc("openai", "m", mock); auto cr = cc.chat(ChatRequest{"m", {{"user", "hi"}}, false}); assert(cr.text == "hello"); auto smock = [](const std::string&, const std::string&, const std::map&) { return std::string("data: {\"content\":\"a\"}\n\ndata: [DONE]\n\n"); }; ChatClient cs("anthropic", "m", smock); std::vector got; cs.chat_stream(ChatRequest{"m", {}, true}, [&](const std::string& d) { got.push_back(d); return true; }); assert(got.size() == 1); bool threw = false; try { ChatClient bad("openai", "m"); bad.chat(ChatRequest{}); } catch (const detz::llm::BackendError&) { threw = true; } assert(threw); detz::llm::ModelHealth h; h.record("a", false, 5); h.record("b", true, 9); assert(h.size() == 2 && h.best()->model == "b"); assert(detz::llm::provider_names().find("openrouter") != std::string::npos); assert(detz::llm::provider_info("xai").base_url.find("x.ai") != std::string::npos); detz::llm::Opencode oc("http://localhost:9", mock); assert(oc.complete("m", {}).text == "hello"); bool be = false; try { detz::llm::Opencode no; no.complete("m", {}); } catch (const detz::llm::BackendError&) { be = true; } assert(be); // M2 util+config assert(detz::Consts::kTotalStepCap == 500 && detz::Consts::kAuditMaxChars == 20000); assert(std::string(detz::kDefaultModel) == "muse"); assert(!detz::ZenFreeModels().empty() && !detz::PollinationsModels().empty()); assert(detz::Paint("x", detz::Ansi::kRed).find("x") != std::string::npos); assert(detz::Truncate("abc", 1500, 500) == "abc"); std::string big(3000, 'a'); assert(detz::Truncate(big, 100, 100).find("chars truncated") != std::string::npos); assert(detz::TruncMarker(5).find("5") != std::string::npos); assert(detz::CappedText("hi") == "hi"); assert(detz::ChunkLines("").empty()); assert(detz::ChunkLines("a\nb").size() == 1); assert(detz::CollapseRepeatedLines("x\nx\nx").find("repeated 2") != std::string::npos); assert(detz::CollapseRepeatedLines("a\nb").find("repeated") == std::string::npos); { auto [tags, rest] = detz::SplitLeadingTags("@a @b hello"); assert(tags.size() == 2 && rest == "hello"); } { auto [tags, rest] = detz::SplitLeadingTags("hi"); assert(tags.empty() && rest == "hi"); } { auto dir = std::filesystem::temp_directory_path().string(); std::string f = dir + "/detz_m2_test.txt"; FILE* fh = std::fopen(f.c_str(), "w"); std::fputs("x", fh); std::fclose(fh); assert(detz::ExpandFileMentions("@detz_m2_test.txt", dir).find("detz_m2_test") != std::string::npos); assert(detz::ExpandFileMentions("see @nope-missing-xyz", dir).find("@nope") != std::string::npos); auto cf = detz::CompleteFiles("detz_m2_test", dir); assert(!cf.empty()); assert(detz::CompleteFiles("zzz-no-match-xyz", dir).empty()); std::filesystem::remove(f); } { detz::Config cfg = detz::Config::FromEnv(); assert(!cfg.model.empty()); assert(!detz::SettingsCatalog().empty()); assert(!detz::SplitModels("a, b;c").empty()); auto ids = detz::KnownModelIds(cfg); assert(!ids.empty()); auto rt = detz::ResolveTag("auto", {}, ids, "/tmp"); assert(rt.first == "auto"); auto ru = detz::ResolveTag("zzz-unknown-xyz", {}, ids, "/tmp"); assert(ru.first == "unknown"); std::map bots = {{"bob", "BotBob"}}; auto rb = detz::ResolveTag("bob", bots, ids, "/tmp"); assert(rb.first == "bot"); } std::puts("M2 OK"); std::puts("M4+M5 OK"); return 0; }