0dba4f3663
- daemon.el: launchd plist generation, install/start/stop/status/wire - forge.el: dispatch daemon command, add to usage - install.el: auto-register soul as launchd agent after install - schema.el: add FORGE_DIR constant for absolute path references forge daemon install --all installs all 19 souls as resident launchd agents with KeepAlive. forge daemon wire registers each soul as an Engram peer to every other soul. forge daemon status health-checks all.
94 lines
4.4 KiB
EmacsLisp
94 lines
4.4 KiB
EmacsLisp
// schema.el — Forge shared constants and helper functions.
|
|
//
|
|
// Provides the engram URL resolver, API key accessors, and JSON template
|
|
// builders used by all pipeline stages (probe, compiler, install).
|
|
|
|
// ── Constants ─────────────────────────────────────────────────────────────────
|
|
|
|
let ENGRAM_DEFAULT_URL: String = "http://localhost:8742"
|
|
let FORGE_VERSION: String = "0.1.0"
|
|
|
|
// Absolute forge root — used by daemon.el and install.el for launchd plists
|
|
// and per-soul data paths that must be absolute even when invoked from a
|
|
// different working directory.
|
|
let FORGE_DIR: String = "/Users/will/Development/neuron-technologies/forge"
|
|
|
|
// Canonical directory layout — enforced by the tool, not by convention.
|
|
let FORGE_SEEDS_DIR: String = "seeds" // compiled seed JSON files
|
|
let FORGE_PROBES_DIR: String = "probes" // raw .forge interview responses
|
|
let FORGE_LOG_DIR: String = "log" // session and event logs
|
|
let FORGE_LOG_FILE: String = "log/sessions.jsonl" // append-only session log
|
|
|
|
// ── Environment accessors ──────────────────────────────────────────────────────
|
|
|
|
fn engram_url() -> String {
|
|
let u: String = env("ENGRAM_URL")
|
|
if str_eq(u, "") { return ENGRAM_DEFAULT_URL }
|
|
return u
|
|
}
|
|
|
|
fn engram_key() -> String {
|
|
let k: String = env("ENGRAM_API_KEY")
|
|
if str_eq(k, "") { return "" }
|
|
return k
|
|
}
|
|
|
|
fn anthropic_key() -> String {
|
|
let k: String = env("ANTHROPIC_API_KEY")
|
|
if str_eq(k, "") { return "" }
|
|
return k
|
|
}
|
|
|
|
// ── Directory helpers ─────────────────────────────────────────────────────────
|
|
|
|
// ensure_dirs — create canonical forge directories if they don't exist.
|
|
// Call once at startup from any command that writes files.
|
|
fn ensure_dirs() -> Void {
|
|
if !fs_exists(FORGE_SEEDS_DIR) { fs_mkdir(FORGE_SEEDS_DIR) }
|
|
if !fs_exists(FORGE_PROBES_DIR) { fs_mkdir(FORGE_PROBES_DIR) }
|
|
if !fs_exists(FORGE_LOG_DIR) { fs_mkdir(FORGE_LOG_DIR) }
|
|
}
|
|
|
|
// log_event — append a JSON-lines entry to log/sessions.jsonl.
|
|
// event: "research" | "install" | "summon" | "probe" | "compile"
|
|
// subject: display name or comma-joined list for multi-summon
|
|
// detail: arbitrary context string (root_id, conv_id, file path, etc.)
|
|
fn log_event(event: String, subject: String, detail: String) -> Void {
|
|
ensure_dirs()
|
|
let ts: Int = unix_timestamp()
|
|
let entry: String = "{\"ts\":" + int_to_str(ts) +
|
|
",\"event\":\"" + str_escape_json(event) +
|
|
"\",\"subject\":\"" + str_escape_json(subject) +
|
|
"\",\"detail\":\"" + str_escape_json(detail) + "\"}\n"
|
|
// Read existing log and append (EL has fs_write but not fs_append natively)
|
|
let existing: String = fs_read(FORGE_LOG_FILE)
|
|
fs_write(FORGE_LOG_FILE, existing + entry)
|
|
}
|
|
|
|
// ── String utilities ──────────────────────────────────────────────────────────
|
|
|
|
// str_escape_json — escape a string for safe embedding in a JSON value.
|
|
// Handles: backslash, double-quote, newline, tab, carriage return.
|
|
fn str_escape_json(s: String) -> String {
|
|
let r: String = str_replace(s, "\\", "\\\\")
|
|
let r = str_replace(r, "\"", "\\\"")
|
|
let r = str_replace(r, "\n", "\\n")
|
|
let r = str_replace(r, "\t", "\\t")
|
|
let r = str_replace(r, "\r", "\\r")
|
|
return r
|
|
}
|
|
|
|
// ── JSON template builders ────────────────────────────────────────────────────
|
|
|
|
// probe_response_template — builds the initial shell written to <name>.forge.
|
|
// The sections and responses fields are populated by probe_main() at runtime.
|
|
fn probe_response_template(subject: String) -> String {
|
|
"{\"subject\":\"" + subject + "\",\"version\":\"1.0\",\"sections\":{},\"responses\":[]}"
|
|
}
|
|
|
|
// seed_template — builds the shell written to seed.json after compilation.
|
|
// Patterns are merged into this structure by compile_main().
|
|
fn seed_template(subject: String) -> String {
|
|
"{\"subject\":\"" + subject + "\",\"version\":\"1.0\",\"values\":[],\"voice_profile\":{},\"biography\":[],\"reasoning_patterns\":[],\"relationships\":[]}"
|
|
}
|