2026-10-25 05:06:38 +01:00
// C++ side of the differential tests (tests/misc_diff.py): prints the same transcript as tests/misc_py.py.
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <functional>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
#include <map>
#include <sstream>
#include "bundled.h"
#include "bundled_data.h"
#include "audittool.h"
#include "release.h"
#include "chunker.h"
#include "telegram.h"
#include "ragtool.h"
#include "retrievaleval.h"
#include "install.h"
#include "installconsts.h"
#include "ftssearch.h"
#include "miscdatetime.h"
#include "miscjson.h"
#include "miscpy.h"
#include "miscsha256.h"
#include "schedtime.h"
#include "schedtool.h"
#include "schedvault.h"
#include "sqlitedb.h"
#include "scheduler.h"
#include "schedtool.h"
#include "skillfile.h"
#include "skilltool.h"
using detz :: misc :: Json ;
using detz :: misc :: PyFs ;
using detz :: misc :: PyStr ;
namespace sk = detz :: skills ;
static std :: string DATA_DIR ;
static Json data ( const std :: string & name ) {
std :: ifstream in ( DATA_DIR + "/" + name , std :: ios :: binary );
std :: stringstream ss ;
ss << in . rdbuf ();
return Json :: loads ( ss . str ());
}
static std :: string j ( const Json & v ) { return v . dumps (); }
static std :: string js ( const std :: string & s ) { return Json ( s ). dumps (); }
static Json arr_of ( const std :: vector < std :: string >& v ) {
Json a = Json :: array ();
for ( const auto & s : v ) a . push ( s );
return a ;
}
static void out ( const std :: string & line = "" ) { std :: cout << line << " \n " ; }
static std :: string tai_home () { return PyFs :: env ( "TAI_HOME" ); }
static std :: string py_bool ( bool b ) { return b ? "True" : "False" ; }
static void write ( const std :: string & path , const std :: string & text ) {
PyFs :: makedirs ( PyFs :: dirname ( path ));
PyFs :: write_bytes ( path , text );
}
static std :: string read ( const std :: string & path ) { return PyFs :: read_bytes ( path ); }
// ------------------------------------------------------------------ scenarios without state
static void sc_json ( const std :: string & ) {
for ( const auto & c : data ( "json_cases.json" ). items ()) {
try {
Json v = Json :: loads ( c . as_string ());
out ( js ( c . as_string ()) + " => " + v . dumps ());
} catch ( const detz :: misc :: JsonError & ) {
out ( js ( c . as_string ()) + " => ERR" );
}
}
}
static void sc_datetime ( const std :: string & ) {
for ( const auto & c : data ( "datetime_cases.json" ). items ()) {
std :: string iso , parsed ;
try {
iso = detz :: misc :: DateTime :: fromisoformat ( c . as_string ()). isoformat ();
} catch ( const std :: exception & ) {
iso = "ERR" ;
}
try {
parsed = detz :: sched :: ScheduleTime :: parse_schedule_at ( c . as_string ());
} catch ( const std :: exception & e ) {
parsed = std :: string ( "ERR " ) + e . what ();
}
bool err = parsed . rfind ( "ERR" , 0 ) == 0 ;
std :: string shown = "-" ;
if ( ! err ) {
try {
shown = js ( detz :: sched :: ScheduleTime :: local_display ( parsed ));
} catch ( const std :: exception & e ) {
shown = std :: string ( "ERR " ) + e . what ();
}
}
out ( js ( c . as_string ()) + " => " + iso + " | " + parsed + " | " + shown );
}
for ( const auto & c : data ( "duration_cases.json" ). items ()) {
auto d = detz :: sched :: ScheduleTime :: parse_duration ( c . as_string ());
out ( "duration " + js ( c . as_string ()) + " => " + ( d ? std :: to_string ( * d ) : std :: string ( "null" )));
}
for ( const auto & c : data ( "delay_cases.json" ). items ()) {
out ( "delay " + j ( c ) + " => " + js ( detz :: sched :: ScheduleTime :: format_delay ( c . as_double ())));
}
}
static void sc_chunk ( const std :: string & ) {
for ( const auto & c : data ( "chunk_cases.json" ). items ()) {
std :: string text = c . get ( "text" ) -> as_string ();
auto chunks = detz :: rag :: Chunker :: chunk_lines ( text , static_cast < int > ( c . get ( "max_lines" ) -> as_int ()), static_cast < int > ( c . get ( "overlap" ) -> as_int ()),
static_cast < int > ( c . get ( "max_chars" ) -> as_int ()));
out ( "chunks " + std :: to_string ( chunks . size ()) + " " + j ( arr_of ( chunks )));
out ( "collapse " + js ( detz :: rag :: Chunker :: collapse_repeated_lines ( text )));
out ( "lines " + j ( arr_of ( PyStr :: splitlines ( text ))));
out ( "strip " + js ( PyStr :: strip ( text )));
}
}
static void sc_fts ( const std :: string & ) {
using detz :: rag :: FtsQuery ;
for ( const auto & c : data ( "fts_cases.json" ). items ()) {
auto terms = FtsQuery :: fts_escape ( c . as_string ());
out ( js ( c . as_string ()) + " => " + ( terms ? j ( arr_of ( * terms )) : std :: string ( "null" )));
if ( terms ) {
out ( " match " + js ( FtsQuery :: fts_match ( * terms )));
out ( " or " + js ( FtsQuery :: fts_match_or ( * terms )));
out ( " prefix " + js ( FtsQuery :: fts_match_prefix ( * terms )));
out ( " variants " + j ( arr_of ( FtsQuery :: fts_match_variants ( * terms ))));
}
}
out ( "rank " + js ( FtsQuery :: fts_rank ( "fts_docs" )));
for ( const std :: string & raw : std :: vector < std :: string > { "Release Notes!" , " a b " , "---" , std :: string ( 40 , 'x' ), " \xc3\xa9 t \xc3\xa9 " , "a,b;c" , "Hello World 2" , ".." , "UPPER" , "a-b-c" }) {
out ( "tag " + js ( raw ) + " => " + js ( detz :: misc :: TagNames :: normalize_tag ( raw )));
}
std :: vector < std :: string > items = { "A b" , "a-b" , "" , "C!" , std :: string ( 40 , 'd' ), std :: string ( 39 , 'd' ) + "e" };
for ( int i = 0 ; i < 30 ; ++ i ) items . push_back ( "t" + std :: to_string ( i ));
out ( "tags " + j ( arr_of ( detz :: misc :: TagNames :: normalize_tags ( items ))));
}
static void sc_skills_data ( const std :: string & ) {
for ( const auto & kv : sk :: BundledData :: files ()) {
out ( "skill " + kv . first + " upstream " + js ( sk :: BundledData :: upstream (). at ( kv . first )));
for ( const auto & f : kv . second ) {
out ( " file " + f . first + " len " + std :: to_string ( f . second . size ()) + " sha8 " + sk :: BundledSkills :: bundled_skill_digest ( f . second ) +
" sha256 " + detz :: misc :: Sha256 :: hex ( f . second ));
}
}
for ( const auto & kv : sk :: BundledData :: blueprints ()) {
out ( "blueprint " + kv . first + " hint " + js ( kv . second . hint ) + " scope " + kv . second . scope + " brief " + js ( kv . second . brief ));
}
out ( "catalog empty " + js ( sk :: SkillFiles :: skill_catalog ( sk :: SkillSet ())));
sk :: SkillSet two ;
sk :: Skill a ;
a . name = "deep-research" ;
a . description = std :: string ( 400 , 'x' );
sk :: Skill b ;
b . name = "zeta" ;
b . description = "short" ;
two . put ( a );
two . put ( b );
out ( "catalog one " + js ( sk :: SkillFiles :: skill_catalog ( two )));
out ( "prompt " + js ( sk :: SkillFiles :: create_skill_prompt ( "my-skill" , "do the thing" , "/tmp/x/my-skill" )));
for ( const std :: string & raw : std :: vector < std :: string > { "a" , "ab" , "a-b" , "-a" , "a-" , "A" , "a_b" , std :: string ( 64 , 'a' ), std :: string ( 65 , 'a' ), "" , "a b" , "0x" , "a \n " }) {
out ( "name " + js ( raw ) + " => " + py_bool ( sk :: SkillFiles :: skill_name_valid ( raw )));
}
std :: vector < std :: vector < std :: string >> front_cases = {
{ "name: x" , "description: y" },
{ "name: 'x'" , "description: \" y z \" " },
{ "name: x" , "description: >" , " line one" , " line two" , "other: v" },
{ "name: x" , "description: |" , " line one" , " line two" , "tail: 1" },
{ "name: x" , "description: >-" , " folded" },
{ " indented: no" , "key: va:lue" , "noval" , "k2:" , "k3: ''quoted''" },
{ "a: >" , "b: 1" },
{ "a: |" , " \t t1" , " t2" , "z: 9" },
};
for ( const auto & lines : front_cases ) {
auto front = sk :: SkillFiles :: parse_skill_front ( lines );
// json.dumps of a dict keeps the parse (insertion) order; the C++ map is sorted, so compare as sorted key objects
Json o = Json :: object ();
for ( const auto & kv : front ) o . set ( kv . first , kv . second );
out ( "front " + j ( arr_of ( lines )) + " => " + j ( o ));
}
}
// ------------------------------------------------------------------ filesystem scenarios
static Json skill_json ( const std :: optional < sk :: Skill >& s ) {
if ( ! s ) return Json ();
Json o = Json :: object ();
o . set ( "name" , s -> name );
o . set ( "description" , s -> description );
o . set ( "body" , s -> body );
return o ;
}
static void sc_skills_files ( const std :: string & root ) {
std :: string home = tai_home ();
out ( "== front-matter parse" );
std :: vector < std :: pair < std :: string , std :: string >> cases = {
{ "ok" , "--- \n name: ok \n description: fine one \n --- \n\n\n body here \n " },
{ "crlf" , "--- \r\n name: crlf \r\n description: win \r\n --- \r\n body \r\n " },
{ "nofront" , "just text \n " },
{ "noend" , "--- \n name: noend \n description: d \n " },
{ "badname" , "--- \n name: Bad_Name \n description: d \n --- \n body \n " },
{ "nodesc" , "--- \n name: nodesc \n --- \n body \n " },
{ "quoted" , "--- \n name: 'quoted' \n description: \" has: colon \"\n --- \n body \n " },
{ "folded" , "--- \n name: folded \n description: > \n one \n two \n --- \n body \n " },
{ "emptybody" , "--- \n name: emptybody \n description: d \n ---" },
};
for ( const auto & kv : cases ) {
std :: string path = root + "/parse/" + kv . first + "/SKILL.md" ;
write ( path , kv . second );
out ( "parse " + kv . first + " => " + j ( skill_json ( sk :: SkillFiles :: parse_skill_file ( path ))));
}
out ( "== discover with external roots and collisions" );
std :: string proj = root + "/proj" ;
std :: string uh = PyFs :: home ();
write ( uh + "/.claude/skills/ext-home/SKILL.md" , "--- \n name: ext-home \n description: from claude home \n --- \n body ext-home \n " );
write ( uh + "/.claude/skills/shared/SKILL.md" , "--- \n name: shared \n description: external copy \n --- \n body external \n " );
write ( proj + "/.claude/skills/proj-claude/SKILL.md" , "--- \n name: proj-claude \n description: project claude \n --- \n body pc \n " );
write ( proj + "/.agents/skills/proj-agents/SKILL.md" , "--- \n name: proj-agents \n description: project agents \n --- \n body pa \n " );
write ( home + "/skills/shared/SKILL.md" , "--- \n name: shared \n description: tai copy \n --- \n body tai \n " );
write ( home + "/skills/native/SKILL.md" , "--- \n name: native \n description: native home skill \n --- \n body native \n " );
write ( home + "/skills/native/scripts/run.sh" , "echo hi \n " );
write ( home + "/skills/native/references/ref.md" , "ref \n " );
write ( home + "/skills/native/assets/a.txt" , "a \n " );
write ( proj + "/.tai/skills/proj-tai/SKILL.md" , "--- \n name: proj-tai \n description: project tai skill \n --- \n body ptai \n " );
write ( home + "/skills/broken/SKILL.md" , "no front matter \n " );
write ( home + "/skills/stray-file.txt" , "x \n " );
{
Json meta = Json :: object ();
meta . set ( "source" , "/some/path" );
meta . set ( "mode" , "symlink" );
meta . set ( "scope" , "home" );
meta . set ( "n" , 3 );
Json nested = Json :: object ();
Json arr = Json :: array ();
arr . push ( 1 ). push ( Json ()). push ( true );
nested . set ( "a" , arr );
meta . set ( "nested" , nested );
sk :: SkillFiles :: save_skill_install_meta ( home + "/skills" , "native" , meta );
}
auto skills = sk :: SkillFiles :: discover_skills ( home , proj );
for ( const auto & s : skills . items ()) {
out ( "skill " + s . name + " root=" + s . root + " managed=" + py_bool ( s . managed ) + " install=" + ( s . install ? j ( * s . install ) : std :: string ( "null" )) +
" note=" + js ( sk :: SkillFiles :: skill_provenance_note ( s )) + " extras=" + j ( arr_of ( sk :: SkillFiles :: skill_extra_files ( s . root ))));
out ( " desc=" + js ( s . description ) + " body=" + js ( s . body ));
}
std :: vector < std :: string > order ;
for ( const auto & s : skills . items ()) order . push_back ( s . name );
out ( "order " + j ( arr_of ( order )));
out ( "catalog " + js ( sk :: SkillFiles :: skill_catalog ( skills )));
out ( "== scope helpers" );
for ( const std :: string scope : { "project" , "home" }) {
out ( "scope_dir " + scope + " " + sk :: SkillFiles :: skill_scope_dir ( scope , home , proj , "nm" ));
out ( "scope_dir " + scope + " " + sk :: SkillFiles :: skill_scope_dir ( scope , home , proj ));
}
std :: string empty = root + "/emptyproj" ;
PyFs :: makedirs ( empty );
out ( "default scope empty " + sk :: SkillFiles :: default_skill_scope ( empty ));
for ( const std :: string marker : { ".git" , ".tai" , ".claude/skills" , ".agents/skills" }) {
std :: string tag = PyStr :: replace_all ( marker , "/" , "_" );
std :: string d = root + "/mk-" + tag ;
PyFs :: makedirs ( d + "/" + marker );
out ( "default scope " + marker + " " + sk :: SkillFiles :: default_skill_scope ( d ));
}
for ( const std :: string path : { "/a/b/.claude/skills/x" , "/a/b/.agents/skills/x/" , "/a/b/other/x" , "/a/.claude/skills/../x" , "/a/.claude/skills//x" }) {
out ( "external " + path + " " + py_bool ( sk :: SkillFiles :: is_external_skill_root ( path )));
}
auto none = sk :: SkillFiles :: load_skill_install_meta ( home + "/skills" , "nothing" );
out ( "meta none " + ( none ? j ( * none ) : std :: string ( "null" )));
write ( home + "/skills/.installs/bad.json" , "{not json" );
auto bad = sk :: SkillFiles :: load_skill_install_meta ( home + "/skills" , "bad" );
out ( "meta bad " + ( bad ? j ( * bad ) : std :: string ( "null" )));
auto ok = sk :: SkillFiles :: load_skill_install_meta ( home + "/skills" , "native" );
out ( "meta ok " + ( ok ? j ( * ok ) : std :: string ( "null" )));
}
static int count_files ( const std :: string & base ) { return static_cast < int > ( PyFs :: walk_files ( base ). size ()); }
static void sc_skills_install_tool ( const std :: string & root );
static void sc_skills_ops ( const std :: string & root ) {
std :: string home = tai_home ();
sk :: BundledSkills bundled ;
auto step = [ & ]( const std :: string & label , const std :: string & mode ) {
out ( label + " => " + bundled . op_skills ( mode , home ));
out ( " status: " + sk :: BundledSkills :: status_line ( home ));
out ( " files: " + std :: to_string ( count_files ( home + "/skills" )));
};
out ( "-- fresh" );
step ( "install" , "install" );
step ( "install again" , "install" );
step ( "upgrade clean" , "upgrade" );
{
std :: string s = "[" ;
bool first = true ;
for ( const auto & n : sk :: BundledSkills :: names ()) {
s += std :: string ( first ? "" : ", " ) + ( sk :: BundledSkills :: bundled_skill_pristine ( home , n ) ? "true" : "false" );
first = false ;
}
out ( "pristine all " + s + "]" );
}
std :: string taste = home + "/skills/taste/SKILL.md" ;
write ( taste , "user rewrite" );
out ( "-- modified taste" );
step ( "install" , "install" );
step ( "upgrade" , "upgrade" );
std :: string extra = home + "/skills/taste/mynotes.md" ;
write ( extra , "mine" );
step ( "reinstall" , "reinstall" );
out ( "extra kept " + py_bool ( PyFs :: isfile ( extra )));
out ( "-- crlf edit counts as equal after universal newlines" );
std :: string path = home + "/skills/plan/SKILL.md" ;
write ( path , PyStr :: replace_all ( read ( path ), " \n " , " \r\n " ));
step ( "upgrade crlf" , "upgrade" );
out ( "-- uninstall with user content" );
std :: string gitp = home + "/skills/git/SKILL.md" ;
write ( gitp , "user rewrite git" );
std :: string gextra = home + "/skills/git/mynotes.md" ;
write ( gextra , "mine" );
write ( home + "/skills/git/sub/deep.txt" , "deep" );
step ( "uninstall" , "uninstall" );
step ( "uninstall again" , "uninstall" );
PyFs :: remove ( gitp );
PyFs :: remove ( gextra );
PyFs :: remove ( home + "/skills/git/sub/deep.txt" );
step ( "uninstall final" , "uninstall" );
step ( "uninstall empty" , "uninstall" );
out ( "-- sidecar-only uninstall" );
{
Json meta = Json :: object ();
meta . set ( "files" , Json :: object ());
sk :: SkillFiles :: save_skill_install_meta ( home + "/skills" , "taste" , meta );
}
step ( "uninstall sidecar" , "uninstall" );
out ( "-- tracked-digest removal of an edited file" );
step ( "install" , "install" );
auto meta = sk :: SkillFiles :: load_skill_install_meta ( home + "/skills" , "taste" );
std :: vector < std :: string > keys ;
for ( const auto & m : meta -> members ()) keys . push_back ( m . first );
std :: sort ( keys . begin (), keys . end ());
out ( "meta " + j ( arr_of ( keys )));
out ( "meta files " + j ( * meta -> get ( "files" )));
{
Json fixed = Json :: object ();
for ( const char * k : { "source" , "mode" , "scope" , "upstream" , "bundled_version" }) fixed . set ( k , * meta -> get ( k ));
out ( "meta fixed " + j ( fixed ));
}
chmod (( home + "/skills/taste" ). c_str (), 0500 );
step ( "install readonly" , "install" );
chmod (( home + "/skills/taste" ). c_str (), 0700 );
out ( "-- error path: skills dir is a file" );
std :: string other = root + "/home2" ;
PyFs :: makedirs ( other );
write ( other + "/skills" , "file not dir" );
out ( "blocked => " + bundled . op_skills ( "install" , other ));
out ( "blocked uninstall => " + bundled . op_skills ( "uninstall" , other ));
sc_skills_install_tool ( root );
}
class SkillApp : public sk :: SkillHost {
public :
std :: string home_ , cwd_ ;
sk :: SkillSet skills_ ;
int depth_ { 0 };
std :: vector < std :: string > approvals ;
int refreshed { 0 };
bool approve { true };
std :: function < std :: string ( const std :: string & , int ) > runner ;
bool ask_approval ( const std :: string & what ) override { approvals . push_back ( what ); return approve ; }
std :: string home () const override { return home_ ; }
std :: string cwd () const override { return cwd_ ; }
int depth () const override { return depth_ ; }
const sk :: SkillSet & skills () const override { return skills_ ; }
void refresh_skills () override { ++ refreshed ; skills_ = sk :: SkillFiles :: discover_skills ( home_ , cwd_ ); }
void audit_skill_install ( const std :: string & , const std :: string & ) override {}
std :: string run_worker ( const std :: string & prompt , int timeout , int ) override { return runner ( prompt , timeout ); }
};
static std :: string dispatch ( sk :: SkillTool & tool , const std :: string & name , const Json & args ) {
try {
if ( name == "install_skill" ) return tool . run_install_skill ( args );
if ( name == "load_skill" ) return tool . run_load_skill ( args );
if ( name == "create_skill" ) return tool . run_create_skill ( args );
} catch ( const std :: exception & e ) {
return "error: " + PyStr :: short_error ( e . what ());
}
return "error: unknown tool " + name ;
}
static Json obj ( std :: initializer_list < std :: pair < const char * , Json >> kv ) {
Json o = Json :: object ();
for ( const auto & p : kv ) o . set ( p . first , p . second );
return o ;
}
static std :: string replace_root ( std :: string s , const std :: string & root ) { return PyStr :: replace_all ( s , root , "<ROOT>" ); }
static void sc_skills_install_tool ( const std :: string & root ) {
std :: string home = tai_home ();
std :: string proj = root + "/proj" ;
if ( chdir ( proj . c_str ()) != 0 ) return ;
SkillApp app ;
app . home_ = home ;
app . cwd_ = proj ;
app . skills_ = sk :: SkillFiles :: discover_skills ( home , proj );
sk :: SkillTool tool ( app );
out ( "== install_skill / load_skill / create_skill" );
std :: string src = root + "/srcskill" ;
write ( src + "/SKILL.md" , "--- \n name: from-src \n description: installed from a dir \n --- \n body src \n " );
write ( src + "/scripts/x.sh" , "echo x \n " );
write ( src + "/references/r.md" , "r \n " );
std :: string nested = root + "/nested" ;
write ( nested + "/inner/SKILL.md" , "--- \n name: inner \n description: nested one \n --- \n body inner \n " );
std :: string two = root + "/two" ;
write ( two + "/a/SKILL.md" , "--- \n name: aa \n description: d \n --- \n b \n " );
write ( two + "/b/SKILL.md" , "--- \n name: bb \n description: d \n --- \n b \n " );
std :: string barefile = root + "/bare.md" ;
write ( barefile , "--- \n name: bare-one \n description: bare md file \n --- \n body bare \n " );
std :: string badfile = root + "/bad.md" ;
write ( badfile , "no front \n " );
std :: string ext = proj + "/.claude/skills/extskill" ;
write ( ext + "/SKILL.md" , "--- \n name: extskill \n description: external one \n --- \n body ext \n " );
auto call = [ & ]( const std :: string & label , const Json & args ) { out ( label + " => " + js ( dispatch ( tool , "install_skill" , args ))); };
call ( "empty" , obj ({{ "source" , "" }}));
call ( "bad scope" , obj ({{ "source" , src }, { "scope" , "mars" }}));
call ( "bad mode" , obj ({{ "source" , src }, { "mode" , "link" }}));
call ( "missing" , obj ({{ "source" , root + "/nope" }}));
call ( "dir home" , obj ({{ "source" , src }, { "scope" , "home" }}));
call ( "dir home again denied?" , obj ({{ "source" , src }, { "scope" , "home" }}));
app . approve = false ;
call ( "dir home denied" , obj ({{ "source" , src }, { "scope" , "home" }}));
app . approve = true ;
call ( "dir home force" , obj ({{ "source" , src }, { "scope" , "home" }, { "force" , true }}));
call ( "dir project" , obj ({{ "source" , src }, { "scope" , "project" }, { "name" , "renamed" }}));
call ( "bad name" , obj ({{ "source" , src }, { "name" , "Bad Name" }}));
call ( "nested" , obj ({{ "source" , nested }, { "scope" , "home" }}));
call ( "two children" , obj ({{ "source" , two }, { "scope" , "home" }}));
call ( "bare file" , obj ({{ "source" , barefile }, { "scope" , "home" }}));
call ( "bad file" , obj ({{ "source" , badfile }}));
call ( "symlink ext default" , obj ({{ "source" , ext }, { "scope" , "home" }}));
call ( "symlink explicit" , obj ({{ "source" , src }, { "scope" , "home" }, { "mode" , "symlink" }, { "name" , "linked" }, { "force" , true }}));
call ( "symlink bare" , obj ({{ "source" , barefile }, { "mode" , "symlink" }}));
call ( "not a skill source" , obj ({{ "source" , "/dev/null" }}));
out ( "approvals " + j ( arr_of ( app . approvals )));
out ( "refreshed " + std :: to_string ( app . refreshed ));
out ( "skills " + j ( arr_of ( app . skills_ . sorted_names ())));
out ( "== load_skill" );
app . skills_ = sk :: SkillFiles :: discover_skills ( home , proj );
for ( const std :: string name : { "from-src" , "deep-research" , "extskill" , "nonexistent" , "" }) {
out ( "load " + js ( name ) + " => " + js ( dispatch ( tool , "load_skill" , obj ({{ "name" , name }}))));
}
out ( "== create_skill" );
app . runner = []( const std :: string & prompt , int timeout ) { return "worker said: " + PyStr :: prefix ( prompt , 40 ) + " t=" + std :: to_string ( timeout ); };
auto create = [ & ]( const Json & args ) { out ( "create " + j ( args ) + " => " + js ( dispatch ( tool , "create_skill" , args ))); };
create ( obj ({{ "name" , "" }, { "brief" , "b" }}));
create ( obj ({{ "name" , "ok-name" }, { "brief" , "" }}));
create ( obj ({{ "name" , "ok-name" }, { "brief" , "b" }, { "scope" , "mars" }}));
create ( obj ({{ "name" , "made" }, { "brief" , "make it" }, { "scope" , "home" }, { "timeout" , 10 }}));
create ( obj ({{ "name" , "made2" }, { "brief" , "make it" }, { "timeout" , "abc" }}));
create ( obj ({{ "name" , "made3" }, { "brief" , "x" }, { "timeout" , 99999 }}));
app . depth_ = 5 ;
out ( "create depth => " + js ( dispatch ( tool , "create_skill" , obj ({{ "name" , "dd" }, { "brief" , "b" }}))));
app . depth_ = 0 ;
app . runner = [ & ]( const std :: string & prompt , int ) {
std :: string marker = "Create a new agent skill named 'wrote' in " ;
std :: string path = prompt . substr ( marker . size ());
path = path . substr ( 0 , path . find ( ". \n " ));
write ( path + "/SKILL.md" , "--- \n name: wrote \n description: written by worker \n --- \n body wrote \n " );
return replace_root ( "done writing " + path , root );
};
out ( "create written => " + js ( replace_root ( dispatch ( tool , "create_skill" , obj ({{ "name" , "wrote" }, { "brief" , "w" }, { "scope" , "home" }})), root )));
out ( "create replaced => " + js ( replace_root ( dispatch ( tool , "create_skill" , obj ({{ "name" , "wrote" }, { "brief" , "w" }, { "scope" , "home" }})), root )));
out ( "refreshed " + std :: to_string ( app . refreshed ));
}
// ------------------------------------------------------------------ install scenarios
namespace ins = detz :: install ;
class FakeBox : public ins :: ContainerPort {
public :
std :: optional < std :: string > engine ;
std :: string state = "running" , venv = "venv ready" , ensure_error ;
std :: optional < std :: string > container_engine () override { return engine ; }
std :: string box_state ( const std :: string & ) override { return state ; }
std :: string box_venv_state ( const std :: string & ) override { return venv ; }
std :: string ensure_box () override {
if ( ! ensure_error . empty ()) throw detz :: misc :: BackendError ( ensure_error );
return engine ? * engine : std :: string ();
}
};
static ins :: InstallContext install_ctx () {
ins :: InstallContext ctx ;
const char * py = std :: getenv ( "MISC_TAI_PY" );
ctx . script_path = py ? py : "tai.py" ;
return ctx ;
}
static void sc_install_hooks ( const std :: string & root ) {
FakeBox box ;
ins :: StdIo io ;
ins :: Installer inst ( install_ctx (), box , io );
std :: string home = tai_home ();
std :: string uh = PyFs :: home ();
std :: string rc = uh + "/.bashrc" , zrc = uh + "/.zshrc" ;
write ( rc , "# my bashrc \n export A=1" );
write ( zrc , "" );
auto status = [ & ] { return PyStr :: join ( inst . status_lines ( home ), " \n " ); };
std :: vector < std :: pair < std :: string , std :: function < std :: string () >>> steps = {
{ "bash install" , [ & ] { return inst . op_hook ( "install" , home ); }},
{ "bash install again" , [ & ] { return inst . op_hook ( "install" , home ); }},
{ "bash upgrade" , [ & ] { return inst . op_hook ( "upgrade" , home ); }},
{ "plexer install" , [ & ] { return inst . op_plexer_hook ( "install" , home ); }},
{ "plexer again" , [ & ] { return inst . op_plexer_hook ( "install" , home ); }},
{ "zsh install" , [ & ] { return inst . op_zsh_hook ( "install" , home ); }},
{ "zsh again" , [ & ] { return inst . op_zsh_hook ( "install" , home ); }},
{ "fish install" , [ & ] { return inst . op_fish_hook ( "install" , home ); }},
{ "zsh plexer install" , [ & ] { return inst . op_zsh_plexer_hook ( "install" , home ); }},
{ "fish plexer install" , [ & ] { return inst . op_fish_plexer_hook ( "install" , home ); }},
{ "status" , status },
{ "bash reinstall" , [ & ] { return inst . op_hook ( "reinstall" , home ); }},
{ "plexer reinstall" , [ & ] { return inst . op_plexer_hook ( "reinstall" , home ); }},
{ "zsh uninstall" , [ & ] { return inst . op_zsh_hook ( "uninstall" , home ); }},
{ "fish uninstall" , [ & ] { return inst . op_fish_hook ( "uninstall" , home ); }},
{ "zsh uninstall again" , [ & ] { return inst . op_zsh_hook ( "uninstall" , home ); }},
{ "bash uninstall" , [ & ] { return inst . op_hook ( "uninstall" , home ); }},
{ "plexer uninstall" , [ & ] { return inst . op_plexer_hook ( "uninstall" , home ); }},
{ "zsh plexer uninstall" , [ & ] { return inst . op_zsh_plexer_hook ( "uninstall" , home ); }},
{ "fish plexer uninstall" , [ & ] { return inst . op_fish_plexer_hook ( "uninstall" , home ); }},
{ "status after" , status },
};
for ( const auto & st : steps ) out ( st . first + " => " + js ( st . second ()));
out ( "rc " + js ( read ( rc )));
out ( "zrc " + js ( read ( zrc )));
out ( "== stale and duplicated blocks" );
const std :: string & begin = ins :: InstallConsts :: BASHRC_MARK_BEGIN ();
const std :: string & end = ins :: InstallConsts :: BASHRC_MARK_END ();
write ( rc , "head \n " + begin + " \n stale content \n " + end + " \n mid \n " + begin + " \n second stale \n " + end + " \n tail \n " );
out ( "install over stale => " + js ( inst . op_hook ( "install" , home )));
out ( "rc " + js ( read ( rc )));
write ( rc , "x \n " + begin + " \n unterminated \n " );
out ( "install over unterminated => " + js ( inst . op_hook ( "install" , home )));
out ( "rc " + js ( read ( rc )));
out ( "uninstall unterminated => " + js ( inst . op_hook ( "uninstall" , home )));
out ( "rc " + js ( read ( rc )));
write ( rc , "crlf \r\n line \r\n " );
out ( "install crlf => " + js ( inst . op_hook ( "install" , home )));
out ( "rc " + js ( read ( rc )));
chmod ( rc . c_str (), 0400 );
out ( "readonly install => " + js ( inst . op_plexer_hook ( "install" , home )));
chmod ( rc . c_str (), 0600 );
auto present = [ & ]( const std :: string & path ) {
Json a = Json :: array ();
for ( bool b : { ins :: Installer :: hook_present ( path ), ins :: Installer :: zsh_hook_present ( path ), ins :: Installer :: fish_hook_present ( path ),
ins :: Installer :: plexer_hook_present ( path ), ins :: Installer :: zsh_plexer_hook_present ( path ), ins :: Installer :: fish_plexer_hook_present ( path )})
a . push ( b );
return a ;
};
out ( "present " + j ( present ( rc )));
out ( "present missing " + j ( present ( root + "/nope" )));
for ( const std :: string shell : { "bash" , "zsh" , "fish" , "other" }) out ( "rc path " + shell + " " + ins :: Install :: shell_rc_path ( shell ));
setenv ( "XDG_CONFIG_HOME" , ( root + "/xdg" ). c_str (), 1 );
out ( "rc path fish xdg " + ins :: Install :: shell_rc_path ( "fish" ));
unsetenv ( "XDG_CONFIG_HOME" );
Json sp = Json :: array ();
for ( const char * n : { "zsh" , "fish" , "bash" , "nosuchshell" }) sp . push ( ins :: Install :: shell_present ( n ));
out ( "shell_present " + j ( sp ));
}
class InstallApp : public sk :: SkillHost {
public :
std :: string home_ , cwd_ ;
sk :: SkillSet skills_ ;
std :: vector < std :: string > approvals ;
bool approve { true };
bool ask_approval ( const std :: string & what ) override { approvals . push_back ( what ); return approve ; }
std :: string home () const override { return home_ ; }
std :: string cwd () const override { return cwd_ ; }
const sk :: SkillSet & skills () const override { return skills_ ; }
void refresh_skills () override { skills_ = sk :: SkillFiles :: discover_skills ( home_ , cwd_ ); }
void audit_skill_install ( const std :: string & , const std :: string & ) override {}
std :: string run_worker ( const std :: string & , int , int ) override { return "" ; }
};
static void set_box ( FakeBox & box , std :: optional < std :: string > engine , const std :: string & state = "running" , const std :: string & venv = "venv ready" , const std :: string & err = "" ) {
box . engine = engine ;
box . state = state ;
box . venv = venv ;
box . ensure_error = err ;
}
static void sc_install_ops ( const std :: string & root ) {
FakeBox box ;
set_box ( box , std :: string ( "podman" ));
ins :: StdIo io ;
ins :: Installer inst ( install_ctx (), box , io );
std :: string home = tai_home ();
std :: string uh = PyFs :: home ();
out ( "-- binary" );
for ( const std :: string mode : { "install" , "install" , "upgrade" , "reinstall" , "uninstall" , "uninstall" , "install" }) out ( "binary " + mode + " => " + js ( inst . op_binary ( mode , home )));
std :: string target = uh + "/.local/bin/tai.py" ;
{
struct stat st ;
stat ( target . c_str (), & st );
struct stat st2 ;
stat ( install_ctx (). script_path . c_str (), & st2 );
char buf [ 16 ];
std :: snprintf ( buf , sizeof buf , "0o%o" , static_cast < unsigned > ( st . st_mode & 0777 ));
out ( std :: string ( "binary mode " ) + buf + " size_equal " + py_bool ( st . st_size == st2 . st_size ));
}
write ( target , "VERSION = \" 0.0.1 \"\n " );
out ( "binary refresh => " + js ( inst . op_binary ( "install" , home )));
out ( "binary refresh upgrade => " + js ( inst . op_binary ( "upgrade" , home )));
auto opt_js = []( const std :: optional < std :: string >& v ) { return v ? js ( * v ) : std :: string ( "null" ); };
out ( "script_version " + opt_js ( inst . script_version ( target )) + " " + opt_js ( inst . script_version ( root + "/nope" )) + " " + opt_js ( inst . script_version ( install_ctx (). script_path )));
write ( root + "/v1" , "x \n VERSION = \" 1.2.3 \"\n y \n " );
write ( root + "/v2" , "VERSION = \" 1.2 \"\n VERSION = \" 1.2.3 \"\n VERSION = \" a.b.c \"\n " );
write ( root + "/v3" , "VERSION = \" 4.5.6 \" " );
write ( root + "/v4" , "VERSION = \" 4.5.6 \" \n " );
{
std :: string s = "[" ;
bool first = true ;
for ( const char * n : { "v1" , "v2" , "v3" , "v4" }) {
s += std :: string ( first ? "" : ", " ) + ( inst . script_version ( root + "/" + n ) ? js ( * inst . script_version ( root + "/" + n )) : std :: string ( "null" ));
first = false ;
}
out ( "script_version v1..v4 " + s + "]" );
}
out ( "-- venv" );
for ( const std :: string mode : { "install" , "install" , "reinstall" , "uninstall" , "uninstall" , "install" }) out ( "venv " + mode + " => " + js ( inst . op_venv ( mode , home )));
{
auto vp = ins :: Install :: venv_python ( home );
out ( "venv helpers " + js ( ins :: Install :: venv_dir ( home )) + " " + js ( vp ? * vp : std :: string ()) + " " + py_bool ( ins :: Install :: venv_available ()));
}
out ( "-- services (no systemctl)" );
for ( const std :: string mode : { "install" , "install" , "reinstall" , "upgrade" , "uninstall" , "uninstall" }) out ( "scheduler " + mode + " => " + js ( inst . op_scheduler_service ( mode , home )));
out ( "telegram without token => " + js ( inst . op_telegram_service ( "install" , home )));
out ( "service_exec " + js ( inst . service_exec ( home , "/x/tai.py" , { "--a" , "b" })));
out ( "unit_dir " + js ( ins :: Systemd :: unit_dir ( home )));
{
auto st = ins :: Systemd :: service_state ( "tai-scheduler.service" );
Json a = Json :: array ();
a . push ( st . first ). push ( st . second );
out ( "service_state " + j ( a ));
}
out ( "activate " + js ( ins :: Systemd :: activate_service ( "tai-scheduler.service" )));
{
auto r = ins :: Systemd :: remove_service_unit ( home , "tai-scheduler.service" );
Json a = Json :: array ();
a . push ( r . first ). push ( r . second );
out ( "remove " + j ( a ));
}
out ( "-- container" );
for ( const std :: string mode : { "install" , "upgrade" , "reinstall" , "uninstall" }) out ( "container " + mode + " => " + js ( inst . op_container ( mode , home )));
set_box ( box , std :: string ( "podman" ), "stopped" , "no venv (reinstall container to rebuild)" );
for ( const std :: string mode : { "install" , "reinstall" }) out ( "container stopped " + mode + " => " + js ( inst . op_container ( mode , home )));
set_box ( box , std :: string ( "podman" ), "running" , "venv ready" , "engine exploded" );
out ( "container failing => " + js ( inst . op_container ( "install" , home )));
set_box ( box , std :: nullopt );
for ( const std :: string mode : { "install" , "uninstall" }) out ( "container noengine " + mode + " => " + js ( inst . op_container ( mode , home )));
set_box ( box , std :: string ( "podman" ));
out ( "-- install_report" );
struct Rep { std :: string action ; std :: vector < std :: string > targets ; };
std :: vector < Rep > reps = {{ "install" , { "skills" , "bash-hook" , "venv" }}, { "status" , { "skills" }}, { "upgrade" , ins :: InstallConsts :: INSTALL_TARGETS ()},
{ "uninstall" , { "skills" , "bash-hook" , "plexer-hook" , "binary" }}};
for ( const auto & r : reps ) out ( "report " + r . action + " " + PyStr :: replace_all ( PyStr :: replace_all ( j ( arr_of ( r . targets )), " \" " , "'" ), "," , "," ) + " => \n " + inst . install_report ( r . action , r . targets , home ));
out ( "-- install_self" );
for ( const std :: string shell : { "/bin/bash" , "/usr/bin/zsh" , "/usr/bin/fish" , "" , "/bin/sh" }) {
setenv ( "SHELL" , shell . c_str (), 1 );
out ( "shell " + js ( shell ));
std :: cout . flush ();
inst . install_self ();
}
out ( "-- install tool" );
InstallApp app ;
app . home_ = home ;
app . cwd_ = root ;
auto run_tool = [ & ]( const Json & args ) {
return inst . run_install ( args , home , nullptr , [ & ]( const std :: string & w ) { return app . ask_approval ( w ); }, [ & ] { app . refresh_skills (); });
};
std :: vector < Json > tool_args = {
obj ({{ "action" , "bogus" }}), obj ({{ "action" , "status" }}), obj ({{ "action" , "STATUS " }, { "targets" , arr_of ({ "skills" })}}), obj ({{ "action" , "install" }, { "targets" , arr_of ({ "nope" })}}),
obj ({{ "action" , "install" }, { "targets" , Json :: array ()}}), obj ({{ "action" , "install" }, { "targets" , "skills" }}), obj ({{ "action" , "install" }, { "targets" , arr_of ({ "skills" })}}),
obj ({{ "action" , "uninstall" }, { "targets" , arr_of ({ "skills" , "bash-hook" })}}), Json :: object ()};
for ( const auto & args : tool_args ) {
app . skills_ = sk :: SkillSet ();
std :: string res = run_tool ( args );
out ( "tool " + j ( args ) + " => " + js ( res ) + " | skills=" + j ( arr_of ( app . skills_ . sorted_names ())));
}
app . approve = false ;
out ( "tool denied => " + js ( run_tool ( obj ({{ "action" , "install" }, { "targets" , arr_of ({ "skills" })}}))));
out ( "approvals " + j ( arr_of ( app . approvals )));
}
static void sc_install_noengine ( const std :: string & ) {
FakeBox box ;
set_box ( box , std :: nullopt );
ins :: StdIo io ;
ins :: Installer inst ( install_ctx (), box , io );
std :: string home = tai_home ();
auto lines = inst . status_lines ( home );
Json a = Json :: array ();
for ( std :: size_t i = lines . size () - 3 ; i < lines . size (); ++ i ) a . push ( lines [ i ]);
out ( j ( a ));
for ( const std :: string mode : { "install" , "uninstall" }) out ( "container " + mode + " => " + js ( inst . op_container ( mode , home )));
}
static void sc_vault_line ( const std :: string & ) {
std :: string home = tai_home ();
out ( "empty " + js ( ins :: Installer :: vault_line ( home )));
write ( home + "/memory.db" , "" );
out ( "kept " + js ( ins :: Installer :: vault_line ( home )));
}
// ------------------------------------------------------------------ scheduler scenario
namespace sc = detz :: sched ;
using detz :: misc :: DbValue ;
using detz :: misc :: SqliteDb ;
static Json db_json ( const DbValue & v ) {
if ( v . is_null ()) return Json ();
if ( v . is_int ()) return Json ( v . as_int ());
return Json ( v . as_text ());
}
static Json row_json ( const detz :: misc :: DbRow & r ) {
Json a = Json :: array ();
for ( const auto & v : r ) a . push ( db_json ( v ));
return a ;
}
// Seal with passphrase disabled: lock is the identity, unlock follows Seal.unlock's error paths.
class DisabledSeal : public sc :: SealPort {
public :
bool enabled () const override { return false ; }
std :: string lock ( const std :: string & plain ) const override { return plain ; }
std :: string unlock ( const std :: string & sealed ) const override {
if ( ! is_sealed ( sealed )) throw sc :: SealError ( "not sealed" );
std :: size_t d1 = sealed . find ( '$' ), d2 = sealed . find ( '$' , d1 + 1 ), d3 = sealed . find ( '$' , d2 + 1 );
if ( d2 == std :: string :: npos || d3 == std :: string :: npos ) throw sc :: SealError ( "sealed value is corrupt" );
throw sc :: SealError ( "seal check failed" );
}
std :: string safe_unlock ( const std :: string & sealed ) const override {
try { return unlock ( sealed ); } catch ( const sc :: SealError & ) { return "[sealed: decrypt failed]" ; }
}
};
// The tag side of Store as the schedule code uses it (no plural folding needed for the test vocabulary)
class SqlTags : public sc :: TagPort {
public :
SqlTags ( SqliteDb & db ) : db_ ( db ) {}
void tag_item ( const std :: string & item , const std :: vector < std :: string >& tags , const std :: string & profile ) override {
for ( const auto & t : detz :: misc :: TagNames :: normalize_tags ( tags )) db_ . execute ( "INSERT OR IGNORE INTO tags (item, tag, profile) VALUES (?, ?, ?)" , { item , t , profile });
}
void set_item_tags ( const std :: string & item , const std :: vector < std :: string >& tags , const std :: string & profile ) override {
db_ . execute ( "DELETE FROM tags WHERE item = ? AND profile = ?" , { item , profile });
tag_item ( item , tags , profile );
}
std :: vector < std :: string > item_tags ( const std :: string & item , const std :: string & profile ) override {
std :: vector < std :: string > out_tags ;
for ( const auto & r : db_ . query ( "SELECT tag FROM tags WHERE item = ? AND profile = ? ORDER BY tag" , { item , profile })) out_tags . push_back ( r [ 0 ]. as_text ());
return out_tags ;
}
private :
SqliteDb & db_ ;
};
// Registry with spawn_agent/poll_agent/running_agents semantics of tai.py and the Gate runner of the Python twin.
class FakeAgents : public sc :: AgentPort {
public :
struct Rec {
std :: string task , status = "running" , result ;
std :: thread th ;
};
std :: mutex m ;
std :: map < int , std :: unique_ptr < Rec >> recs ;
int next = 1 ;
bool report_zero = false ;
std :: mutex gm ;
std :: condition_variable gcv ;
bool released = false ;
~ FakeAgents () override {
release ();
for ( auto & kv : recs ) {
if ( kv . second -> th . joinable ()) kv . second -> th . join ();
}
}
void release () {
std :: lock_guard < std :: mutex > lock ( gm );
released = true ;
gcv . notify_all ();
}
int running_agents () override {
if ( report_zero ) return 0 ;
std :: lock_guard < std :: mutex > lock ( m );
int n = 0 ;
for ( auto & kv : recs ) n += kv . second -> status == "running" ;
return n ;
}
int spawn_agent ( const std :: string & task , const std :: string & , int64_t ) override {
std :: lock_guard < std :: mutex > lock ( m );
int live = 0 ;
for ( auto & kv : recs ) live += kv . second -> status == "running" ;
if ( live >= 8 ) throw sc :: AgentsFull ( "too many live agents (" + std :: to_string ( live ) + " of 8)" );
int id = next ++ ;
auto rec = std :: make_unique < Rec > ();
rec -> task = task ;
Rec * raw = rec . get ();
recs [ id ] = std :: move ( rec );
raw -> th = std :: thread ([ this , raw , task ] {
std :: string result , status ;
try {
if ( task . rfind ( "slow:" , 0 ) == 0 ) {
std :: unique_lock < std :: mutex > lock ( gm );
gcv . wait_for ( lock , std :: chrono :: seconds ( 30 ), [ this ] { return released ; });
result = "slow done " + task ;
} else if ( task . find ( "boom" ) != std :: string :: npos ) {
throw std :: runtime_error ( "boom" );
} else {
result = "ok:" + task ;
}
status = result . find ( "[time limit reached]" ) != std :: string :: npos ? "timeout" : "done" ;
} catch ( const std :: exception & e ) {
result = std :: string ( "worker failed: " ) + PyStr :: short_error ( e . what ());
status = "error" ;
}
std :: lock_guard < std :: mutex > lock ( m );
raw -> result = result ;
raw -> status = status ;
});
return id ;
}
std :: pair < std :: string , std :: string > poll_agent ( int id , double wait ) override {
Rec * rec ;
{
std :: lock_guard < std :: mutex > lock ( m );
auto it = recs . find ( id );
if ( it == recs . end ()) return { "missing" , "no agent " + std :: to_string ( id )};
rec = it -> second . get ();
}
auto deadline = std :: chrono :: steady_clock :: now () + std :: chrono :: duration < double > ( wait );
while ( std :: chrono :: steady_clock :: now () < deadline ) {
{
std :: lock_guard < std :: mutex > lock ( m );
if ( rec -> status != "running" ) break ;
}
std :: this_thread :: sleep_for ( std :: chrono :: milliseconds ( 5 ));
}
std :: lock_guard < std :: mutex > lock ( m );
if ( rec -> status == "running" ) return { rec -> status , "agent " + std :: to_string ( id ) + " still running (0s elapsed)" };
if ( rec -> status == "error" ) return { rec -> status , rec -> result };
std :: string text = rec -> result ;
std :: size_t n = PyStr :: len ( text );
if ( n > 6000 + 2000 + 50 ) text = PyStr :: prefix ( text , 6000 ) + " \n ...[" + std :: to_string ( n - 6000 - 2000 ) + " chars truncated]... \n " + PyStr :: suffix ( text , 2000 );
if ( text . empty ()) text = "(empty result)" ;
return { rec -> status , text };
}
};
class SchedApp : public sc :: ScheduleHost {
public :
std :: vector < std :: string > approvals ;
bool approve = true ;
sc :: ScheduleVault * vault_ = nullptr ;
bool ask_approval ( const std :: string & what ) override { approvals . push_back ( what ); return approve ; }
std :: string active_profile () const override { return "t" ; }
sc :: ScheduleVault & vault () override { return * vault_ ; }
};
static void sched_rows ( SqliteDb & db , const std :: string & label ) {
out ( "-- " + label );
for ( const auto & r : db . query ( "SELECT id, name, prompt, profile, every_sec, next_run, timeout, status, last_status, last_result, updated FROM schedules ORDER BY id" )) out ( "row " + j ( row_json ( r )));
Json tags = Json :: array ();
for ( const auto & r : db . query ( "SELECT item, tag, profile FROM tags WHERE item LIKE 'sched:%' ORDER BY item, tag" )) tags . push ( row_json ( r ));
out ( "tags " + j ( tags ));
}
static void sc_sched ( const std :: string & ) {
std :: string db_path = tai_home () + "/memory.db" ;
SqliteDb db ( db_path , 30 , true );
DisabledSeal seal ;
SqlTags tags ( db );
FakeAgents agents ;
sc :: Scheduler scheduler ( db_path , seal , agents );
sc :: ScheduleVault vault ( db , seal , tags , "t" );
auto quiesce = [ & ] { scheduler . join_watchers (); };
auto item_json = []( const sc :: ScheduleItem & it ) {
Json o = Json :: object ();
o . set ( "id" , it . id ). set ( "name" , it . name ). set ( "prompt" , it . prompt ). set ( "profile" , it . profile ). set ( "every" , it . every ). set ( "next_run" , it . next_run ). set ( "timeout" , it . timeout );
o . set ( "status" , it . status ). set ( "last" , it . last ). set ( "result" , it . result ). set ( "created" , it . created ). set ( "tags" , arr_of ( it . tags ));
return o ;
};
const std :: string NOW = "2026-10-25T12:00:00+00:00" ;
out ( "== list and format" );
auto items = vault . list_schedules ();
for ( const auto & it : items ) out ( "item " + j ( item_json ( it )));
out ( "format: \n " + sc :: Scheduler :: format_schedule_lines ( items , detz :: misc :: DateTime :: fromisoformat ( NOW )));
out ( "format empty: " + sc :: Scheduler :: format_schedule_lines ({}, detz :: misc :: DateTime :: fromisoformat ( NOW )));
{
Json a = Json :: array ();
for ( const auto & it : vault . list_schedules ( "other" )) a . push ( item_json ( it ));
out ( "other profile: " + j ( a ));
}
out ( "== running leases" );
std :: string nowiso = detz :: misc :: DateTime :: now_utc (). isoformat ();
struct Lease { std :: string status , updated ; int64_t timeout ; };
for ( const auto & l : std :: vector < Lease > {{ "running" , nowiso , 600 }, { "running" , "2000-01-01T00:00:00+00:00" , 600 }, { "done" , "" , 0 }, { "running" , "garbage" , 10 }, { "running" , nowiso , 0 }}) {
out ( "running " + l . status + " " + ( l . updated . rfind ( "2026" , 0 ) == 0 ? std :: string ( "now" ) : l . updated ) + " " + std :: to_string ( l . timeout ) + " => " +
py_bool ( sc :: Scheduler :: schedule_running ( l . status , l . updated , l . timeout )));
}
out ( "== sealed rows (added now: Store refuses to open with them present and no passphrase)" );
vault . add_schedule ( "sealed" , "tai1$AAAA$BBBB$CCCC" , "t" , 0 , "2026-05-01T00:00:00+00:00" , 300 );
vault . add_schedule ( "sealed-corrupt" , "tai1$bad" , "t" , 0 , "2026-05-02T00:00:00+00:00" , 300 );
out ( "== tick 1" );
std :: cout . flush ();
int fired = scheduler . scheduler_tick ();
out ( "fired " + std :: to_string ( fired ));
quiesce ();
sched_rows ( db , "after tick 1" );
out ( "== tick 2" );
out ( "fired " + std :: to_string ( scheduler . scheduler_tick ()));
quiesce ();
out ( "== cap phase" );
for ( int k = 0 ; k < 9 ; ++ k ) vault . add_schedule ( "slow" + std :: to_string ( k ), "slow:" + std :: to_string ( k ), "t" , 315360000 , "2025-01-0" + std :: to_string ( k + 1 ) + "T00:00:00+00:00" , 600 );
out ( "fired " + std :: to_string ( scheduler . scheduler_tick ()));
out ( "fired " + std :: to_string ( scheduler . scheduler_tick ()));
out ( "running agents " + std :: to_string ( agents . running_agents ()));
out ( "fired " + std :: to_string ( scheduler . scheduler_tick ()));
sched_rows ( db , "after cap ticks" );
out ( "== AgentsFull restore branch" );
vault . add_schedule ( "full-once" , "slow:once" , "t" , 0 , "2025-02-01T00:00:00+00:00" , 600 );
agents . report_zero = true ;
out ( "fired " + std :: to_string ( scheduler . scheduler_tick ()));
agents . report_zero = false ;
sched_rows ( db , "after AgentsFull" );
agents . release ();
quiesce ();
sched_rows ( db , "after release" );
out ( "== schedule tool" );
SchedApp app ;
app . vault_ = & vault ;
sc :: ScheduleTool tool ( app );
auto dispatch_tool = [ & ]( const std :: string & name , const Json & args ) {
try {
if ( name == "schedule" ) return tool . run_schedule ( args );
if ( name == "unschedule" ) return tool . run_unschedule ( args );
return tool . run_schedules ( args );
} catch ( const std :: exception & e ) {
return "error: " + PyStr :: short_error ( e . what ());
}
};
std :: vector < Json > calls = {
obj ({{ "prompt" , "" }}), obj ({{ "prompt" , "p" }}), obj ({{ "prompt" , "p" }, { "at" , "2099-01-01T10:00" }, { "every" , 120 }}), obj ({{ "prompt" , "p" }, { "at" , "nonsense" }}),
obj ({{ "prompt" , "p" }, { "every" , "abc" }}), obj ({{ "prompt" , "p" }, { "every" , 30 }}),
obj ({{ "prompt" , "tool one" }, { "at" , "2099-01-01T10:00" }, { "name" , std :: string ( 100 , 'N' )}, { "timeout" , 5 }, { "tags" , arr_of ({ "Alpha" , "beta!" , "" , std :: string ( 40 , 'x' )})}}),
obj ({{ "prompt" , "tool two" }, { "every" , 3600 }, { "timeout" , "abc" }, { "profile" , "t" }}), obj ({{ "prompt" , "tool three" }, { "every" , "7200" }, { "timeout" , 99999 }}),
obj ({{ "prompt" , "p" }, { "every" , 60 }, { "profile" , "other" }}), obj ({{ "prompt" , "p" }, { "every" , 60 }, { "profile" , "bad profile!" }}),
obj ({{ "prompt" , "p" }, { "every" , 60 }, { "tags" , "notalist" }}), obj ({{ "prompt" , "p" }, { "every" , 60 }, { "tags" , [] { Json a = Json :: array (); a . push ( 1 ). push ( 2 ); return a ; }()}}),
obj ({{ "prompt" , "tool four" }, { "every" , 86400 }, { "tags" , Json :: array ()}}), obj ({{ "prompt" , " padded " }, { "at" , "2099-02-02T02:02:02Z" }, { "timeout" , 0 }}),
obj ({{ "prompt" , "p" }, { "at" , "9999-12-31T24:00" }}), obj ({{ "prompt" , "p" }, { "at" , "0001-01-01T00:00" }}), obj ({{ "prompt" , "p" }, { "every" , 60.5 }}), obj ({{ "prompt" , "p" }, { "every" , true }}),
};
for ( const auto & args : calls ) out ( "schedule " + j ( args ) + " => " + js ( dispatch_tool ( "schedule" , args )));
app . approve = false ;
out ( "schedule denied => " + js ( dispatch_tool ( "schedule" , obj ({{ "prompt" , "denied" }, { "every" , 60 }}))));
app . approve = true ;
out ( "schedules => " + js ( dispatch_tool ( "schedules" , Json :: object ())));
for ( const auto & args : std :: vector < Json > { obj ({{ "id" , 999 }}), obj ({{ "id" , "abc" }}), obj ({{ "id" , 0 }}), Json :: object (), obj ({{ "id" , "13" }}), obj ({{ "id" , 14.0 }})}) {
out ( "unschedule " + j ( args ) + " => " + js ( dispatch_tool ( "unschedule" , args )));
}
app . approve = false ;
out ( "unschedule denied => " + js ( dispatch_tool ( "unschedule" , obj ({{ "id" , 15 }}))));
app . approve = true ;
out ( "approvals " + j ( arr_of ( app . approvals )));
sched_rows ( db , "final" );
out ( "remove nonexistent " + py_bool ( vault . remove_schedule ( 99999 )));
}
// ------------------------------------------------------------------ rag scenario
namespace rg = detz :: rag ;
static Json hit_json ( const rg :: FtsHit & h ) {
Json o = Json :: object ();
o . set ( "item" , db_json ( h . item )). set ( "kind" , h . kind ). set ( "sub" , h . sub ). set ( "title" , h . title ). set ( "snippet" , h . snippet ). set ( "rank" , h . rank );
return o ;
}
static Json ids_json ( const std :: vector < DbValue >& v ) {
Json a = Json :: array ();
for ( const auto & x : v ) a . push ( db_json ( x ));
return a ;
}
static Json mean_json ( const rg :: EvalMean & m ) {
Json o = Json :: object ();
o . set ( "hit" , m . hit ). set ( "mrr" , m . mrr ). set ( "ndcg" , m . ndcg ). set ( "cp" , m . cp );
return o ;
}
static Json result_json ( const rg :: EvalResult & r ) {
Json o = Json :: object ();
o . set ( "k" , r . k ). set ( "goldens" , r . goldens ). set ( "overall" , mean_json ( r . overall ));
Json cats = Json :: object ();
for ( const auto & c : r . by_category ) {
Json e = Json :: object ();
e . set ( "goldens" , c . second . goldens ). set ( "mean" , mean_json ( c . second . mean ));
cats . set ( c . first , e );
}
o . set ( "by_category" , cats );
Json misses = Json :: array ();
for ( const auto & m : r . misses ) {
Json e = Json :: object ();
e . set ( "query" , m . query ). set ( "category" , m . category );
misses . push ( e );
}
o . set ( "misses" , misses );
return o ;
}
static Json pairs_json ( const rg :: ImplicitPairs & p ) {
Json o = Json :: object ();
o . set ( "searches" , p . searches ). set ( "read_follow" , p . read_follow );
Json pairs = Json :: array ();
for ( const auto & x : p . pairs ) {
Json e = Json :: object ();
e . set ( "query" , x . query ). set ( "read" , x . read ). set ( "rank" , x . rank ? Json ( * x . rank ) : Json ()). set ( "shown" , x . shown );
pairs . push ( e );
}
o . set ( "pairs" , pairs ). set ( "zero_hit" , arr_of ( p . zero_hit )). set ( "zero_hit_count" , p . zero_hit_count );
return o ;
}
class RagApp : public rg :: RagHost {
public :
RagApp ( SqliteDb & db , rg :: FtsSearch & fts , rg :: ChunkStore & chunks ) : db_ ( db ), fts_ ( fts ), chunks_ ( chunks ) {}
std :: string active_profile () const override { return "t" ; }
bool sealed () const override { return false ; }
std :: vector < rg :: FtsHit > fts_search ( const std :: string & q , const std :: vector < std :: string >& kinds , const std :: string & profile , int limit ) override { return fts_ . fts_search ( q , kinds , profile , limit ); }
std :: vector < rg :: EventRow > events_like ( const std :: string & , const std :: string & , int ) override { return {}; }
void log_event ( const std :: string & profile , const std :: string & role , const std :: string & kind , const std :: string & text ) override {
std :: string value = PyStr :: prefix ( text , 2000 );
db_ . execute ( "INSERT INTO events (profile, ts, role, kind, text, tags) VALUES (?, ?, ?, ?, ?, ?)" , { profile , detz :: sched :: ScheduleTime :: now_iso (), role , kind , value , " " + role + " " + kind + " " });
}
std :: map < int64_t , rg :: ChunkRow > get_chunks_by_ids ( const std :: vector < int64_t >& ids , const std :: string & profile ) override { return chunks_ . get_chunks_by_ids ( ids , profile ); }
std :: vector < rg :: GraphEdge > edges_for ( const std :: string & item , const std :: string & profile ) override {
std :: vector < rg :: GraphEdge > out_edges ;
for ( const auto & r : db_ . query ( "SELECT src, dst, relation FROM edges WHERE profile = ? AND (src = ? OR dst = ?)" , { profile , item , item })) {
out_edges . push_back ({ r [ 0 ]. as_text () == item ? r [ 1 ]. as_text () : r [ 0 ]. as_text (), r [ 2 ]. as_text ()});
}
return out_edges ;
}
2026-10-28 13:11:45 +01:00
std :: string profiles_dir () const override { return tai_home () + "/profiles" ; }
2026-10-25 05:06:38 +01:00
std :: string node_title ( const std :: string & node , const std :: string & profile ) override {
std :: size_t colon = node . find ( ':' );
if ( colon == std :: string :: npos ) return node ;
std :: string kind = node . substr ( 0 , colon ), key = node . substr ( colon + 1 );
if ( kind == "mem" ) {
auto rows = db_ . query ( "SELECT title FROM records WHERE profile = ? AND id = ?" , { profile , node });
if ( rows . empty ()) return node ;
std :: string t = rows [ 0 ][ 0 ]. as_text ();
return t . empty () ? node : t ;
}
if ( kind == "secret" ) return "secret:" + key ;
auto rows = db_ . query ( "SELECT name, prompt FROM schedules WHERE profile = ? AND id = ?" , { profile , std :: stoll ( key )});
if ( rows . empty ()) return node ;
std :: string name = rows [ 0 ][ 0 ]. as_text ();
return name . empty () ? "schedule #" + key : name ;
}
private :
SqliteDb & db_ ;
rg :: FtsSearch & fts_ ;
rg :: ChunkStore & chunks_ ;
};
static void sc_rag ( const std :: string & ) {
SqliteDb db ( tai_home () + "/memory.db" , 30 , true );
rg :: FtsSearch fts ( db , "t" );
rg :: ChunkStore chunks ( db , "t" );
out ( "== fts_search" );
std :: vector < std :: string > queries = { "alpha" , "alpha bravo" , "zebra" , "caf \xc3\xa9 " , "r \xc3\xa9 sum \xc3\xa9 na \xc3\xaf ve" , "snake_case" , "numbers123" , "nothingmatchesthis" , "" , "!!!" , "retrieval index" , "wh" ,
"ALPHA" , std :: string ( 50 , 'x' ), "unique zebra jumps" , "message" , "file" , "ro" , "v2beta kernel" };
std :: vector < std :: vector < std :: string >> kind_sets = {{}, { "record" }, { "chunk" }, { "audit" }, { "event" }, { "record" , "chunk" }};
for ( const auto & q : queries ) {
for ( const auto & kinds : kind_sets ) {
for ( int limit : { 10 , 3 }) {
Json a = Json :: array ();
for ( const auto & h : fts . fts_search ( q , kinds , "t" , limit )) a . push ( hit_json ( h ));
out ( "search " + js ( q ) + " " + j ( arr_of ( kinds )) + " " + std :: to_string ( limit ) + " => " + j ( a ));
}
}
}
{
Json a = Json :: array ();
for ( const auto & h : fts . fts_search ( "alpha" , { "record" }, "other" , 10 )) a . push ( hit_json ( h ));
out ( "other profile " + j ( a ));
Json l = Json :: array ();
for ( int n : { 0 , - 5 , 1 , 100 , 500 }) l . push ( static_cast < int64_t > ( fts . fts_search ( "alpha" , {}, "t" , n ). size ()));
out ( "limits " + j ( l ));
}
out ( "== eval" );
out ( "tokens " + j ( arr_of ( rg :: RetrievalEval :: tokens ( "The quick Brown fox jumped_over 123456 abcdefg ABCDEFG caf \xc3\xa9 s r \xc3\xa9 sum \xc3\xa9 s" ))));
out ( "tokens4 " + j ( arr_of ( rg :: RetrievalEval :: tokens ( "The quick Brown fox" , 4 ))));
auto goldens = rg :: RetrievalEval :: goldens_from_vault ( db , "t" );
out ( "goldens " + std :: to_string ( goldens . size ()));
for ( const auto & g : goldens ) {
Json o = Json :: object ();
o . set ( "query" , g . query ). set ( "expected" , ids_json ( g . expected )). set ( "category" , g . category ). set ( "source" , db_json ( g . source ));
out ( "golden " + j ( o ));
}
auto result = rg :: RetrievalEval :: score ( fts , goldens , "t" );
out ( "score " + j ( result_json ( result )));
auto pairs = rg :: RetrievalEval :: implicit_pairs ( db , "t" , false );
out ( "pairs " + j ( pairs_json ( pairs )));
out ( "report: \n " + rg :: RetrievalEval :: format_report ( result , pairs ));
out ( "empty report: \n " + rg :: RetrievalEval :: format_report ( rg :: RetrievalEval :: score ( fts , {}, "t" ), rg :: RetrievalEval :: implicit_pairs ( db , "nobody" , false )));
out ( "small k " + j ( result_json ( rg :: RetrievalEval :: score ( fts , std :: vector < rg :: Golden > ( goldens . begin (), goldens . begin () + 12 ), "t" , { "record" }, 1 , 2 ))));
{
auto ro = []( std :: optional < int > r ) { return r ? Json ( * r ) : Json (); };
out ( "rank_of " + j ( ro ( rg :: RetrievalEval :: rank_of ( DbValue ( "b" ), { DbValue ( "a" ), DbValue ( "b" )}))) + " " + j ( ro ( rg :: RetrievalEval :: rank_of ( DbValue ( "z" ), { DbValue ( "a" )}))) + " " +
j ( ro ( rg :: RetrievalEval :: best_rank ({ DbValue ( "z" ), DbValue ( "a" )}, { DbValue ( "q" ), DbValue ( "a" ), DbValue ( "z" )}))));
Json m = Json :: array ();
m . push ( rg :: RetrievalEval :: hit_at_k ( 3 )). push ( rg :: RetrievalEval :: hit_at_k ( 6 )). push ( rg :: RetrievalEval :: hit_at_k ( std :: nullopt )). push ( rg :: RetrievalEval :: reciprocal_rank ( 4 ));
m . push ( rg :: RetrievalEval :: ndcg_at_k ( 3 )). push ( rg :: RetrievalEval :: ndcg_at_k ( 9 ));
m . push ( rg :: RetrievalEval :: context_precision ({ DbValue ( "a" ), DbValue ( "c" )}, { DbValue ( "a" ), DbValue ( "b" ), DbValue ( "c" ), DbValue ( "d" )}));
m . push ( rg :: RetrievalEval :: context_precision ({}, { DbValue ( "a" )})). push ( rg :: RetrievalEval :: context_precision ({ DbValue ( "x" )}, { DbValue ( "a" )}));
out ( "metrics " + j ( m ));
}
for ( const std :: string & text : std :: vector < std :: string > { "q=alpha \t hits=record:m1,m2,,chunk:4" , "nothing" , "q= \t hits=a" , "a=b=c \t q= spaced \t hits= x ,y " , "q=a \t q=b \t hits=record:z" }) {
auto parsed = rg :: RetrievalEval :: parse_search_event ( text );
Json v ;
if ( parsed ) {
v = Json :: array ();
v . push ( parsed -> first ). push ( arr_of ( parsed -> second ));
}
out ( "parse " + js ( text ) + " => " + j ( v ));
}
out ( "== chunks table" );
std :: string rid = db . query ( "SELECT id FROM records WHERE profile = 't' ORDER BY id LIMIT 1" )[ 0 ][ 0 ]. as_text ();
chunks . add_chunks ( "record" , rid , { "one" , "two" , "three" }, "t" );
Json rows_j = Json :: array ();
std :: vector < int64_t > ids ;
for ( const auto & r : db . query ( "SELECT id, parent_kind, parent_id, idx, text, profile FROM chunks WHERE parent_id = ? ORDER BY idx" , { rid })) {
rows_j . push ( row_json ( r ));
ids . push_back ( r [ 0 ]. as_int ());
}
out ( "chunks " + j ( rows_j ));
auto chunk_obj = []( const std :: map < int64_t , rg :: ChunkRow >& m ) {
Json o = Json :: object ();
for ( const auto & kv : m ) {
Json c = Json :: object ();
c . set ( "parent_kind" , kv . second . parent_kind ). set ( "parent_id" , kv . second . parent_id ). set ( "idx" , kv . second . idx ). set ( "text" , kv . second . text );
o . set ( std :: to_string ( kv . first ), c );
}
return o ;
};
std :: vector < int64_t > ask = ids ;
ask . push_back ( 999999 );
out ( "by ids " + j ( chunk_obj ( chunks . get_chunks_by_ids ( ask , "t" ))));
out ( "by ids empty " + j ( chunk_obj ( chunks . get_chunks_by_ids ({}, "t" ))) + " other " + j ( chunk_obj ( chunks . get_chunks_by_ids ( ids , "other" ))));
chunks . add_chunks ( "record" , rid , {}, "t" );
out ( "after clear " + std :: to_string ( db . query ( "SELECT COUNT(*) FROM chunks WHERE parent_id = ?" , { rid })[ 0 ][ 0 ]. as_int ()));
out ( "== search tool" );
RagApp host ( db , fts , chunks );
rg :: RagTool tool ( host );
std :: vector < Json > calls = {
obj ({{ "query" , "" }}), obj ({{ "query" , "alpha" }}), obj ({{ "query" , "alpha" }, { "limit" , 3 }}), obj ({{ "query" , "alpha" }, { "limit" , "2" }}), obj ({{ "query" , "alpha" }, { "limit" , "x" }}),
obj ({{ "query" , "alpha" }, { "limit" , 0 }}), obj ({{ "query" , "alpha" }, { "limit" , - 2 }}), obj ({{ "query" , "retrieval" }, { "kinds" , arr_of ({ "chunk" })}}),
obj ({{ "query" , "alpha" }, { "kinds" , arr_of ({ "record" })}, { "expand" , true }, { "limit" , 20 }}), obj ({{ "query" , "alpha" }, { "kinds" , arr_of ({ "bogus" })}}), obj ({{ "query" , "alpha" }, { "kinds" , Json :: array ()}}),
obj ({{ "query" , "alpha" }, { "kinds" , "record" }}), obj ({{ "query" , "file" }, { "kinds" , arr_of ({ "audit" })}}), obj ({{ "query" , "message" }, { "kinds" , arr_of ({ "event" })}}),
obj ({{ "query" , "zebra" }, { "kinds" , arr_of ({ "record" , "chunk" , "audit" })}}), obj ({{ "query" , "nothingmatchesthis" }}), obj ({{ "query" , std :: string ( 200 , 'x' )}}), obj ({{ "query" , " spaced " }}),
obj ({{ "query" , "caf \xc3\xa9 r \xc3\xa9 sum \xc3\xa9 " }, { "limit" , 50 }}),
};
for ( const auto & args : calls ) {
std :: string res ;
try {
res = tool . run_search ( args );
} catch ( const std :: exception & e ) {
res = "error: " + PyStr :: short_error ( e . what ());
}
out ( "search " + j ( args ) + " => " + js ( res ));
}
Json logged = Json :: array ();
for ( const auto & r : db . query ( "SELECT profile, role, kind, text FROM events WHERE kind = 'search-query' ORDER BY id DESC LIMIT 25" )) logged . push ( row_json ( r ));
out ( "logged " + j ( logged ));
}
// ------------------------------------------------------------------ telegram scenarios
namespace tg = detz :: telegram ;
class LogRec : public detz :: misc :: LogSink {
public :
void event ( const std :: string & level , const std :: string & component , const std :: string & event , const std :: string & message , const std :: string & profile ,
const std :: string & bot , const std :: string & chat , const Json & meta ) override {
Json a = Json :: array ();
a . push ( level ). push ( component ). push ( event ). push ( message ). push ( profile ). push ( bot ). push ( chat ). push ( meta );
out ( "LOG " + j ( a ));
}
void set_context ( const std :: string & key , const std :: string & value ) override { out ( "CTX set " + key + "=" + value ); }
void clear_context ( const std :: string & key ) override { out ( "CTX pop " + key ); }
};
class TgAgent : public tg :: TelegramAgent {
public :
std :: string home_ ;
std :: string profile () const override { return "t" ; }
std :: string bot () const override { return "main" ; }
std :: string home () const override { return home_ ; }
void reset_history () override { out ( "AGENT reset_history" ); }
std :: string run_turn ( const std :: string & text ) override {
out ( "AGENT run_turn " + js ( text ) + " capture=True" );
if ( text . find ( "explode" ) != std :: string :: npos ) throw std :: runtime_error ( "agent exploded" );
if ( text == "long" ) return std :: string ( 9000 , 'L' );
if ( text == "empty reply" ) return "" ;
return "echo:" + text ;
}
void start_scheduler () override { out ( "start_scheduler called" ); }
};
class TgBox : public tg :: BoxPort {
public :
std :: string ensure_box () override {
out ( "BOX ensure_box" );
if ( std :: getenv ( "MISC_BOX_FAIL" )) throw detz :: misc :: BackendError ( "box down" );
return "eng" ;
}
std :: string box_transcribe ( const std :: string & engine , const std :: string & audio ) override {
// Python prints the audio decoded as latin-1: each byte becomes one code point
std :: string latin ;
for ( unsigned char c : audio ) {
if ( c < 0x80 ) latin += static_cast < char > ( c );
else { latin += static_cast < char > ( 0xC0 | ( c >> 6 )); latin += static_cast < char > ( 0x80 | ( c & 0x3F )); }
}
out ( "BOX transcribe " + engine + " " + js ( latin ));
if ( audio == "AUDIO" ) return "voice says hi" ;
return "error: model failed" ;
}
};
struct StopLoop {};
static std :: string tg_api () { return std :: getenv ( "MISC_TG_API" ); }
static std :: string tg_file () { return std :: getenv ( "MISC_TG_FILE" ); }
static void sc_telegram ( const std :: string & root ) {
LogRec log ;
TgAgent agent ;
TgBox box ;
std :: string home = tai_home ();
agent . home_ = home ;
tg :: TelegramBot bot ( agent , nullptr , & box , log );
bot . set_api ( tg_api (), tg_file ());
out ( "== token" );
std :: string env_path = tg :: TelegramBot :: telegram_env_path ( home );
out ( "env path " + js ( env_path ));
unsetenv ( "TELEGRAM_BOT_TOKEN" );
out ( "no file => " + js ( tg :: TelegramBot :: load_telegram_token ( home )));
std :: vector < std :: pair < std :: string , std :: string >> bodies = {
{ "plain" , "TELEGRAM_BOT_TOKEN=abc123 \n " }, { "quoted" , "TELEGRAM_BOT_TOKEN='abc' \n " }, { "dquoted" , "TELEGRAM_BOT_TOKEN= \" x y \"\n " }, { "spaces" , "TELEGRAM_BOT_TOKEN= spaced \n " },
{ "other first" , "OTHER=1 \n TELEGRAM_BOT_TOKEN=second \n TELEGRAM_BOT_TOKEN=third \n " }, { "none" , "OTHER=1 \n " }, { "empty" , "" }, { "crlf" , "TELEGRAM_BOT_TOKEN=win \r\n " },
{ "noeq" , "TELEGRAM_BOT_TOKEN \n " }, { "eq in value" , "TELEGRAM_BOT_TOKEN=a=b=c \n " }, { "quotes only" , "TELEGRAM_BOT_TOKEN='' \n " }, { "indented" , " TELEGRAM_BOT_TOKEN=nope \n " }};
for ( const auto & b : bodies ) {
write ( env_path , b . second );
out ( "file " + b . first + " => " + js ( tg :: TelegramBot :: load_telegram_token ( home )));
}
setenv ( "TELEGRAM_BOT_TOKEN" , "fromenv" , 1 );
out ( "env wins => " + js ( tg :: TelegramBot :: load_telegram_token ( home )));
setenv ( "TELEGRAM_BOT_TOKEN" , "" , 1 );
out ( "empty env falls back => " + js ( tg :: TelegramBot :: load_telegram_token ( home )));
unsetenv ( "TELEGRAM_BOT_TOKEN" );
PyFs :: remove ( env_path );
out ( "== call / send" );
tg :: Telegram good ( "good" , nullptr , tg_api (), tg_file ());
out ( "getMe " + j ( good . call ( "getMe" , Json :: object ())));
for ( const std :: pair < std :: string , std :: string >& c : std :: vector < std :: pair < std :: string , std :: string >> {{ "bad token" , "bad" }, { "not json" , "nojson" }}) {
try {
tg :: Telegram t ( c . second , nullptr , tg_api (), tg_file ());
out ( c . first + " => " + j ( t . call ( "getMe" , Json :: object ())));
} catch ( const std :: exception & e ) {
out ( c . first + " => raised " + js ( PyStr :: short_error ( e . what ())));
}
}
std :: string e1 ( 4001 , 'x' );
std :: string em ;
for ( int i = 0 ; i < 4001 ; ++ i ) em += " \xc3\xa9 " ;
std :: string smile ;
for ( int i = 0 ; i < 4100 ; ++ i ) smile += " \xf0\x9f\x98\x80 " ;
std :: string lines ;
for ( int i = 0 ; i < 2000 ; ++ i ) lines += "line \n " ;
for ( const std :: string & text : std :: vector < std :: string > { "" , "short" , std :: string ( 4000 , 'S' ), std :: string ( 4001 , 'S' ), std :: string ( 8000 , 'S' ), std :: string ( 8001 , 'S' ), em , smile , lines }) {
tg :: TelegramBot :: telegram_send ( good , Json ( 42 ), text );
}
tg :: TelegramBot :: telegram_send ( good , Json ( "chat-as-string" ), "hi" );
out ( "== updates" );
auto chat = []( const Json & id ) { return obj ({{ "id" , id }}); };
auto msg = [ & ]( const Json & id , std :: initializer_list < std :: pair < const char * , Json >> extra ) {
Json m = Json :: object ();
m . set ( "chat" , chat ( id ));
for ( const auto & p : extra ) m . set ( p . first , p . second );
return m ;
};
std :: vector < Json > updates ;
auto upd = [ & ]( int id , const Json & message ) { updates . push_back ( obj ({{ "update_id" , id }, { "message" , message }})); };
upd ( 1 , msg ( 111 , {{ "text" , "/start" }}));
upd ( 2 , msg ( 111 , {{ "text" , "/new" }}));
upd ( 3 , msg ( 111 , {{ "text" , "hello there" }}));
upd ( 4 , msg ( 111 , {{ "text" , "" }}));
upd ( 5 , msg ( 111 , {{ "text" , " " }}));
upd ( 6 , msg ( 0 , {{ "text" , "zero chat" }}));
upd ( 7 , obj ({{ "text" , "no chat" }}));
updates . push_back ( obj ({{ "update_id" , 8 }}));
upd ( 9 , msg ( 111 , {}));
upd ( 10 , msg ( 111 , {{ "text" , "explode please" }}));
upd ( 11 , msg ( 111 , {{ "text" , "long" }}));
upd ( 12 , msg ( 111 , {{ "text" , "empty reply" }}));
upd ( 13 , msg ( 222 , {{ "voice" , obj ({{ "file_id" , "f1" }})}}));
upd ( 14 , msg ( 222 , {{ "audio" , obj ({{ "file_id" , "f1" }})}}));
upd ( 15 , msg ( 222 , {{ "voice" , obj ({{ "file_id" , "nofile" }})}}));
upd ( 16 , msg ( 222 , {{ "voice" , obj ({{ "file_id" , "fbad" }})}}));
upd ( 17 , msg ( 222 , {{ "voice" , obj ({{ "file_id" , "fmodel" }})}}));
upd ( 18 , msg ( 222 , {{ "voice" , Json :: object ()}, { "text" , "text with empty voice" }}));
upd ( 19 , msg ( 222 , {{ "voice" , obj ({{ "file_id" , "fmissingfile" }})}}));
upd ( 20 , msg ( Json ( "str-chat" ), {{ "text" , "string chat id" }}));
upd ( 21 , msg ( 111 , {{ "text" , "unicode caf \xc3\xa9 \xf0\x9f\x98\x80 " }}));
for ( const auto & update : updates ) {
out ( "-- update " + j ( update ));
try {
bot . handle_telegram_update ( good , update );
} catch ( const std :: exception & e ) {
out ( "raised " + js ( PyStr :: short_error ( e . what ())));
}
}
setenv ( "MISC_BOX_FAIL" , "1" , 1 );
out ( "-- box failing" );
try {
bot . handle_telegram_update ( good , obj ({{ "update_id" , 30 }, { "message" , msg ( 5 , {{ "voice" , obj ({{ "file_id" , "f1" }})}})}}));
} catch ( const std :: exception & e ) {
out ( "raised " + js ( PyStr :: short_error ( e . what ())));
}
unsetenv ( "MISC_BOX_FAIL" );
out ( "== run_telegram_bot" );
struct Run { const char * label ; const char * token ; };
for ( const Run & r : { Run { "missing" , nullptr }, Run { "bad auth" , "bad" }, Run { "not json" , "nojson" }, Run { "no username" , "noname" }, Run { "good" , "good" }}) {
unsetenv ( "TELEGRAM_BOT_TOKEN" );
if ( r . token ) setenv ( "TELEGRAM_BOT_TOKEN" , r . token , 1 );
out ( std :: string ( "-- run " ) + r . label );
std :: cout . flush ();
try {
int res = bot . run_telegram_bot ( nullptr , []( int seconds ) {
out ( "sleep " + std :: to_string ( seconds ));
throw StopLoop ();
});
out ( "returned " + std :: to_string ( res ));
} catch ( const StopLoop & ) {
out ( "stopped by sleep" );
}
std :: cout . flush ();
}
( void ) root ;
}
static void sc_telegram_install ( const std :: string & root ) {
LogRec log ;
TgAgent agent ;
TgBox box ;
FakeBox fbox ;
set_box ( fbox , std :: string ( "podman" ));
ins :: StdIo io ;
ins :: InstallContext ctx = install_ctx ();
ctx . telegram_api = tg_api ();
ins :: Installer inst ( ctx , fbox , io );
std :: string home = tai_home ();
struct T { const char * label ; const char * token ; };
for ( const T & t : { T { "good" , "good" }, T { "bad" , "bad" }, T { "nojson" , "nojson" }, T { "noname" , "noname" }}) {
setenv ( "TELEGRAM_BOT_TOKEN" , t . token , 1 );
out ( std :: string ( "-- install_telegram " ) + t . label );
std :: cout . flush ();
int res = inst . install_telegram ();
out ( "returned " + std :: to_string ( res ));
out ( "unit exists " + py_bool ( PyFs :: exists ( PyFs :: home () + "/.config/systemd/user/tai-telegram.service" )) + " env exists " +
py_bool ( PyFs :: exists ( tg :: TelegramBot :: telegram_env_path ( home ))));
}
unsetenv ( "TELEGRAM_BOT_TOKEN" );
out ( "-- install_telegram without token (stdin closed)" );
std :: cout . flush ();
out ( "returned " + std :: to_string ( inst . install_telegram ()));
out ( "-- install_telegram box failing" );
set_box ( fbox , std :: string ( "podman" ), "running" , "venv ready" , "no engine here" );
setenv ( "TELEGRAM_BOT_TOKEN" , "good" , 1 );
out ( "returned " + std :: to_string ( inst . install_telegram ()));
set_box ( fbox , std :: string ( "podman" ));
out ( "-- op_telegram_service" );
for ( const char * token : { "good" , "bad" , "nojson" , "noname" }) {
setenv ( "TELEGRAM_BOT_TOKEN" , token , 1 );
for ( const std :: string mode : { "install" , "install" , "reinstall" , "upgrade" , "uninstall" , "uninstall" }) {
out ( std :: string ( "service " ) + token + " " + mode + " => " + js ( inst . op_telegram_service ( mode , home )));
}
}
unsetenv ( "TELEGRAM_BOT_TOKEN" );
write ( tg :: TelegramBot :: telegram_env_path ( home ), "TELEGRAM_BOT_TOKEN=good \n " );
out ( "service from env file => " + js ( inst . op_telegram_service ( "install" , home )));
out ( "-- uninstall_telegram" );
out ( "returned " + std :: to_string ( inst . uninstall_telegram ()));
set_box ( fbox , std :: nullopt );
out ( "returned noengine " + std :: to_string ( inst . uninstall_telegram ()));
( void ) root ;
}
// ------------------------------------------------------------------ release / audit scenarios
using detz :: install :: SelfRelease ;
class NoRecords : public ins :: FileRecordPort {
public :
void upsert_file_record ( const std :: string & , const std :: string & , const std :: optional < int64_t >& ) override {} // records table: store module
};
class RelHost : public ins :: ReleaseHost {
public :
std :: vector < std :: string > approvals ;
bool approve = true ;
std :: string script , home_ ;
ins :: AuditVault * vault_ = nullptr ;
bool ask_approval ( const std :: string & w ) override { approvals . push_back ( w ); return approve ; }
std :: string home () const override { return home_ ; }
std :: string audit_actor () const override { return "main" ; }
ins :: AuditPort & store () override { return * vault_ ; }
std :: string script_file () const override { return script ; }
};
static std :: string copy_file_bytes ( const std :: string & from , const std :: string & to ) {
write ( to , PyFs :: read_bytes ( from ));
return to ;
}
static void sc_release ( const std :: string & root ) {
SqliteDb db ( tai_home () + "/memory.db" , 30 , true );
ins :: AuditVault vault ( db , "t" );
NoRecords records ;
std :: string script = copy_file_bytes ( install_ctx (). script_path , root + "/script.py" );
std :: string folder = root + "/backups" ;
out ( "== versions" );
struct V { const char * cur ; const char * part ; };
for ( const V & v : { V { "1.2.3" , "patch" }, V { "1.2.3" , "minor" }, V { "1.2.3" , "major" }, V { "9.9.9" , "patch" }, V { "1.2.3" , "bogus" }, V { "1.2" , "patch" }, V { "a.b.c" , "patch" }, V { "1.2.3.4" , "patch" }}) {
try {
out ( std :: string ( "next " ) + v . cur + " " + v . part + " => " + SelfRelease :: next_version ( v . cur , v . part ));
} catch ( const std :: exception & e ) {
out ( std :: string ( "next " ) + v . cur + " " + v . part + " => raised " + js ( e . what ()));
}
}
out ( "== bump" );
for ( const char * part : { "patch" , "minor" , "major" , "patch" }) {
auto r = SelfRelease :: release_bump ( script , part );
Json a = Json :: array ();
a . push ( r . first ). push ( r . second );
out ( std :: string ( "bump " ) + part + " => " + j ( a ));
}
{
std :: string text = PyFs :: read_text ( script );
std :: vector < std :: string > vl ;
for ( const auto & l : PyStr :: splitlines ( text )) {
if ( l . rfind ( "VERSION = " , 0 ) == 0 ) vl . push_back ( l );
}
out ( "version line " + j ( arr_of ( vl )));
}
write ( root + "/nov.py" , "print('x') \n " );
for ( const std :: string & f : { root + "/nov.py" , root + "/missing.py" }) {
try {
SelfRelease :: release_bump ( f , "patch" );
} catch ( const std :: exception & e ) {
out ( "bump error " + js ( replace_root ( e . what (), root )));
}
}
write ( root + "/crlf.py" , "a \r\n VERSION = \" 1.0.0 \"\r\n b \r\n " );
{
auto r = SelfRelease :: release_bump ( root + "/crlf.py" , "patch" );
Json a = Json :: array ();
a . push ( r . first ). push ( r . second );
out ( "crlf bump " + j ( a ) + " " + js ( PyFs :: read_bytes ( root + "/crlf.py" )));
}
out ( "== snapshots and pruning" );
auto snap = SelfRelease :: snapshot_self ( script , folder , "9.9.9" );
out ( "snapshot " + js ( PyFs :: basename ( snap . first )) + " " + snap . second );
out ( "has digest " + py_bool ( SelfRelease :: backup_has_digest ( folder , snap . second )) + " " + py_bool ( SelfRelease :: backup_has_digest ( folder , "deadbeef" )));
out ( "has digest nofolder " + py_bool ( SelfRelease :: backup_has_digest ( root + "/nofolder" , snap . second )));
for ( int i = 0 ; i < 14 ; ++ i ) {
char name [ 128 ];
std :: snprintf ( name , sizeof name , "/tai-0.0.%d-20200101T000000Z-%08d.py" , i , i );
write ( folder + name , "x" );
struct timespec ts [ 2 ] = {{ 1000 + i , 0 }, { 1000 + i , 0 }};
utimensat ( AT_FDCWD , ( folder + name ). c_str (), ts , 0 );
}
write ( folder + "/notes.txt" , "keep" );
out ( "pruned " + std :: to_string ( SelfRelease :: prune_backups ( folder )));
out ( "left " + PyStr :: replace_all ( j ( arr_of ( PyFs :: listdir_sorted ( folder ))), PyFs :: basename ( snap . first ), "<SNAP>" ));
out ( "prune missing " + std :: to_string ( SelfRelease :: prune_backups ( root + "/nofolder" )));
out ( "== ensure_self_backup" );
PyFs :: rmtree ( folder );
auto first = SelfRelease :: ensure_self_backup ( tai_home (), & vault , & records , script , "1.44.2" );
out ( "ensure first " + ( first ? js ( PyFs :: basename ( * first )) : std :: string ( "null" )));
auto second = SelfRelease :: ensure_self_backup ( tai_home (), & vault , & records , script , "1.44.2" );
out ( "ensure second " + ( second ? js ( PyFs :: basename ( * second )) : std :: string ( "null" )));
{
Json rows = Json :: array ();
for ( const auto & r : db . query ( "SELECT actor, action, path, message, old_size, new_size, tags FROM audit ORDER BY id" )) rows . push ( row_json ( r ));
out ( "audit " + j ( rows ));
}
out ( "== do_release" );
try {
SelfRelease :: do_release ( vault , script , folder , "patch" , " " );
} catch ( const std :: exception & e ) {
out ( "blank message " + js ( e . what ()));
}
{
auto r = SelfRelease :: do_release ( vault , script , folder , "minor" , " ship it " , "tester" );
Json a = Json :: array ();
a . push ( r . old_version ). push ( r . new_version ). push ( PyFs :: basename ( r . dest )). push ( r . row_id );
out ( "do_release " + j ( a ));
}
out ( "== release tool" );
RelHost host ;
host . script = script ;
host . home_ = tai_home ();
host . vault_ = & vault ;
ins :: ReleaseTool tool ( host );
auto rel = [ & ]( const Json & args ) {
try {
return tool . run_release ( args );
} catch ( const std :: exception & e ) {
return "error: " + PyStr :: short_error ( e . what ());
}
};
for ( const Json & args : std :: vector < Json > { obj ({{ "part" , "" }, { "message" , "m" }}), obj ({{ "part" , "patch" }, { "message" , "" }}), obj ({{ "part" , "huge" }, { "message" , "m" }}),
obj ({{ "part" , "Patch" }, { "message" , "tool release" }}), obj ({{ "part" , "major" }, { "message" , std :: string ( 300 , 'm' )}})}) {
out ( "release " + j ( args ) + " => " + js ( replace_root ( rel ( args ), root )));
}
host . approve = false ;
out ( "release denied => " + js ( rel ( obj ({{ "part" , "patch" }, { "message" , "no" }}))));
host . approve = true ;
write ( script , "nothing here \n " );
out ( "release no version => " + js ( rel ( obj ({{ "part" , "patch" }, { "message" , "m" }}))));
out ( "approvals " + j ( arr_of ( host . approvals )));
out ( "== capped helpers" );
{
auto c0 = SelfRelease :: capped_text ( std :: nullopt );
auto c1 = SelfRelease :: capped_text ( std :: string ( "abc" ));
std :: string e ;
for ( int i = 0 ; i < 20001 ; ++ i ) e += " \xc3\xa9 " ;
auto c2 = SelfRelease :: capped_text ( e );
auto c3 = SelfRelease :: capped_text ( std :: string ( 20001 , 'x' ));
auto pair_json = []( const std :: pair < std :: optional < std :: string > , std :: optional < int64_t >>& p ) {
Json a = Json :: array ();
a . push ( p . first ? Json ( * p . first ) : Json ()). push ( p . second ? Json ( * p . second ) : Json ());
return a ;
};
Json all = Json :: array ();
all . push ( pair_json ( c0 )). push ( pair_json ( c1 )). push ( Json ( * c2 . second ));
all . push ( Json ( PyStr :: suffix ( * c3 . first , 60 ))). push ( SelfRelease :: trunc_marker ( 5 ));
out ( "capped " + j ( all ));
}
std :: string big = "line \r\n second \r third \n " ;
for ( int i = 0 ; i < 30000 ; ++ i ) big += " \xc3\xa9 " ;
write ( root + "/big.txt" , big );
for ( int cap : { 20000 , 50 , 100000 }) {
auto r = SelfRelease :: read_capped ( root + "/big.txt" , static_cast < std :: size_t > ( cap ));
out ( "read_capped " + std :: to_string ( cap ) + " => " + ( r . text ? js ( PyStr :: prefix ( * r . text , 40 )) : std :: string ( "null" )) + " " + ( r . size ? std :: to_string ( * r . size ) : std :: string ( "null" )));
}
write ( root + "/bad.bin" , std :: string ( "ok \xff\xfe bad \xc3 end" ));
{
auto r = SelfRelease :: read_capped ( root + "/bad.bin" );
Json a = Json :: array ();
a . push ( r . text ? Json ( * r . text ) : Json ()). push ( r . size ? Json ( * r . size ) : Json ());
out ( "read_capped invalid " + j ( a ));
}
{
auto r = SelfRelease :: read_capped ( root + "/missing" );
Json a = Json :: array ();
a . push ( Json ()). push ( Json ());
out ( "read_capped missing " + j ( a ));
( void ) r ;
}
}
class AuditApp : public ins :: AuditHost {
public :
std :: vector < std :: string > approvals ;
bool approve = true ;
ins :: AuditVault * vault_ = nullptr ;
rg :: FtsSearch * fts_ = nullptr ;
bool ask_approval ( const std :: string & w ) override { approvals . push_back ( w ); return approve ; }
std :: string active_profile () const override { return "t" ; }
ins :: AuditVault & vault () override { return * vault_ ; }
rg :: FtsSearch & fts () override { return * fts_ ; }
void read_files_add ( const std :: string & ) override {}
void audit_file ( const std :: string & action , const std :: string & path , const std :: optional < std :: string >& o , const std :: optional < std :: string >& n , const std :: string & message ) override {
vault_ -> audit_event_full ( "main" , action , path , message , o , n , { "file" , action }, std :: nullopt , std :: nullopt , "t" );
}
void upsert_file_record ( const std :: string & , const std :: string & , const std :: string & ) override {} // records table: store module
void note_diff ( const std :: string & , const std :: optional < std :: string >& , const std :: optional < std :: string >& ) override {}
std :: string box_restore ( const std :: string & , const std :: string & , const std :: string & ) override { return "box restore unsupported in this test" ; }
};
static void sc_audit ( const std :: string & root ) {
SqliteDb db ( tai_home () + "/memory.db" , 30 , true );
ins :: AuditVault vault ( db , "t" );
rg :: FtsSearch fts ( db , "t" );
AuditApp app ;
app . vault_ = & vault ;
app . fts_ = & fts ;
ins :: AuditTool tool ( app );
auto call = [ & ]( const std :: string & name , const Json & args ) {
std :: string res ;
try {
res = name == "audit" ? tool . run_audit ( args ) : name == "tags" ? tool . run_tags ( args ) : tool . run_restore ( args );
} catch ( const std :: exception & e ) {
res = "error: " + PyStr :: short_error ( e . what ());
}
out ( name + " " + j ( args ) + " => " + js ( replace_root ( res , root )));
};
out ( "== audit" );
for ( const Json & a : std :: vector < Json > { Json :: object (), obj ({{ "limit" , 3 }}), obj ({{ "path" , "area/a.txt" }}), obj ({{ "tag" , "file" }}), obj ({{ "tag" , "nomatch" }}), obj ({{ "query" , "alpha" }}),
obj ({{ "query" , "write" }}), obj ({{ "query" , "zzzz" }}), obj ({{ "limit" , "x" }}), obj ({{ "limit" , 500 }}), obj ({{ "query" , "unicode" }})})
call ( "audit" , a );
out ( "== tags" );
for ( const Json & a : std :: vector < Json > { Json :: object (), obj ({{ "prefix" , "al" }}), obj ({{ "prefix" , "A_" }}), obj ({{ "prefix" , "a%" }}), obj ({{ "prefix" , "zzz" }}), obj ({{ "limit" , 1 }}),
obj ({{ "limit" , "x" }}), obj ({{ "prefix" , " Al " }})})
call ( "tags" , a );
out ( "== restore" );
for ( const Json & a : std :: vector < Json > { Json :: object (), obj ({{ "id" , "x" }}), obj ({{ "id" , 9999 }}), obj ({{ "id" , 6 }}), obj ({{ "id" , 7 }}), obj ({{ "id" , 1 }}), obj ({{ "id" , 3 }}), obj ({{ "id" , 4 }}),
obj ({{ "id" , 5 }}), obj ({{ "id" , 12 }}), obj ({{ "id" , 10 }}), obj ({{ "id" , 11 }})})
call ( "restore" , a );
for ( const std :: string rel : { "a.txt" , "sub/deep/r.txt" , "u.txt" }) {
std :: string path = "area/" + rel ;
out ( "file " + rel + " " + ( PyFs :: exists ( path ) ? js ( read ( path )) : std :: string ( "null" )));
}
app . approve = false ;
call ( "restore" , obj ({{ "id" , 2 }}));
app . approve = true ;
Json ap = Json :: array ();
for ( const auto & a : app . approvals ) ap . push ( replace_root ( a , root ));
out ( "approvals " + j ( ap ));
}
int main ( int argc , char ** argv ) {
if ( argc < 3 ) return 2 ;
std :: string name = argv [ 1 ], root = argv [ 2 ];
bool prepare = argc > 3 && std :: string ( argv [ 3 ]) == "prepare" ;
const char * data_dir = std :: getenv ( "MISC_DATA_DIR" );
DATA_DIR = data_dir ? data_dir : "tests/misc_data" ;
if ( chdir (( root + "/proj" ). c_str ()) != 0 ) return 2 ;
if ( prepare ) return 0 ; // C++ never prepares: the Python side builds fixtures with the real tai.py
static const std :: map < std :: string , std :: function < void ( const std :: string & ) >> scenarios = {
{ "json" , sc_json }, { "datetime" , sc_datetime }, { "chunk" , sc_chunk }, { "fts" , sc_fts },
{ "skills_data" , sc_skills_data }, { "skills_files" , sc_skills_files }, { "skills_ops" , sc_skills_ops },
{ "install_hooks" , sc_install_hooks }, { "install_hooks_noshell" , sc_install_hooks }, { "install_ops" , sc_install_ops },
{ "install_noengine" , sc_install_noengine }, { "vault_line" , sc_vault_line }, { "sched" , sc_sched }, { "rag" , sc_rag }, { "release" , sc_release }, { "audit" , sc_audit }, { "telegram" , sc_telegram }, { "telegram_install" , sc_telegram_install },
};
auto it = scenarios . find ( name );
if ( it == scenarios . end ()) {
std :: cerr << "unknown scenario " << name << " \n " ;
return 2 ;
}
it -> second ( root );
return 0 ;
}