// Scenario runner for tests/foundation_parity.py: replays a JSON list of // Store operations against a real vault in $TAI_HOME and prints the results as // sorted-key JSON. The python side replays the same scenario through tai.py; // the driver diffs both results and both vault dumps. // // Usage: foundation_probe (needs TAI_HOME, TAI_SESSION) #include #include #include #include #include #include #include #include "config/config.h" #include "config/prompts.h" #include "config/settings_rules.h" #include #include #include #include "plexer/flow_validator.h" #include "plexer/plexer.h" #include "repl/repl.h" #include "repl/repl_style.h" #include "session/conversation.h" #include "store/debuglog.h" #include "plexer/plexer_flow.h" #include "session/shell_context.h" #include "store/fts.h" #include "store/patterns.h" #include "store/tag_rules.h" #include "store/json.h" #include "store/spill.h" #include "store/store.h" using detz::Config; using detz::store::Json; using detz::store::NullSeal; using detz::store::Store; namespace { struct Args { const Json* pos; const Json* kw; const Json* get(size_t i, const char* name) const { if (pos && pos->is_array() && i < pos->size()) return &pos->items()[i]; if (kw && kw->is_object()) return kw->find(name); return nullptr; } bool present(size_t i, const char* name) const { const Json* v = get(i, name); return v != nullptr; } std::string str(size_t i, const char* name, const std::string& d = "") const { const Json* v = get(i, name); return (v && v->is_string()) ? v->as_string() : d; } long long num(size_t i, const char* name, long long d) const { const Json* v = get(i, name); return (v && v->is_number()) ? v->as_int() : d; } std::vector list(size_t i, const char* name) const { std::vector out; const Json* v = get(i, name); if (v && v->is_array()) for (auto& x : v->items()) out.push_back(x.as_string()); return out; } Json json(size_t i, const char* name) const { const Json* v = get(i, name); return v ? *v : Json(); } bool is_null(size_t i, const char* name) const { const Json* v = get(i, name); return !v || v->is_null(); } std::optional opt_str(size_t i, const char* name) const { const Json* v = get(i, name); if (!v || v->is_null()) return std::nullopt; return v->as_string(); } }; Json strs(const std::vector& v) { Json a = Json::array(); for (auto& s : v) a.push(Json(s)); return a; } Json arr(const std::vector& v) { Json a = Json::array(); for (auto& s : v) a.push(s); return a; } Json opt(const std::optional& v) { return v ? *v : Json(); } Json opt_s(const std::optional& v) { return v ? Json(*v) : Json(); } Json value_json(const detz::SettingValue& v) { switch (v.kind) { case detz::SettingValue::Kind::Null: return Json(); case detz::SettingValue::Kind::Bool: return Json(v.b); case detz::SettingValue::Kind::Float: return Json(v.d); default: return Json(v.s); } } Json setting_json(const detz::store::SettingRow& r) { Json o = Json::object(); o.set("key", r.key); o.set("scope", r.scope); o.set("type", r.type); o.set("default", value_json(r.def)); o.set("required", r.required); o.set("nullable", r.nullable); o.set("options", r.has_options ? strs(r.options) : Json()); o.set("preferred", Json()); o.set("encrypted", r.encrypted); o.set("env", r.env); o.set("desc", r.desc); o.set("stored", opt_s(r.stored)); o.set("value", value_json(r.value)); o.set("source", r.source); o.set("created", opt_s(r.created)); o.set("updated", opt_s(r.updated)); return o; } Json rows_json(const std::vector& rows) { Json a = Json::array(); for (auto& r : rows) a.push(setting_json(r)); return a; } Json events_json(const std::vector& rows) { Json a = Json::array(); for (auto& r : rows) a.push(arr({Json(r.ts), Json(r.role), Json(r.kind), Json(r.text)})); return a; } using Handler = std::function; std::map handlers() { std::map h; h["add_record"] = [](Store& s, const Args& a) { return Json(s.add_record(a.str(0, "kind"), a.str(1, "title"), a.str(2, "content"), a.list(3, "tags"), a.str(4, "profile"))); }; h["get_record"] = [](Store& s, const Args& a) { return opt(s.get_record(a.str(0, "record_id"), a.str(1, "profile"))); }; h["read_record"] = [](Store& s, const Args& a) { return opt(s.read_record(a.str(0, "record_id"), a.num(1, "offset", 0), a.num(2, "limit", 4000), a.str(3, "profile"))); }; h["search_records"] = [](Store& s, const Args& a) { return arr(s.search_records(a.str(0, "query"), a.str(1, "kind"), a.list(2, "tags"), static_cast(a.num(3, "limit", 8)), a.str(4, "profile"))); }; h["delete_record"] = [](Store& s, const Args& a) { return Json(s.delete_record(a.str(0, "record_id"), a.str(1, "profile"))); }; h["save_secret"] = [](Store& s, const Args& a) { std::optional> tags; if (!a.is_null(3, "tags")) tags = a.list(3, "tags"); s.save_secret(a.str(0, "name"), a.str(1, "value"), a.json(2, "meta"), tags, a.str(4, "profile")); return Json(); }; h["secret_meta"] = [](Store& s, const Args& a) { return s.secret_meta(a.str(0, "name"), a.str(1, "profile")); }; h["list_secret_infos"] = [](Store& s, const Args& a) { return arr(s.list_secret_infos(a.str(0, "profile"))); }; h["load_secret"] = [](Store& s, const Args& a) { return opt_s(s.load_secret(a.str(0, "name"), a.str(1, "profile"))); }; h["delete_secret"] = [](Store& s, const Args& a) { return Json(s.delete_secret(a.str(0, "name"), a.str(1, "profile"))); }; h["redact"] = [](Store& s, const Args& a) { return Json(s.redact(a.str(0, "text"), a.str(1, "profile"))); }; h["known_tags"] = [](Store& s, const Args& a) { auto t = s.known_tags(a.str(0, "profile")); return strs(std::vector(t.begin(), t.end())); }; h["canonical_tags"] = [](Store& s, const Args& a) { return strs(s.canonical_tags(a.list(0, "tags"), nullptr, a.str(2, "profile"))); }; h["tag_counts"] = [](Store& s, const Args& a) { Json out = Json::array(); for (auto& [t, n] : s.tag_counts(a.str(0, "prefix"), static_cast(a.num(1, "limit", 50)), a.str(2, "profile"))) out.push(arr({Json(t), Json(static_cast(n))})); return out; }; h["tag_item"] = [](Store& s, const Args& a) { s.tag_item(a.str(0, "item"), a.list(1, "tags"), a.str(2, "profile")); return Json(); }; h["set_item_tags"] = [](Store& s, const Args& a) { s.set_item_tags(a.str(0, "item"), a.list(1, "tags"), a.str(2, "profile")); return Json(); }; h["item_tags"] = [](Store& s, const Args& a) { return strs(s.item_tags(a.str(0, "item"), a.str(1, "profile"))); }; h["tagged_items"] = [](Store& s, const Args& a) { auto r = s.tagged_items(a.list(0, "tags"), a.str(1, "profile")); return r ? strs(*r) : Json(); }; h["add_edge"] = [](Store& s, const Args& a) { try { return Json(s.add_edge(a.str(0, "src"), a.str(1, "dst"), a.str(2, "relation", "linked"), a.str(3, "profile"))); } catch (const detz::store::ValueError& e) { Json o = Json::object(); o.set("ValueError", e.what()); return o; } }; h["edges_for"] = [](Store& s, const Args& a) { return arr(s.edges_for(a.str(0, "node"), a.str(1, "profile"))); }; h["remove_edges"] = [](Store& s, const Args& a) { return Json(static_cast(s.remove_edges(a.str(0, "node"), a.str(1, "profile")))); }; h["traverse"] = [](Store& s, const Args& a) { return arr(s.traverse(a.str(0, "start"), static_cast(a.num(1, "depth", 2)), static_cast(a.num(2, "limit", 50)), a.str(3, "profile"))); }; h["add_chunks"] = [](Store& s, const Args& a) { s.add_chunks(a.str(0, "parent_kind"), a.str(1, "parent_id"), a.list(2, "texts"), a.str(3, "profile")); return Json(); }; h["get_chunks_by_ids"] = [](Store& s, const Args& a) { std::vector ids; const Json* v = a.get(0, "ids"); if (v && v->is_array()) for (auto& x : v->items()) ids.push_back(x.as_int()); Json o = Json::object(); for (auto& [id, d] : s.get_chunks_by_ids(ids, a.str(1, "profile"))) o.set(std::to_string(id), d); return o; }; h["audit_event"] = [](Store& s, const Args& a) { return Json(static_cast(s.audit_event(a.str(0, "actor"), a.str(1, "action"), a.str(2, "path"), a.str(3, "message"), a.opt_str(4, "old"), a.opt_str(5, "new"), a.list(6, "tags"), a.is_null(7, "old_size") ? -1 : a.num(7, "old_size", -1), a.is_null(8, "new_size") ? -1 : a.num(8, "new_size", -1), a.str(9, "profile")))); }; h["audit_history"] = [](Store& s, const Args& a) { return arr(s.audit_history(a.str(0, "path"), a.str(1, "tag"), static_cast(a.num(2, "limit", 20)), a.str(3, "profile"))); }; h["audit_get"] = [](Store& s, const Args& a) { return opt(s.audit_get(a.num(0, "row_id", 0), a.str(1, "profile"))); }; h["audit_search"] = [](Store& s, const Args& a) { return arr(s.audit_search(a.str(0, "query"), a.str(1, "profile"), static_cast(a.num(2, "limit", 20)))); }; h["upsert_file_record"] = [](Store& s, const Args& a) { return Json(s.upsert_file_record(a.str(0, "path"), a.str(1, "content"), a.is_null(2, "true_size") ? -1 : a.num(2, "true_size", -1), a.str(3, "profile"))); }; h["file_record_id"] = [](Store& s, const Args& a) { return opt_s(s.file_record_id(a.str(0, "path"), a.str(1, "profile"))); }; h["delete_file_record"] = [](Store& s, const Args& a) { return Json(s.delete_file_record(a.str(0, "path"), a.str(1, "profile"))); }; h["log_event"] = [](Store& s, const Args& a) { s.log_event(a.str(0, "profile"), a.str(1, "role"), a.str(2, "kind"), a.str(3, "text"), a.list(4, "tags")); return Json(); }; h["search_events"] = [](Store& s, const Args& a) { return events_json(s.search_events(a.str(0, "profile"), a.str(1, "query"), static_cast(a.num(2, "limit", 8)), a.list(3, "tags"))); }; h["events_like"] = [](Store& s, const Args& a) { return events_json(s.events_like(a.str(0, "profile"), a.str(1, "query"), static_cast(a.num(2, "limit", 8)), a.list(3, "tags"))); }; h["history_add"] = [](Store& s, const Args& a) { return Json(s.history_add(a.str(0, "profile"), a.str(1, "bot"), a.str(2, "text"))); }; h["history_load"] = [](Store& s, const Args& a) { return strs(s.history_load(a.str(0, "profile"), static_cast(a.num(1, "limit", 1000)))); }; h["history_last"] = [](Store& s, const Args& a) { return opt_s(s.history_last(a.str(0, "profile"))); }; h["add_schedule"] = [](Store& s, const Args& a) { std::optional> tags; if (!a.is_null(6, "tags")) tags = a.list(6, "tags"); return Json(static_cast(s.add_schedule(a.str(0, "name"), a.str(1, "prompt"), a.str(2, "profile"), a.num(3, "every_sec", 0), a.str(4, "next_run"), a.num(5, "timeout", 0), tags))); }; h["remove_schedule"] = [](Store& s, const Args& a) { return Json(s.remove_schedule(a.num(0, "row_id", 0), a.str(1, "profile"))); }; h["list_schedules"] = [](Store& s, const Args& a) { return arr(s.list_schedules(a.str(0, "profile"))); }; h["fts_search"] = [](Store& s, const Args& a) { Json out = Json::array(); for (auto& hit : s.fts_search(a.str(0, "query"), a.list(1, "kinds"), a.str(2, "profile"), static_cast(a.num(3, "limit", 10)))) { Json o = Json::object(); if (hit.item_numeric) o.set("item", static_cast(std::stoll(hit.item))); else o.set("item", hit.item); o.set("kind", hit.kind); o.set("sub", hit.sub); o.set("title", hit.title); o.set("snippet", hit.snippet); o.set("rank", hit.rank); out.push(o); } return out; }; h["save_system"] = [](Store& s, const Args& a) { s.save_system(a.str(0, "name"), a.str(1, "text")); return Json(); }; h["load_system"] = [](Store& s, const Args& a) { return opt_s(s.load_system(a.str(0, "name"))); }; h["save_session"] = [](Store& s, const Args& a) { std::vector msgs; const Json* v = a.get(1, "messages"); if (v && v->is_array()) msgs = v->items(); s.save_session(a.str(0, "name"), msgs, a.str(2, "bot", "main"), a.str(3, "ctx")); return Json(); }; h["load_session"] = [](Store& s, const Args& a) { return arr(s.load_session(a.str(0, "name"), a.str(1, "bot", "main"), a.str(2, "ctx"))); }; h["save_turn_state"] = [](Store& s, const Args& a) { s.save_turn_state(a.str(0, "profile"), a.str(1, "bot"), a.json(2, "state"), a.str(3, "ctx")); return Json(); }; h["load_turn_state"] = [](Store& s, const Args& a) { return s.load_turn_state(a.str(0, "profile"), a.str(1, "bot", "main"), a.str(2, "ctx")); }; h["save_bots"] = [](Store& s, const Args& a) { s.save_bots(a.str(0, "profile"), a.json(1, "bots")); return Json(); }; h["load_bots"] = [](Store& s, const Args& a) { return s.load_bots(a.str(0, "profile")); }; h["list_bots"] = [](Store& s, const Args& a) { return arr(s.list_bots(a.str(0, "profile"))); }; h["resolve_bot"] = [](Store& s, const Args& a) { return opt_s(s.resolve_bot(a.str(0, "profile"), a.str(1, "mention"))); }; h["save_bot_system"] = [](Store& s, const Args& a) { s.save_bot_system(a.str(0, "profile"), a.str(1, "bot"), a.str(2, "text")); return Json(); }; h["load_bot_system"] = [](Store& s, const Args& a) { return opt_s(s.load_bot_system(a.str(0, "profile"), a.str(1, "bot"))); }; h["list_profiles"] = [](Store& s, const Args&) { return strs(s.list_profiles()); }; h["get_or_create_settings"] = [](Store& s, const Args& a) { try { std::optional> keys; if (!a.is_null(0, "keys")) { const Json* v = a.get(0, "keys"); keys = v->is_string() ? std::vector{v->as_string()} : a.list(0, "keys"); } return rows_json(s.get_or_create_settings(keys, a.str(1, "scope", "global"))); } catch (const detz::store::ValueError& e) { Json o = Json::object(); o.set("ValueError", e.what()); return o; } }; h["get_all_settings"] = [](Store& s, const Args& a) { try { return rows_json(s.get_all_settings(a.str(0, "scope", "global"))); } catch (const detz::store::ValueError& e) { Json o = Json::object(); o.set("ValueError", e.what()); return o; } }; h["upsert_settings"] = [](Store& s, const Args& a) { try { std::map items; Json v = a.json(0, "items"); if (v.is_object()) for (auto& m : v.members()) items[m.first] = m.second; return rows_json(s.upsert_settings(items, a.str(1, "scope", "global"))); } catch (const detz::store::ValueError& e) { Json o = Json::object(); o.set("ValueError", e.what()); return o; } }; h["mcp_save_server"] = [](Store& s, const Args& a) { try { s.mcp_save_server(a.json(0, "entry")); return Json(); } catch (const detz::store::ValueError& e) { Json o = Json::object(); o.set("ValueError", e.what()); return o; } }; h["mcp_get_server"] = [](Store& s, const Args& a) { return opt(s.mcp_get_server(a.str(0, "name"))); }; h["mcp_list_servers"] = [](Store& s, const Args&) { return arr(s.mcp_list_servers()); }; h["mcp_remove_server"] = [](Store& s, const Args& a) { s.mcp_remove_server(a.str(0, "name")); return Json(); }; h["mcp_set_enabled"] = [](Store& s, const Args& a) { const Json* v = a.get(2, "enabled"); s.mcp_set_enabled(a.str(0, "server"), a.str(1, "profile"), v && v->is_bool() && v->as_bool()); return Json(); }; h["mcp_server_enabled"] = [](Store& s, const Args& a) { return Json(s.mcp_server_enabled(a.str(0, "server"), a.str(1, "profile"))); }; h["mcp_enabled_servers"] = [](Store& s, const Args& a) { return arr(s.mcp_enabled_servers(a.str(0, "profile"))); }; h["mcp_store_tools"] = [](Store& s, const Args& a) { std::vector tools; const Json* v = a.get(1, "tools"); if (v && v->is_array()) tools = v->items(); s.mcp_store_tools(a.str(0, "server"), tools); return Json(); }; h["mcp_cached_tools"] = [](Store& s, const Args& a) { return arr(s.mcp_cached_tools(a.str(0, "server"))); }; h["mcp_tool_pins"] = [](Store& s, const Args& a) { Json o = Json::object(); for (auto& [k, v] : s.mcp_tool_pins(a.str(0, "server"))) o.set(k, v); return o; }; h["load_dir_defaults"] = [](Store& s, const Args& a) { Json o = Json::object(); for (auto& [k, v] : s.load_dir_defaults(a.str(0, "directory"))) o.set(k, v); return o; }; h["save_dir_defaults"] = [](Store& s, const Args& a) { s.save_dir_defaults(a.str(0, "directory"), a.str(1, "provider"), a.str(2, "model"), a.str(3, "bot"), a.list(4, "clear")); return Json(); }; h["spill_or_truncate"] = [](Store& s, const Args& a) { return Json(detz::store::Spill::spill_or_truncate(&s, a.str(0, "kind"), a.str(1, "title"), a.str(2, "text"), a.list(3, "tags"), a.str(4, "profile"))); }; return h; } // Replays scripted replies for PlexerFlow and logs every screen it was asked. class FakeController : public detz::plexer::PlexerController { public: explicit FakeController(Json replies) : replies_(std::move(replies)) {} Json send_keys(const std::string&, bool) override { return Json(); } Json read_pane(int) override { return Json(""); } Json status() override { return Json(); } Json ask(const Json& screen, const Json&) override { asked.push(screen); Json r = replies_.items()[next_++]; return r; } Json asked = Json::array(); private: Json replies_; size_t next_{0}; }; Json err_json(const char* what) { Json o = Json::object(); o.set("ValueError", what); return o; } // Captures everything written to fd 1 while alive (the REPL prints with printf). class StdoutCapture { public: StdoutCapture() { std::fflush(stdout); saved_ = ::dup(1); file_ = std::tmpfile(); ::dup2(::fileno(file_), 1); } std::string finish() { std::fflush(stdout); ::dup2(saved_, 1); ::close(saved_); std::string out; std::rewind(file_); char buf[4096]; size_t n; while ((n = std::fread(buf, 1, sizeof buf, file_)) > 0) out.append(buf, n); std::fclose(file_); return out; } private: int saved_; std::FILE* file_; }; class NullHost : public detz::repl::ReplHost { public: std::string run_turn(const std::string&) override { return ""; } }; void add_pure_handlers(std::map& h) { using namespace detz; h["statusbar"] = [](Store&, const Args& a) { return Json(repl::ReplStyle::statusbar(a.str(0, "version"), a.str(1, "profile"), a.str(2, "directory"), a.json(3, "yolo").as_bool(), static_cast(a.num(4, "agents", 0)), static_cast(a.num(5, "width", 0)))); }; h["strip_ansi"] = [](Store&, const Args& a) { return Json(repl::ReplStyle::strip_ansi(a.str(0, "text"))); }; h["truncate_ansi"] = [](Store&, const Args& a) { return Json(repl::ReplStyle::truncate_ansi(a.str(0, "text"), static_cast(a.num(1, "width", 0)))); }; h["glow_prompt"] = [](Store&, const Args&) { return Json(repl::ReplStyle::glow_prompt()); }; h["glow_title"] = [](Store&, const Args& a) { return Json(repl::ReplStyle::glow_title(a.str(0, "version"), a.str(1, "profile"))); }; h["sleep"] =[](Store&, const Args& a) { std::this_thread::sleep_for(std::chrono::duration(a.json(0, "seconds").as_double())); return Json(); }; h["native_ctl"] = [](Store&, const Args& a) { plexer::NativePlexerController ctl(a.str(0, "sock"), a.str(1, "pane")); std::string method = a.str(2, "method"); Json args = a.json(3, "args"); try { if (method == "type_text") { ctl.type_text(args.items()[0].as_string(), 0.0, args.items()[1].as_bool()); return Json(); } if (method == "call") return ctl.call(args.items()[0]); if (method == "send_keys") return ctl.send_keys(args.items()[0].as_string(), args.items()[1].as_bool()); if (method == "read_pane") return ctl.read_pane(static_cast(args.items()[0].as_int())); if (method == "status") return ctl.status(); return ctl.ask(args.items()[0], args.items()[1]); } catch (const plexer::PlexerError& e) { Json o = Json::object(); o.set("PlexerError", e.what()); return o; } }; h["tmux_ctl"] = [](Store&, const Args& a) { plexer::TmuxPlexerController ctl(a.str(0, "pane")); std::string method = a.str(1, "method"); Json args = a.json(2, "args"); try { if (method == "type_text") { ctl.type_text(args.items()[0].as_string(), 0.0, args.items()[1].as_bool()); return Json(); } if (method == "send_keys") return ctl.send_keys(args.items()[0].as_string(), args.items()[1].as_bool()); if (method == "read_pane") return ctl.read_pane(static_cast(args.items()[0].as_int())); if (method == "status") return ctl.status(); return ctl.ask(args.items()[0], args.items()[1]); } catch (const plexer::PlexerError& e) { Json o = Json::object(); o.set("PlexerError", e.what()); return o; } }; h["log_query"] = [](Store& s, const Args& a) { Json f = a.json(0, "filter"); store::LogFilter lf; lf.level = f.get_string("level"); lf.component = f.get_string("component"); lf.event = f.get_string("event"); lf.profile = f.get_string("profile"); lf.bot = f.get_string("bot"); lf.chat = f.get_string("chat"); lf.run = f.get_string("run"); if (const Json* l = f.find("limit")) lf.limit = static_cast(l->as_int()); return arr(s.log_query(lf)); }; h["debug_log"] = [](Store& s, const Args& a) { auto& log = store::DebugLog::Global(); log.configure(a.str(0, "sink"), a.str(1, "fmt"), s.config().home, &s); for (auto& ev : a.json(2, "events").items()) { const auto& it = ev.items(); Json kw = it[4]; log.event(it[0].as_string(), it[1].as_string(), it[2].as_string(), it[3].as_string(), kw.get_string("profile"), kw.get_string("bot"), kw.get_string("chat"), kw.has("meta") ? *kw.find("meta") : Json()); } std::string run = log.run; log.close(); log.reset(); std::ifstream in(s.config().home + "/debug.log", std::ios::binary); std::stringstream ss; ss << in.rdbuf(); return arr({Json(run), Json(ss.str())}); }; h["repl_script"] = [](Store& s, const Args& a) { Config cfg = s.config(); cfg.profile = "default"; const char* tai_session = std::getenv("TAI_SESSION"); session::Conversation conv(s, cfg, true, false, false, tai_session ? tai_session : ""); NullHost host; repl::Repl::Options opts; repl::Repl app(conv, host, opts); Json outputs = Json::array(); for (auto& text : a.json(0, "script").items()) { StdoutCapture cap; bool cont = app.handle_command(text.as_string()); outputs.push(arr({Json(cap.finish()), Json(cont)})); } Json msgs = Json::array(); for (size_t k = 1; k < conv.messages().size(); k++) msgs.push(conv.messages()[k]); return arr({outputs, arr({Json(conv.profile()), Json(conv.bot()), msgs})}); }; h["prompt"] = [](Store&, const Args& a) { std::string n = a.str(0, "name"); if (n == "DEFAULT_SYSTEM") return Json(Prompts::DefaultSystem()); if (n == "MERGE_SYSTEM") return Json(Prompts::MergeSystem()); if (n == "COMPACT_SYSTEM") return Json(Prompts::CompactSystem()); if (n == "AUTONOMOUS_NOTE") return Json(Prompts::AutonomousNote()); if (n == "HELP_TEXT") return Json(Prompts::HelpText()); if (n == "LEGACY_PASSWORD_NOTE") return Json(Prompts::LegacyPasswordNote()); return Json(Prompts::VaultMemoryNote()); }; h["capability_block"] = [](Store&, const Args& a) { return Json(Prompts::CapabilityBlock(a.json(0, "yolo").is_bool() && a.json(0, "yolo").as_bool(), a.json(1, "auto").is_bool() && a.json(1, "auto").as_bool())); }; h["orientation_block"] = [](Store&, const Args& a) { return Json(Prompts::OrientationBlock(a.str(0, "directory"), a.json(1, "sandbox").is_bool() && a.json(1, "sandbox").as_bool())); }; h["settings_catalog"] = [](Store&, const Args&) { Json o = Json::object(); for (auto& [k, s] : SettingsCatalog()) { Json e = Json::object(); e.set("key", s.key); e.set("env", s.env); e.set("type", s.type); e.set("default", value_json(s.def)); e.set("desc", s.help); e.set("required", s.required); e.set("nullable", s.nullable); e.set("encrypted", s.encrypted); e.set("options", s.hasOptions ? strs(s.options) : Json()); e.set("preferred", Json()); e.set("true_words", s.trueWords.empty() ? Json() : strs(s.trueWords)); e.set("false_words", s.falseWords.empty() ? Json() : strs(s.falseWords)); o.set(k, e); } return o; }; h["json_dumps"] = [](Store&, const Args& a) { Json v = a.json(0, "value"); return arr({Json(v.dumps()), Json(v.dumps(true))}); }; h["json_roundtrip"] = [](Store&, const Args& a) { try { return Json(Json::loads(a.str(0, "text")).dumps(true)); } catch (const store::JsonError&) { return err_json("x"); } }; h["float_repr"] = [](Store&, const Args& a) { return Json(Json::float_repr(a.json(0, "v").as_double())); }; h["normalize_tag"] = [](Store&, const Args& a) { return Json(store::TagRules::normalize_tag(a.str(0, "raw"))); }; h["normalize_tags"] = [](Store&, const Args& a) { return strs(store::TagRules::normalize_tags(a.list(0, "items"))); }; h["singular_noun"] = [](Store&, const Args& a) { return Json(store::TagRules::singular_noun(a.str(0, "word"))); }; h["tag_variants"] = [](Store&, const Args& a) { return strs(store::TagRules::tag_variants(a.str(0, "tag"))); }; h["parse_node_id"] = [](Store&, const Args& a) { auto r = store::TagRules::parse_node_id(a.str(0, "raw")); return r ? arr({Json(r->first), Json(r->second)}) : Json(); }; h["fts_match_variants"] = [](Store&, const Args& a) { auto t = store::Fts::escape(a.str(0, "query")); return t ? strs(store::Fts::match_variants(*t)) : Json(); }; h["fts_rank"] = [](Store&, const Args& a) { return Json(store::Fts::rank(a.str(0, "table"))); }; h["profile_re"] = [](Store&, const Args& a) { return Json(store::Patterns::profile(a.str(0, "s"))); }; h["bot_re"] = [](Store&, const Args& a) { return Json(store::Patterns::bot(a.str(0, "s"))); }; h["secret_re"] = [](Store&, const Args& a) { return Json(store::Patterns::secret(a.str(0, "s"))); }; h["mcp_server_re"] = [](Store&, const Args& a) { return Json(store::Patterns::mcp_server(a.str(0, "s"))); }; h["normalize_setting_value"] = [](Store&, const Args& a) { try { auto r = SettingsRules::Normalize(a.str(0, "key"), SettingsCatalog().at(a.str(0, "key")), a.json(1, "value")); return opt_s(r); } catch (const store::ValueError& e) { return err_json(e.what()); } }; h["parse_setting_env"] = [](Store&, const Args& a) { try { return value_json(SettingsRules::ParseEnv(SettingsCatalog().at(a.str(0, "key")), a.str(1, "raw"))); } catch (const store::ValueError& e) { return err_json(e.what()); } }; h["parse_setting_stored"] = [](Store&, const Args& a) { try { return value_json(SettingsRules::ParseStored(SettingsCatalog().at(a.str(0, "key")), a.str(1, "stored"))); } catch (const store::ValueError&) { return err_json("could not convert"); } }; h["parse_backends"] = [](Store&, const Args& a) { Json out = Json::array(); for (auto& b : ParseBackends(a.str(0, "spec"))) { Json o = Json::object(); o.set("label", b.label); o.set("base", b.base); o.set("key", b.key); o.set("model", b.model); o.set("profile", b.profile); out.push(o); } return out; }; h["split_models"] = [](Store&, const Args& a) { return strs(SplitModels(a.str(0, "spec"))); }; h["chunk_lines"] = [](Store&, const Args& a) { return strs(store::Spill::chunk_lines(a.str(0, "text"), static_cast(a.num(1, "max_lines", 60)), static_cast(a.num(2, "overlap_lines", 3)), static_cast(a.num(3, "max_chars", 4000)))); }; h["truncate"] = [](Store&, const Args& a) { return Json(store::Spill::truncate(a.str(0, "text"), static_cast(a.num(1, "head", 1500)), static_cast(a.num(2, "tail", 500)))); }; h["shell_current"] = [](Store&, const Args& a) { std::map env; Json e = a.json(0, "env"); if (e.is_object()) for (auto& m : e.members()) env[m.first] = m.second.as_string(); auto c = session::ShellContext::current(&env, a.num(1, "pid", 0), a.str(2, "proc_root"), a.json(3, "now").as_double(), a.num(4, "clk_tck", 100)); Json chain = Json::array(); for (auto& x : c.chain) { Json o = Json::object(); o.set("pid", static_cast(x.pid)); o.set("ppid", static_cast(x.ppid)); o.set("comm", x.comm); o.set("argv0", x.argv0); o.set("name", x.name); o.set("start", x.start); o.set("start_iso", x.start_iso); o.set("sid", x.sid); chain.push(o); } return arr({Json(c.sid), Json(c.shell), Json(static_cast(c.pid)), Json(c.started), c.parent ? Json(*c.parent) : Json(), chain}); }; h["sanitize_sid"] = [](Store&, const Args& a) { return Json(session::ShellContext::sanitize(a.str(0, "value"))); }; h["validate_flow_spec"] = [](Store&, const Args& a) { auto r = plexer::FlowValidator::spec(a.json(0, "spec")); return arr({r.second.empty() ? r.first : Json(), Json(r.second)}); }; h["run_flow"] = [](Store&, const Args& a) { auto v = plexer::FlowValidator::spec(a.json(0, "spec")); if (!v.second.empty()) return arr({Json(), Json(v.second)}); FakeController fake(a.json(1, "replies")); plexer::PlexerFlow flow(v.first); Json outcome = flow.run(fake); return arr({outcome, fake.asked}); }; } Json substitute(const Json& v, const std::vector& results) { if (v.is_string() && v.as_string().size() > 2 && v.as_string().rfind("$R", 0) == 0) { size_t idx = std::stoul(v.as_string().substr(2)); if (idx < results.size()) return results[idx]; } if (v.is_array()) { Json a = Json::array(); for (auto& x : v.items()) a.push(substitute(x, results)); return a; } if (v.is_object()) { Json o = Json::object(); for (auto& m : v.members()) o.set(m.first, substitute(m.second, results)); return o; } return v; } } // namespace int main(int argc, char** argv) { if (argc < 2) { std::fprintf(stderr, "usage: foundation_probe scenario.json\n"); return 2; } std::ifstream in(argv[1], std::ios::binary); std::stringstream ss; ss << in.rdbuf(); Json scenario = Json::loads(ss.str()); Config config = Config::Build("default", false, false); NullSeal seal; Store store(config, seal); auto table = handlers(); add_pure_handlers(table); std::vector results; for (auto& step : scenario.items()) { std::string op = step.items()[0].as_string(); Json pos = step.size() > 1 ? substitute(step.items()[1], results) : Json::array(); Json kw = step.size() > 2 ? substitute(step.items()[2], results) : Json::object(); auto it = table.find(op); if (it == table.end()) { std::fprintf(stderr, "unknown op %s\n", op.c_str()); return 3; } Args args{&pos, &kw}; results.push_back(it->second(store, args)); } store.close(); Json out = Json::array(); for (auto& r : results) out.push(r); std::cout << out.dumps(true) << std::endl; return 0; }