LeGittingEdition
By Ethan G Appleby.
Wiki topics:
🔓 · Open Source
LeGittingEdition
By Ethan G Appleby.
Obviously this is a Do Not Run!!! version due to no safety handling (missing) and also this is not to be confused with well… LCE it is clearly LeGittingEdition launching framework of the..
// ============================================================================
// LeGitingEdition (lge)
// A delta layer on top of Git for fork-driven software ecosystems.
//
// Adds: fork registry, usage telemetry, delta-compressed binary distribution,
// branch browsing, AI attribution tracking, and community metrics.
//
// Build: g++ -std=c++17 -O2 -o lge lge.cpp -lsqlite3 -lz -lssl -lcrypto
// ============================================================================
#include <algorithm>
#include <cassert>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <numeric>
#include <optional>
#include <random>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <variant>
#include <vector>
#include <sqlite3.h>
#include <zlib.h>
#include <openssl/sha.h>
namespace fs = std::filesystem;
// ============================================================================
// CONFIG & PATHS
// ============================================================================
namespace config {
inline fs::path home_dir() { return fs::path(std::getenv("HOME")) / ".lge"; }
inline fs::path registry_db() { return home_dir() / "registry.db"; }
inline fs::path telemetry_db() { return home_dir() / "telemetry.db"; }
inline fs::path binary_cache() { return home_dir() / "cache"; }
inline fs::path delta_store() { return home_dir() / "deltas"; }
inline fs::path branches_dir() { return home_dir() / "branches"; }
inline fs::path config_file() { return home_dir() / "config.json"; }
constexpr size_t BLOCK_SIZE = 4096;
constexpr const char* VERSION = "0.1.0";
} // namespace config
// ============================================================================
// UTILITY HELPERS
// ============================================================================
namespace util {
std::string sha256_hex(const std::string& input) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char*>(input.data()),
input.size(), hash);
std::ostringstream oss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
oss << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(hash[i]);
return oss.str();
}
std::string sha256_bytes(const std::vector<uint8_t>& data) {
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256(data.data(), data.size(), hash);
std::ostringstream oss;
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
oss << std::hex << std::setfill('0') << std::setw(2)
<< static_cast<int>(hash[i]);
return oss.str();
}
// FNV-1a fast block hash
std::string block_hash(const uint8_t* data, size_t len) {
uint64_t h = 0xcbf29ce484222325ULL;
for (size_t i = 0; i < len; ++i) {
h ^= data[i];
h *= 0x100000001b3ULL;
}
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(16) << h;
return oss.str();
}
std::string random_hex(size_t bytes) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dist(0, 255);
std::ostringstream oss;
for (size_t i = 0; i < bytes; ++i)
oss << std::hex << std::setfill('0') << std::setw(2) << dist(gen);
return oss.str();
}
std::string utc_now() {
auto now = std::chrono::system_clock::now();
auto t = std::chrono::system_clock::to_time_t(now);
std::tm tm{};
gmtime_r(&t, &tm);
char buf[32];
std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tm);
return buf;
}
std::time_t parse_iso(const std::string& iso) {
std::tm tm{};
strptime(iso.c_str(), "%Y-%m-%dT%H:%M:%S", &tm);
return timegm(&tm);
}
struct ProcResult {
int exit_code;
std::string out;
std::string err;
};
ProcResult run_cmd(const std::vector<std::string>& args) {
std::string cmd;
for (auto& a : args) cmd += "'" + a + "' ";
cmd += "2>/tmp/lge_stderr";
FILE* fp = popen(cmd.c_str(), "r");
if (!fp) return {-1, "", ""};
std::string output;
char buf[4096];
while (fgets(buf, sizeof(buf), fp)) output += buf;
int status = pclose(fp);
int code = WEXITSTATUS(status);
std::string errout;
std::ifstream errf("/tmp/lge_stderr");
if (errf) { std::ostringstream oss; oss << errf.rdbuf(); errout = oss.str(); }
return {code, output, errout};
}
std::vector<uint8_t> read_file_bytes(const fs::path& path) {
std::ifstream f(path, std::ios::binary);
if (!f) return {};
return {std::istreambuf_iterator<char>(f), {}};
}
void write_file_bytes(const fs::path& path, const std::vector<uint8_t>& data) {
std::ofstream f(path, std::ios::binary);
f.write(reinterpret_cast<const char*>(data.data()), data.size());
}
std::string read_file_text(const fs::path& path) {
std::ifstream f(path);
if (!f) return "";
std::ostringstream oss; oss << f.rdbuf();
return oss.str();
}
void write_file_text(const fs::path& path, const std::string& text) {
std::ofstream f(path); f << text;
}
std::string trim(const std::string& s) {
auto start = s.find_first_not_of(" \t\r\n");
auto end = s.find_last_not_of(" \t\r\n");
if (start == std::string::npos) return "";
return s.substr(start, end - start + 1);
}
std::vector<std::string> split(const std::string& s, char delim) {
std::vector<std::string> parts;
std::istringstream ss(s);
std::string part;
while (std::getline(ss, part, delim))
if (!part.empty()) parts.push_back(part);
return parts;
}
std::vector<uint8_t> zlib_compress(const std::vector<uint8_t>& data) {
uLongf bound = compressBound(data.size());
std::vector<uint8_t> out(bound);
int rc = compress2(out.data(), &bound, data.data(), data.size(), 9);
if (rc != Z_OK) return {};
out.resize(bound);
return out;
}
std::vector<uint8_t> zlib_decompress(const std::vector<uint8_t>& data) {
size_t out_size = data.size() * 10;
std::vector<uint8_t> out(out_size);
uLongf actual = out_size;
while (true) {
int rc = uncompress(out.data(), &actual, data.data(), data.size());
if (rc == Z_OK) { out.resize(actual); return out; }
if (rc == Z_BUF_ERROR) {
out_size *= 2; out.resize(out_size); actual = out_size;
} else { return {}; }
}
}
} // namespace util
// ============================================================================
// MINIMAL JSON
// ============================================================================
namespace json {
struct Value;
using Object = std::map<std::string, Value>;
struct Value {
std::variant<std::string, double, bool, Object> data;
Value() : data(std::string("")) {}
Value(const std::string& s) : data(s) {}
Value(const char* s) : data(std::string(s)) {}
Value(double d) : data(d) {}
Value(bool b) : data(b) {}
Value(const Object& o) : data(o) {}
bool is_string() const { return std::holds_alternative<std::string>(data); }
bool is_number() const { return std::holds_alternative<double>(data); }
bool is_bool() const { return std::holds_alternative<bool>(data); }
bool is_object() const { return std::holds_alternative<Object>(data); }
const std::string& str() const { return std::get<std::string>(data); }
double num() const { return std::get<double>(data); }
bool boolean() const { return std::get<bool>(data); }
const Object& obj() const { return std::get<Object>(data); }
Object& obj_mut() { return std::get<Object>(data); }
};
std::string serialize(const Value& v, int indent = 0) {
std::string pad(indent, ' ');
std::string pad2(indent + 2, ' ');
if (v.is_bool()) return v.boolean() ? "true" : "false";
if (v.is_number()) {
std::ostringstream oss; oss << v.num(); return oss.str();
}
if (v.is_string()) return "\"" + v.str() + "\"";
if (v.is_object()) {
std::ostringstream oss;
oss << "{\n";
auto& obj = v.obj();
size_t i = 0;
for (auto& [k, val] : obj) {
oss << pad2 << "\"" << k << "\": " << serialize(val, indent + 2);
if (++i < obj.size()) oss << ",";
oss << "\n";
}
oss << pad << "}";
return oss.str();
}
return "null";
}
class Parser {
std::string_view src;
size_t pos = 0;
void skip_ws() { while (pos < src.size() && std::isspace(src[pos])) ++pos; }
char peek() { skip_ws(); return pos < src.size() ? src[pos] : 0; }
char next() { skip_ws(); return pos < src.size() ? src[pos++] : 0; }
std::string parse_string() {
next();
std::string result;
while (pos < src.size() && src[pos] != '"') {
if (src[pos] == '\\') { ++pos; result += src[pos++]; }
else result += src[pos++];
}
if (pos < src.size()) ++pos;
return result;
}
Value parse_value() {
skip_ws();
if (pos >= src.size()) return Value("");
char c = src[pos];
if (c == '"') return Value(parse_string());
if (c == '{') return Value(parse_object());
if (c == 't') { pos += 4; return Value(true); }
if (c == 'f') { pos += 5; return Value(false); }
if (c == 'n') { pos += 4; return Value(""); }
size_t start = pos;
if (src[pos] == '-') ++pos;
while (pos < src.size() && (std::isdigit(src[pos]) || src[pos] == '.')) ++pos;
return Value(std::stod(std::string(src.substr(start, pos - start))));
}
Object parse_object() {
next();
Object obj;
while (peek() != '}' && pos < src.size()) {
std::string key = parse_string();
next();
obj[key] = parse_value();
if (peek() == ',') next();
}
if (pos < src.size()) ++pos;
return obj;
}
public:
Value parse(const std::string& input) {
src = input; pos = 0; return parse_value();
}
};
Value parse(const std::string& input) { Parser p; return p.parse(input); }
} // namespace json
// ============================================================================
// SQLITE RAII WRAPPER
// ============================================================================
class Database {
sqlite3* db_ = nullptr;
public:
Database() = default;
explicit Database(const fs::path& path) {
if (sqlite3_open(path.c_str(), &db_) != SQLITE_OK) {
std::cerr << "[db] Failed to open " << path << ": "
<< sqlite3_errmsg(db_) << "\n";
db_ = nullptr;
}
}
~Database() { if (db_) sqlite3_close(db_); }
Database(Database&& o) noexcept : db_(o.db_) { o.db_ = nullptr; }
Database& operator=(Database&& o) noexcept {
if (db_) sqlite3_close(db_);
db_ = o.db_; o.db_ = nullptr;
return *this;
}
Database(const Database&) = delete;
Database& operator=(const Database&) = delete;
bool ok() const { return db_ != nullptr; }
bool exec(const std::string& sql) {
char* err = nullptr;
int rc = sqlite3_exec(db_, sql.c_str(), nullptr, nullptr, &err);
if (rc != SQLITE_OK) {
std::cerr << "[db] Error: " << (err ? err : "unknown") << "\n";
sqlite3_free(err);
return false;
}
return true;
}
using Row = std::map<std::string, std::string>;
std::vector<Row> query(const std::string& sql,
const std::vector<std::string>& params = {}) {
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
std::cerr << "[db] Prepare: " << sqlite3_errmsg(db_) << "\n";
return {};
}
for (size_t i = 0; i < params.size(); ++i)
sqlite3_bind_text(stmt, i + 1, params[i].c_str(), -1, SQLITE_TRANSIENT);
std::vector<Row> rows;
int cols = sqlite3_column_count(stmt);
while (sqlite3_step(stmt) == SQLITE_ROW) {
Row row;
for (int c = 0; c < cols; ++c) {
const char* name = sqlite3_column_name(stmt, c);
const char* val = reinterpret_cast<const char*>(
sqlite3_column_text(stmt, c));
row[name] = val ? val : "";
}
rows.push_back(std::move(row));
}
sqlite3_finalize(stmt);
return rows;
}
bool execute(const std::string& sql, const std::vector<std::string>& params) {
sqlite3_stmt* stmt = nullptr;
if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) {
std::cerr << "[db] Prepare: " << sqlite3_errmsg(db_) << "\n";
return false;
}
for (size_t i = 0; i < params.size(); ++i)
sqlite3_bind_text(stmt, i + 1, params[i].c_str(), -1, SQLITE_TRANSIENT);
int rc = sqlite3_step(stmt);
sqlite3_finalize(stmt);
return rc == SQLITE_DONE;
}
std::string scalar(const std::string& sql,
const std::vector<std::string>& params = {}) {
auto rows = query(sql, params);
if (rows.empty()) return "0";
return rows[0].begin()->second;
}
};
// ============================================================================
// SCHEMA INITIALIZATION
// ============================================================================
namespace schema {
void init_registry(Database& db) {
db.exec(R"SQL(
CREATE TABLE IF NOT EXISTS forks (
id TEXT PRIMARY KEY,
url TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT DEFAULT '',
parent_id TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
last_seen TEXT DEFAULT CURRENT_TIMESTAMP,
stars INTEGER DEFAULT 0,
fork_count INTEGER DEFAULT 0,
open_issues INTEGER DEFAULT 0,
FOREIGN KEY (parent_id) REFERENCES forks(id)
);
CREATE TABLE IF NOT EXISTS branches (
id TEXT PRIMARY KEY,
fork_id TEXT NOT NULL,
name TEXT NOT NULL,
head_commit TEXT,
build_status TEXT DEFAULT 'unknown',
last_updated TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (fork_id) REFERENCES forks(id)
);
CREATE TABLE IF NOT EXISTS commits (
hash TEXT PRIMARY KEY,
fork_id TEXT NOT NULL,
branch_id TEXT,
author TEXT,
message TEXT,
timestamp TEXT,
ai_authored_lines INTEGER DEFAULT 0,
human_authored_lines INTEGER DEFAULT 0,
ai_ratio REAL DEFAULT 0.0,
parent_hash TEXT,
FOREIGN KEY (fork_id) REFERENCES forks(id)
);
CREATE TABLE IF NOT EXISTS builds (
commit_hash TEXT PRIMARY KEY,
binary_hash TEXT,
binary_size INTEGER,
delta_from TEXT,
delta_size INTEGER,
build_time_seconds REAL,
platform TEXT DEFAULT 'native',
cached_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (commit_hash) REFERENCES commits(hash)
);
)SQL");
}
void init_telemetry(Database& db) {
db.exec(R"SQL(
CREATE TABLE IF NOT EXISTS sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_hash TEXT NOT NULL,
fork_id TEXT NOT NULL,
branch_id TEXT NOT NULL,
commit_hash TEXT NOT NULL,
start_time TEXT NOT NULL,
duration_seconds INTEGER NOT NULL,
platform TEXT DEFAULT 'native'
);
CREATE TABLE IF NOT EXISTS commit_metrics (
commit_hash TEXT PRIMARY KEY,
total_usage_hours REAL DEFAULT 0,
unique_users INTEGER DEFAULT 0,
avg_session_minutes REAL DEFAULT 0,
median_session_minutes REAL DEFAULT 0,
usage_trend REAL DEFAULT 0,
first_used TEXT,
last_used TEXT
);
CREATE TABLE IF NOT EXISTS ai_signal (
commit_hash TEXT PRIMARY KEY,
ai_ratio REAL NOT NULL,
usage_delta_percent REAL,
session_length_delta_percent REAL,
retention_delta_percent REAL,
signal_confidence REAL DEFAULT 0,
sample_size INTEGER DEFAULT 0
);
)SQL");
}
} // namespace schema
// ============================================================================
// FORK REGISTRY
// ============================================================================
class ForkRegistry {
Database& db_;
public:
explicit ForkRegistry(Database& db) : db_(db) {}
std::string register_fork(const std::string& url,
const std::string& name,
const std::string& desc = "",
const std::string& parent_id = "") {
std::string id = util::sha256_hex(url).substr(0, 12);
db_.execute(
"INSERT OR REPLACE INTO forks (id, url, name, description, parent_id) "
"VALUES (?, ?, ?, ?, ?)",
{id, url, name, desc, parent_id}
);
std::cout << "[registry] Registered: " << name << " (" << id << ")\n";
return id;
}
void index_fork(const std::string& fork_id) {
auto rows = db_.query("SELECT * FROM forks WHERE id = ?", {fork_id});
if (rows.empty()) {
std::cout << "[registry] Fork " << fork_id << " not found\n";
return;
}
auto& fork = rows[0];
std::string url = fork.at("url");
std::cout << "[registry] Indexing " << fork.at("name") << "...\n";
auto result = util::run_cmd({"git", "ls-remote", "--heads", url});
if (result.exit_code != 0) {
std::cout << "[registry] Failed to reach " << url << "\n";
return;
}
for (auto& line : util::split(result.out, '\n')) {
auto trimmed = util::trim(line);
if (trimmed.empty()) continue;
auto tab = trimmed.find('\t');
if (tab == std::string::npos) continue;
std::string hash = trimmed.substr(0, tab);
std::string ref = trimmed.substr(tab + 1);
const std::string prefix = "refs/heads/";
if (ref.find(prefix) == 0) ref = ref.substr(prefix.size());
std::string bid = fork_id + ":" + ref;
db_.execute(
"INSERT OR REPLACE INTO branches "
"(id, fork_id, name, head_commit, last_updated) "
"VALUES (?, ?, ?, ?, ?)",
{bid, fork_id, ref, hash, util::utc_now()}
);
}
std::cout << "[registry] Done indexing " << fork.at("name") << "\n";
}
std::vector<Database::Row> list_forks(const std::string& sort = "usage") {
if (sort == "usage") {
return db_.query(R"SQL(
SELECT f.*,
COALESCE(SUM(cm.total_usage_hours), 0) as total_usage
FROM forks f
LEFT JOIN commits c ON c.fork_id = f.id
LEFT JOIN commit_metrics cm ON cm.commit_hash = c.hash
GROUP BY f.id
ORDER BY total_usage DESC
)SQL");
}
return db_.query(
"SELECT *, '0' as total_usage FROM forks ORDER BY last_seen DESC");
}
std::vector<Database::Row> list_branches(const std::string& fork_id) {
return db_.query(R"SQL(
SELECT b.*,
COALESCE(cm.total_usage_hours, 0) as usage_hours,
COALESCE(cm.unique_users, 0) as unique_users
FROM branches b
LEFT JOIN commit_metrics cm ON cm.commit_hash = b.head_commit
WHERE b.fork_id = ?
ORDER BY usage_hours DESC
)SQL", {fork_id});
}
std::vector<Database::Row> search(const std::string& q) {
std::string like = "%" + q + "%";
return db_.query(
"SELECT * FROM forks WHERE name LIKE ? OR description LIKE ?",
{like, like});
}
std::vector<Database::Row> get_tree() {
return db_.query("SELECT * FROM forks ORDER BY parent_id");
}
};
// ============================================================================
// DELTA ENGINE
// ============================================================================
class DeltaEngine {
Database& db_;
static constexpr uint8_t OP_COPY = 0;
static constexpr uint8_t OP_INSERT = 1;
public:
explicit DeltaEngine(Database& db) : db_(db) {}
std::vector<uint8_t> compute_delta(const std::vector<uint8_t>& base,
const std::vector<uint8_t>& target) {
std::unordered_map<std::string, uint32_t> base_blocks;
for (size_t i = 0; i < base.size(); i += config::BLOCK_SIZE) {
size_t len = std::min(config::BLOCK_SIZE, base.size() - i);
base_blocks[util::block_hash(base.data() + i, len)] =
static_cast<uint32_t>(i);
}
std::vector<uint8_t> raw;
auto emit_u8 = [&](uint8_t v) { raw.push_back(v); };
auto emit_u32 = [&](uint32_t v) {
raw.push_back(v & 0xFF);
raw.push_back((v >> 8) & 0xFF);
raw.push_back((v >> 16) & 0xFF);
raw.push_back((v >> 24) & 0xFF);
};
size_t i = 0;
while (i < target.size()) {
size_t len = std::min(config::BLOCK_SIZE, target.size() - i);
auto h = util::block_hash(target.data() + i, len);
auto it = base_blocks.find(h);
if (it != base_blocks.end()) {
emit_u8(OP_COPY);
emit_u32(it->second);
emit_u32(static_cast<uint32_t>(len));
} else {
emit_u8(OP_INSERT);
emit_u32(static_cast<uint32_t>(len));
raw.insert(raw.end(), target.begin() + i, target.begin() + i + len);
}
i += config::BLOCK_SIZE;
}
return util::zlib_compress(raw);
}
std::vector<uint8_t> apply_delta(const std::vector<uint8_t>& base,
const std::vector<uint8_t>& delta) {
auto raw = util::zlib_decompress(delta);
if (raw.empty()) return {};
std::vector<uint8_t> result;
auto read_u8 = [&](size_t& p) -> uint8_t { return raw[p++]; };
auto read_u32 = [&](size_t& p) -> uint32_t {
uint32_t v = raw[p] | (raw[p+1]<<8) | (raw[p+2]<<16) | (raw[p+3]<<24);
p += 4; return v;
};
size_t p = 0;
while (p < raw.size()) {
uint8_t op = read_u8(p);
if (op == OP_COPY) {
uint32_t off = read_u32(p), len = read_u32(p);
if (off + len <= base.size())
result.insert(result.end(), base.begin()+off, base.begin()+off+len);
} else if (op == OP_INSERT) {
uint32_t len = read_u32(p);
if (p + len <= raw.size()) {
result.insert(result.end(), raw.begin()+p, raw.begin()+p+len);
p += len;
}
}
}
return result;
}
void store_build(const std::string& commit,
const std::vector<uint8_t>& binary,
const std::string& parent = "") {
auto hash = util::sha256_bytes(binary);
auto path = config::binary_cache() / (commit + ".bin");
std::string delta_from, delta_size_str;
if (!parent.empty()) {
auto ppath = config::binary_cache() / (parent + ".bin");
if (fs::exists(ppath)) {
auto pdata = util::read_file_bytes(ppath);
auto delta = compute_delta(pdata, binary);
auto dpath = config::delta_store() / (parent + "_" + commit + ".delta");
util::write_file_bytes(dpath, delta);
delta_from = parent;
delta_size_str = std::to_string(delta.size());
double ratio = 100.0 * delta.size() / binary.size();
std::cout << "[delta] " << commit.substr(0,8)
<< ": " << std::fixed << std::setprecision(1)
<< ratio << "% of full (" << delta.size()
<< " vs " << binary.size() << " bytes)\n";
}
}
util::write_file_bytes(path, binary);
db_.execute(
"INSERT OR REPLACE INTO builds "
"(commit_hash, binary_hash, binary_size, delta_from, "
"delta_size, platform) VALUES (?, ?, ?, ?, ?, ?)",
{commit, hash, std::to_string(binary.size()),
delta_from, delta_size_str, "native"});
}
std::vector<uint8_t> get_build(const std::string& commit) {
auto path = config::binary_cache() / (commit + ".bin");
if (fs::exists(path)) return util::read_file_bytes(path);
// Walk delta chain
struct Link { std::string target; fs::path delta_path; };
std::vector<Link> chain;
std::string cur = commit;
while (!cur.empty()) {
auto rows = db_.query("SELECT * FROM builds WHERE commit_hash = ?", {cur});
if (rows.empty()) break;
std::string df = rows[0].at("delta_from");
if (!df.empty()) {
auto dp = config::delta_store() / (df + "_" + cur + ".delta");
if (fs::exists(dp)) { chain.push_back({cur, dp}); cur = df; }
else break;
} else break;
}
auto base_path = config::binary_cache() / (cur + ".bin");
if (!fs::exists(base_path)) {
std::cerr << "[delta] Missing base: " << cur << "\n";
return {};
}
auto data = util::read_file_bytes(base_path);
for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
auto d = util::read_file_bytes(it->delta_path);
data = apply_delta(data, d);
util::write_file_bytes(config::binary_cache() / (it->target + ".bin"), data);
}
return data;
}
struct Plan {
std::string strategy;
std::string reason;
std::vector<std::string> chain;
int64_t download_bytes = 0;
int64_t full_bytes = 0;
double savings = 0;
};
Plan get_plan(const std::string& commit) {
auto rows = db_.query("SELECT * FROM builds WHERE commit_hash = ?", {commit});
if (rows.empty()) return {"compile", "no cached build"};
if (fs::exists(config::binary_cache() / (commit + ".bin")))
return {"local", ""};
int64_t full = std::stoll(rows[0].at("binary_size"));
int64_t cost = 0;
std::vector<std::string> chain;
std::string cur = commit;
while (!cur.empty()) {
auto b = db_.query("SELECT * FROM builds WHERE commit_hash = ?", {cur});
if (b.empty()) break;
std::string df = b[0].at("delta_from");
if (df.empty()) break;
std::string ds = b[0].at("delta_size");
cost += ds.empty() ? 0 : std::stoll(ds);
chain.push_back(cur);
if (fs::exists(config::binary_cache() / (df + ".bin"))) {
double sav = full > 0 ? (1.0 - (double)cost/full) * 100 : 0;
return {"delta_chain", "", chain, cost, full, sav};
}
cur = df;
}
return {"full_download", "", {}, full, full, 0};
}
};
// ============================================================================
// USAGE TELEMETRY
// ============================================================================
class UsageTracker {
Database& db_;
Database& reg_;
json::Object cfg_;
struct Session {
std::string user_hash, fork_id, branch_id, commit_hash, start_time;
};
std::optional<Session> active_;
void update_metrics(const std::string& commit) {
auto rows = db_.query("SELECT * FROM sessions WHERE commit_hash = ?", {commit});
if (rows.empty()) return;
std::vector<int64_t> durs;
std::set<std::string> users;
std::string first, last;
for (auto& s : rows) {
durs.push_back(std::stoll(s.at("duration_seconds")));
users.insert(s.at("user_hash"));
auto& t = s.at("start_time");
if (first.empty() || t < first) first = t;
if (last.empty() || t > last) last = t;
}
double hours = std::accumulate(durs.begin(), durs.end(), 0LL) / 3600.0;
double avg = (std::accumulate(durs.begin(), durs.end(), 0LL)
/ (double)durs.size()) / 60.0;
std::sort(durs.begin(), durs.end());
size_t m = durs.size() / 2;
double median = (durs.size() % 2 == 0)
? (durs[m-1] + durs[m]) / 2.0 / 60.0
: durs[m] / 60.0;
db_.execute(
"INSERT OR REPLACE INTO commit_metrics "
"(commit_hash, total_usage_hours, unique_users, "
"avg_session_minutes, median_session_minutes, "
"first_used, last_used) VALUES (?, ?, ?, ?, ?, ?, ?)",
{commit, std::to_string(hours),
std::to_string(static_cast<int>(users.size())),
std::to_string(avg), std::to_string(median), first, last});
}
public:
UsageTracker(Database& db, Database& reg, const json::Object& cfg)
: db_(db), reg_(reg), cfg_(cfg) {}
void start_session(const std::string& fork_id,
const std::string& branch_id,
const std::string& commit) {
auto it = cfg_.find("telemetry_opt_in");
if (it != cfg_.end() && !it->second.boolean()) return;
auto pid = cfg_.find("user_id");
std::string uid = pid != cfg_.end() ? pid->second.str() : "";
active_ = Session{
util::sha256_hex(uid).substr(0, 16),
fork_id, branch_id, commit, util::utc_now()
};
std::cout << "[telemetry] Session started: " << commit.substr(0,8) << "\n";
}
void end_session() {
if (!active_) return;
int dur = static_cast<int>(
std::time(nullptr) - util::parse_iso(active_->start_time));
db_.execute(
"INSERT INTO sessions "
"(user_hash, fork_id, branch_id, commit_hash, "
"start_time, duration_seconds) VALUES (?, ?, ?, ?, ?, ?)",
{active_->user_hash, active_->fork_id, active_->branch_id,
active_->commit_hash, active_->start_time, std::to_string(dur)});
update_metrics(active_->commit_hash);
std::cout << "[telemetry] Session ended: " << dur << "s\n";
active_.reset();
}
std::vector<Database::Row> get_trending(int days = 7) {
auto cutoff_t = std::time(nullptr) - (days * 86400);
std::tm tm{}; gmtime_r(&cutoff_t, &tm);
char buf[32]; std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &tm);
return db_.query(R"SQL(
SELECT branch_id, fork_id, commit_hash,
SUM(duration_seconds) / 3600.0 as hours_used,
COUNT(DISTINCT user_hash) as unique_users,
AVG(duration_seconds) / 60.0 as avg_session_min
FROM sessions WHERE start_time > ?
GROUP BY branch_id ORDER BY hours_used DESC
)SQL", {std::string(buf)});
}
std::optional<Database::Row> get_metrics(const std::string& commit) {
auto rows = db_.query(
"SELECT * FROM commit_metrics WHERE commit_hash = ?", {commit});
return rows.empty() ? std::nullopt
: std::optional<Database::Row>(rows[0]);
}
std::optional<Database::Row> compute_ai_signal(const std::string& hash) {
auto commits = reg_.query("SELECT * FROM commits WHERE hash = ?", {hash});
if (commits.empty()) return std::nullopt;
double ai_ratio = std::stod(commits[0].at("ai_ratio"));
if (ai_ratio == 0) return std::nullopt;
auto parent_m = get_metrics(commits[0].at("parent_hash"));
auto current_m = get_metrics(hash);
if (!parent_m || !current_m) return std::nullopt;
double ph = std::stod(parent_m->at("total_usage_hours"));
double ch = std::stod(current_m->at("total_usage_hours"));
double pa = std::stod(parent_m->at("avg_session_minutes"));
double ca = std::stod(current_m->at("avg_session_minutes"));
double usage_d = ph > 0 ? (ch - ph) / ph * 100 : 0;
double session_d = pa > 0 ? (ca - pa) / pa * 100 : 0;
int sample = std::stoi(current_m->at("unique_users"));
double conf = std::min(1.0, sample / 100.0);
db_.execute(
"INSERT OR REPLACE INTO ai_signal "
"(commit_hash, ai_ratio, usage_delta_percent, "
"session_length_delta_percent, signal_confidence, sample_size) "
"VALUES (?, ?, ?, ?, ?, ?)",
{hash, std::to_string(ai_ratio), std::to_string(usage_d),
std::to_string(session_d), std::to_string(conf),
std::to_string(sample)});
Database::Row sig;
sig["commit_hash"] = hash;
sig["ai_ratio"] = std::to_string(ai_ratio);
sig["usage_delta_percent"] = std::to_string(usage_d);
sig["session_length_delta_percent"]= std::to_string(session_d);
sig["signal_confidence"] = std::to_string(conf);
sig["sample_size"] = std::to_string(sample);
return sig;
}
};
// ============================================================================
// BRANCH MANAGER
// ============================================================================
class BranchManager {
Database& reg_;
DeltaEngine delta_;
UsageTracker& tracker_;
public:
BranchManager(Database& reg, UsageTracker& tracker)
: reg_(reg), delta_(reg), tracker_(tracker) {}
fs::path checkout(const std::string& fork_id, const std::string& branch) {
std::string bid = fork_id + ":" + branch;
std::string dname = fork_id + "_" + branch;
fs::path dir = config::branches_dir() / dname;
auto forks = reg_.query("SELECT * FROM forks WHERE id = ?", {fork_id});
if (forks.empty()) {
std::cerr << "[branch] Unknown fork: " << fork_id << "\n";
return {};
}
auto branches = reg_.query("SELECT * FROM branches WHERE id = ?", {bid});
std::string commit;
if (!branches.empty()) commit = branches[0].at("head_commit");
if (!commit.empty()) {
auto plan = delta_.get_plan(commit);
std::cout << "[branch] Strategy: " << plan.strategy << "\n";
if (plan.strategy == "local") {
std::cout << "[branch] Ready: " << commit.substr(0,8) << "\n";
return dir;
}
if (plan.strategy == "delta_chain") {
std::cout << "[branch] Delta: " << plan.download_bytes
<< " bytes (saving " << std::fixed
<< std::setprecision(1) << plan.savings << "%)\n";
}
}
std::string url = forks[0].at("url");
if (fs::exists(dir)) {
std::cout << "[branch] Pulling " << branch << "...\n";
util::run_cmd({"git", "-C", dir.string(), "pull", "--ff-only"});
} else {
std::cout << "[branch] Cloning " << forks[0].at("name")
<< ":" << branch << "...\n";
fs::create_directories(dir);
util::run_cmd({"git", "clone", "--branch", branch,
"--single-branch", "--depth", "1",
url, dir.string()});
}
return dir;
}
void launch(const std::string& fork_id, const std::string& branch,
const std::string& executable) {
std::string bid = fork_id + ":" + branch;
std::string dname = fork_id + "_" + branch;
fs::path dir = config::branches_dir() / dname;
auto result = util::run_cmd(
{"git", "-C", dir.string(), "rev-parse", "HEAD"});
std::string commit = result.exit_code == 0
? util::trim(result.out) : "unknown";
tracker_.start_session(fork_id, bid, commit);
fs::path exe = dir / executable;
if (!fs::exists(exe)) {
// Search common build output paths
std::vector<fs::path> search = {
dir / "build" / "Debug" / executable,
dir / "build" / "Release" / executable,
dir / "target" / "release" / executable,
dir / "target" / "debug" / executable,
dir / "bin" / executable,
};
for (auto& p : search) {
if (fs::exists(p)) { exe = p; break; }
}
}
if (fs::exists(exe)) {
std::cout << "[launch] Running: " << exe << "\n"
<< "[launch] Commit: " << commit.substr(0,8) << "\n"
<< "[launch] Ctrl+C to stop and record session\n";
std::string cmd = "cd '" + exe.parent_path().string() +
"' && '" + exe.string() + "'";
(void)std::system(cmd.c_str());
} else {
std::cerr << "[launch] Executable not found: " << executable << "\n"
<< "[launch] Build the project first, then:\n"
<< " lge launch " << fork_id << " " << branch
<< " <executable>\n";
}
tracker_.end_session();
}
std::vector<Database::Row> list_local() {
std::vector<Database::Row> out;
if (!fs::exists(config::branches_dir())) return out;
for (auto& e : fs::directory_iterator(config::branches_dir())) {
if (!e.is_directory()) continue;
std::string name = e.path().filename().string();
auto sep = name.find('_');
std::string bid = sep != std::string::npos
? name.substr(0,sep) + ":" + name.substr(sep+1) : name;
auto r = util::run_cmd(
{"git", "-C", e.path().string(), "rev-parse", "HEAD"});
std::string commit = r.exit_code == 0
? util::trim(r.out).substr(0,8) : "?";
Database::Row row;
row["branch_id"] = bid;
row["path"] = e.path().string();
row["commit"] = commit;
out.push_back(std::move(row));
}
return out;
}
};
// ============================================================================
// AI ATTRIBUTION
// ============================================================================
class AIAttribution {
Database& reg_;
Database& tel_;
public:
AIAttribution(Database& reg, Database& tel) : reg_(reg), tel_(tel) {}
void tag_commit(const std::string& hash, int ai, int human) {
int total = ai + human;
double ratio = total > 0 ? (double)ai / total : 0;
reg_.execute(
"UPDATE commits SET ai_authored_lines = ?, "
"human_authored_lines = ?, ai_ratio = ? WHERE hash = ?",
{std::to_string(ai), std::to_string(human),
std::to_string(ratio), hash});
}
std::vector<Database::Row> leaderboard() {
return tel_.query(R"SQL(
SELECT commit_hash, ai_ratio, usage_delta_percent,
session_length_delta_percent, signal_confidence, sample_size
FROM ai_signal WHERE signal_confidence > 0.3
ORDER BY usage_delta_percent DESC
)SQL");
}
Database::Row ratio_report(const std::string& fork_id) {
auto rows = reg_.query(R"SQL(
SELECT
COALESCE(SUM(ai_authored_lines), 0) as total_ai,
COALESCE(SUM(human_authored_lines), 0) as total_human,
COALESCE(AVG(ai_ratio), 0) as avg_ratio,
COUNT(*) as total_commits,
SUM(CASE WHEN ai_ratio > 0 THEN 1 ELSE 0 END) as ai_commits
FROM commits WHERE fork_id = ?
)SQL", {fork_id});
return rows.empty() ? Database::Row{} : rows[0];
}
};
// ============================================================================
// CLI
// ============================================================================
namespace cli {
struct Col { std::string key, name; int width; };
void table(const std::vector<Database::Row>& rows,
const std::vector<Col>& cols) {
if (rows.empty()) { std::cout << " (no data)\n"; return; }
auto sep = [&]() {
for (auto& c : cols) {
std::cout << " ";
for (int i = 0; i < c.width; ++i) std::cout << "\u2500";
}
std::cout << "\n";
};
sep();
for (auto& c : cols)
std::cout << " " << std::left << std::setw(c.width) << c.name;
std::cout << "\n"; sep();
for (auto& row : rows) {
for (auto& c : cols) {
auto it = row.find(c.key);
std::string v = it != row.end() ? it->second : "";
try {
if (v.find('.') != std::string::npos) {
std::ostringstream o;
o << std::fixed << std::setprecision(1) << std::stod(v);
v = o.str();
}
} catch (...) {}
if ((int)v.size() > c.width - 1)
v = v.substr(0, c.width - 2) + "~";
std::cout << " " << std::left << std::setw(c.width) << v;
}
std::cout << "\n";
}
sep();
}
} // namespace cli
// ============================================================================
// COMMANDS
// ============================================================================
namespace cmd {
void init(int, char**) {
for (auto& d : {config::home_dir(), config::binary_cache(),
config::delta_store(), config::branches_dir()})
fs::create_directories(d);
if (!fs::exists(config::config_file())) {
json::Object cfg;
cfg["user_id"] = json::Value(util::random_hex(16).substr(0,16));
cfg["telemetry_opt_in"] = json::Value(true);
cfg["compile_local"] = json::Value(false);
cfg["sandbox_enabled"] = json::Value(true);
cfg["ai_attribution"] = json::Value(true);
util::write_file_text(config::config_file(),
json::serialize(json::Value(cfg)));
}
Database reg(config::registry_db()); schema::init_registry(reg);
Database tel(config::telemetry_db()); schema::init_telemetry(tel);
std::cout << "[lge] Initialized at " << config::home_dir() << "\n";
}
void register_fork(int argc, char** argv) {
if (argc < 4) {
std::cerr << "Usage: lge register <url> <name> [--desc TEXT] [--index]\n";
return;
}
std::string url = argv[2], name = argv[3], desc;
bool idx = false;
for (int i = 4; i < argc; ++i) {
std::string a = argv[i];
if (a == "--desc" && i+1 < argc) desc = argv[++i];
if (a == "--index") idx = true;
}
Database reg(config::registry_db());
ForkRegistry r(reg);
auto id = r.register_fork(url, name, desc);
if (idx) r.index_fork(id);
}
void index_cmd(int argc, char** argv) {
Database reg(config::registry_db());
ForkRegistry r(reg);
bool all = false; std::string fid;
for (int i = 2; i < argc; ++i) {
std::string a = argv[i];
if (a == "--all") all = true; else fid = a;
}
if (all) { for (auto& f : r.list_forks("recent")) r.index_fork(f.at("id")); }
else if (!fid.empty()) r.index_fork(fid);
else std::cerr << "Usage: lge index <fork_id> | --all\n";
}
void forks_cmd(int argc, char** argv) {
std::string sort = "usage";
for (int i = 2; i < argc; ++i) {
if (std::string(argv[i]) == "--sort" && i+1 < argc) sort = argv[++i];
}
Database reg(config::registry_db());
ForkRegistry r(reg);
std::cout << "\n LeGitingEdition Fork Registry\n"
<< " Sorted by: " << sort << "\n\n";
cli::table(r.list_forks(sort), {
{"id", "ID", 14},
{"name", "NAME", 30},
{"total_usage", "USAGE (h)", 12},
{"fork_count", "FORKS", 8},
{"stars", "STARS", 8},
});
}
void branches_cmd(int argc, char** argv) {
if (argc < 3) { std::cerr << "Usage: lge branches <fork_id>\n"; return; }
Database reg(config::registry_db());
ForkRegistry r(reg);
std::cout << "\n Branches: " << argv[2] << "\n\n";
cli::table(r.list_branches(argv[2]), {
{"name", "BRANCH", 30},
{"head_commit", "HEAD", 12},
{"usage_hours", "USAGE (h)", 12},
{"unique_users", "USERS", 10},
{"build_status", "BUILD", 10},
});
}
void checkout_cmd(int argc, char** argv) {
if (argc < 4) { std::cerr << "Usage: lge checkout <fork_id> <branch>\n"; return; }
auto cfg = json::parse(util::read_file_text(config::config_file())).obj();
Database reg(config::registry_db()), tel(config::telemetry_db());
UsageTracker tracker(tel, reg, cfg);
BranchManager mgr(reg, tracker);
mgr.checkout(argv[2], argv[3]);
}
void launch_cmd(int argc, char** argv) {
if (argc < 5) {
std::cerr << "Usage: lge launch <fork_id> <branch> <executable>\n";
return;
}
auto cfg = json::parse(util::read_file_text(config::config_file())).obj();
Database reg(config::registry_db()), tel(config::telemetry_db());
UsageTracker tracker(tel, reg, cfg);
BranchManager mgr(reg, tracker);
mgr.launch(argv[2], argv[3], argv[4]);
}
void local_cmd(int, char**) {
auto cfg = json::parse(util::read_file_text(config::config_file())).obj();
Database reg(config::registry_db()), tel(config::telemetry_db());
UsageTracker tracker(tel, reg, cfg);
BranchManager mgr(reg, tracker);
std::cout << "\n Local Branches\n\n";
cli::table(mgr.list_local(), {
{"branch_id", "BRANCH", 40},
{"commit", "COMMIT", 12},
{"path", "PATH", 50},
});
}
void trending_cmd(int argc, char** argv) {
int days = 7;
for (int i = 2; i < argc; ++i)
if (std::string(argv[i]) == "--days" && i+1 < argc) days = std::atoi(argv[++i]);
auto cfg = json::parse(util::read_file_text(config::config_file())).obj();
Database reg(config::registry_db()), tel(config::telemetry_db());
UsageTracker tracker(tel, reg, cfg);
std::cout << "\n Trending (last " << days << " days)\n\n";
cli::table(tracker.get_trending(days), {
{"branch_id", "BRANCH", 40},
{"hours_used", "HOURS", 10},
{"unique_users", "USERS", 10},
{"avg_session_min","AVG SESSION", 12},
});
}
void ai_signal_cmd(int, char**) {
Database reg(config::registry_db()), tel(config::telemetry_db());
AIAttribution ai(reg, tel);
std::cout << "\n AI Contribution Signal (ranked by usage impact)\n\n";
cli::table(ai.leaderboard(), {
{"commit_hash", "COMMIT", 12},
{"ai_ratio", "AI %", 8},
{"usage_delta_percent", "USAGE D%", 12},
{"session_length_delta_percent","SESSION D%", 12},
{"signal_confidence", "CONFIDENCE", 12},
{"sample_size", "USERS", 10},
});
}
void plan_cmd(int argc, char** argv) {
if (argc < 3) { std::cerr << "Usage: lge plan <commit>\n"; return; }
Database reg(config::registry_db());
DeltaEngine d(reg);
auto plan = d.get_plan(argv[2]);
std::cout << "\n Download Plan: " << std::string(argv[2]).substr(0,8) << "\n\n"
<< " strategy: " << plan.strategy << "\n";
if (!plan.reason.empty()) std::cout << " reason: " << plan.reason << "\n";
if (plan.download_bytes > 0) std::cout << " download: " << plan.download_bytes << " bytes\n";
if (plan.full_bytes > 0) std::cout << " full: " << plan.full_bytes << " bytes\n";
if (plan.savings > 0) std::cout << " savings: " << std::fixed
<< std::setprecision(1) << plan.savings << "%\n";
std::cout << "\n";
}
void status_cmd(int, char**) {
std::cout << "\n"
" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u2557\n"
" \u2551 LeGitingEdition v"
<< config::VERSION <<
" \u2551\n"
" \u255a\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550"
"\u2550\u2550\u2550\u2550\u2550\u2550\u255d\n\n";
Database reg(config::registry_db());
int nf = std::stoi(reg.scalar("SELECT COUNT(*) FROM forks"));
int nb = std::stoi(reg.scalar("SELECT COUNT(*) FROM branches"));
int nc = std::stoi(reg.scalar("SELECT COUNT(*) FROM builds"));
Database tel(config::telemetry_db());
int ns = std::stoi(tel.scalar("SELECT COUNT(*) FROM sessions"));
double th = std::stod(tel.scalar(
"SELECT COALESCE(SUM(duration_seconds),0)/3600.0 FROM sessions"));
int na = std::stoi(tel.scalar("SELECT COUNT(*) FROM ai_signal"));
auto cfg = json::parse(util::read_file_text(config::config_file())).obj();
auto gs = [&](const std::string& k) -> std::string {
auto it = cfg.find(k);
return it != cfg.end() && it->second.is_string() ? it->second.str() : "";
};
auto gb = [&](const std::string& k) -> bool {
auto it = cfg.find(k);
return it != cfg.end() && it->second.is_bool() && it->second.boolean();
};
std::cout << " User ID: " << gs("user_id") << "\n"
<< " Telemetry: " << (gb("telemetry_opt_in") ? "ON" : "OFF") << "\n"
<< " Sandbox: " << (gb("sandbox_enabled") ? "ON" : "OFF") << "\n"
<< " AI Attribution: " << (gb("ai_attribution") ? "ON" : "OFF") << "\n\n"
<< " Registry: " << nf << " forks, " << nb << " branches\n"
<< " Cache: " << nc << " builds\n"
<< " Telemetry: " << ns << " sessions, "
<< std::fixed << std::setprecision(1) << th << " hours\n"
<< " AI Signals: " << na << " commits tracked\n\n";
}
void schema_cmd(int, char**) {
std::cout << R"(
LeGitingEdition Telemetry Schema (v1)
══════════════════════════════════════
sessions:
user_hash - SHA256 of local user ID (anonymous)
fork_id - which fork was used
branch_id - which branch was used
commit_hash - exact commit running
start_time - UTC session start
duration_seconds - session length
platform - OS / platform
commit_metrics (aggregated):
total_usage_hours - cumulative session time
unique_users - distinct user hashes
avg_session_minutes - mean session length
median_session_minutes - median session length
usage_trend - rate of change
ai_signal:
ai_ratio - fraction of AI-authored lines
usage_delta_percent - change vs parent commit
session_length_delta_percent - change in session length
signal_confidence - confidence from sample size
sample_size - unique users measured
NOT collected:
- Real names, emails, or IP addresses
- In-application behavior or actions
- Communications of any kind
- Hardware or system specifications
- Any personally identifiable information
)";
}
void search_cmd(int argc, char** argv) {
if (argc < 3) { std::cerr << "Usage: lge search <query>\n"; return; }
Database reg(config::registry_db());
ForkRegistry r(reg);
std::cout << "\n Search: " << argv[2] << "\n\n";
cli::table(r.search(argv[2]), {
{"id", "ID", 14},
{"name", "NAME", 30},
{"description", "DESCRIPTION", 40},
{"url", "URL", 40},
});
}
void tree_cmd(int, char**) {
Database reg(config::registry_db());
ForkRegistry r(reg);
auto forks = r.get_tree();
std::cout << "\n Fork Tree\n\n";
std::map<std::string, std::vector<Database::Row>> children;
std::vector<Database::Row> roots;
for (auto& f : forks) {
std::string pid = f.at("parent_id");
if (pid.empty()) roots.push_back(f);
else children[pid].push_back(f);
}
std::function<void(const Database::Row&, int)> print_node =
[&](const Database::Row& node, int depth) {
std::string prefix(depth * 2, ' ');
std::string id = node.at("id");
std::cout << " " << prefix
<< (depth > 0 ? "\u2514\u2500 " : "")
<< node.at("name") << " [" << id << "]\n";
if (children.count(id)) {
for (auto& child : children[id])
print_node(child, depth + 1);
}
};
for (auto& root : roots) print_node(root, 0);
std::cout << "\n";
}
void help_cmd(int, char**) {
std::cout << R"(
LeGitingEdition (lge) v)" << config::VERSION << R"(
A delta layer on top of Git for fork-driven software ecosystems.
Usage: lge <command> [options]
Registry:
init Initialize lge
register <url> <name> [opts] Register a fork
--desc TEXT Description
--index Index branches now
index <fork_id> | --all Index fork branches
forks [--sort usage|recent] List registered forks
branches <fork_id> List branches
search <query> Search forks
tree Show fork tree
Workspace:
checkout <fork_id> <branch> Check out a branch
launch <fork_id> <branch> <exe> Run a build with telemetry
local List local branches
Analytics:
trending [--days N] Branches ranked by usage
ai-signal AI contribution impact
plan <commit> Show download strategy
System:
status Overview
schema Audit telemetry schema
help This message
)";
}
} // namespace cmd
// ============================================================================
// MAIN
// ============================================================================
int main(int argc, char** argv) {
if (argc < 2) { cmd::help_cmd(argc, argv); return 0; }
std::string c = argv[1];
if (c != "init" && !fs::exists(config::home_dir()))
cmd::init(argc, argv);
std::map<std::string, std::function<void(int,char**)>> commands = {
{"init", cmd::init},
{"register", cmd::register_fork},
{"index", cmd::index_cmd},
{"forks", cmd::forks_cmd},
{"branches", cmd::branches_cmd},
{"checkout", cmd::checkout_cmd},
{"launch", cmd::launch_cmd},
{"local", cmd::local_cmd},
{"trending", cmd::trending_cmd},
{"ai-signal",cmd::ai_signal_cmd},
{"plan", cmd::plan_cmd},
{"status", cmd::status_cmd},
{"schema", cmd::schema_cmd},
{"search", cmd::search_cmd},
{"tree", cmd::tree_cmd},
{"help", cmd::help_cmd},
{"--help", cmd::help_cmd},
{"-h", cmd::help_cmd},
};
auto it = commands.find(c);
if (it != commands.end()) it->second(argc, argv);
else { std::cerr << "Unknown: " << c << "\n"; cmd::help_cmd(argc, argv); return 1; }
return 0;
} 메타데이터
- post_id
- 9ecb30fd4195
- slug
- legittingedition-9ecb30fd4195
- url
- https://medium.com/@appleby.ethan.ea/legittingedition-9ecb30fd4195
- canonical_url
- https://medium.com/@appleby.ethan.ea/legittingedition-9ecb30fd4195
- author_url
- https://medium.com/@appleby.ethan.ea
- status
- ok
- fetched_at
- 2026-07-12 03:01:25