#!/usr/bin/env node import { Command } from "commander"; import { MetaAgent } from "./tier3-compounding/meta-agent.js"; import { loadEnv } from "./upgrades/env-loader.js"; import type { SkillDefinition, LoopIteration } from "./core/types.js"; import * as fs from "node:fs"; import * as path from "node:path"; // Load .env before any command handlers run const envResult = loadEnv(); const packageJson = JSON.parse( fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8") ); const program = new Command(); program .name("fable-agent") .description("Harness-agnostic, model-agnostic self-improving agent system — loops, dynamic workflows, routines") .version(packageJson.version); // ── Run ───────────────────────────────────────────────────── program .command("run ") .description("Run a task through the self-improving agent system") .option("-l, --loop ", "Number of feedback loop iterations", parseInt) .option("-w, --workflow ", "Workflow definition ID to execute") .option("-s, --skill ", "Skill ID to execute") .option("-c, --compound ", "Number of compound runs", parseInt) .action(async (task: string, opts: Record) => { const agent = new MetaAgent(); console.log(`\n Fable Agent v${packageJson.version}`); console.log(` ─────────────────────────────`); console.log(` Task: ${task}`); console.log(` `); try { const compound = opts.compound ? Number(opts.compound) : 1; if (compound > 1) { const results = await agent.compound(task, compound); console.log(`\n ✓ Compound run complete (${compound} iterations)`); for (const r of results) { console.log(` Session ${r.sessionId.slice(0, 8)}… — ${r.loopIterations} loops, converged=${r.converged}`); } } else { const result = await agent.run(task, { skillId: opts.skill as string | undefined, workflowId: opts.workflow as string | undefined, loopIterations: opts.loop ? Number(opts.loop) : undefined, }); console.log(`\n ✓ Run complete`); console.log(` Session: ${result.sessionId}`); console.log(` Iterations: ${result.loopIterations}`); console.log(` Converged: ${result.converged} (${result.convergenceReason ?? "n/a"})`); console.log(` Context: ${result.contextUsage.pct}% of ${result.contextUsage.budget} budget`); console.log(` Knowledge: ${result.knowledgeEntryCount} entries`); } const status = agent.getStatus(); console.log(`\n System State:`); console.log(` Skills: ${status.skills.total} (${status.skills.withHistory} with history)`); console.log(` Knowledge: ${status.knowledge.entries} entries, ${status.knowledge.tags.length} tags`); console.log(` `); } catch (err) { console.error(`\n ✗ Error: ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } }); // ── Session ───────────────────────────────────────────────── const session = program .command("session") .description("Manage autonomous agent sessions"); session .command("start") .description("Start a new autonomous session") .argument("", "Task description") .action(async (task: string) => { const agent = new MetaAgent(); const sess = agent.session.start(task); console.log(`\n Session started:`); console.log(` ID: ${sess.id}`); console.log(` Task: ${sess.task}`); console.log(` Run \`fable-agent session resume ${sess.id}\` to resume if interrupted`); console.log(` `); }); session .command("resume ") .description("Resume a checkpointed session") .action(async (id: string) => { const agent = new MetaAgent(); const sess = agent.session.resume(id); if (!sess) { console.error(` ✗ Session not found: ${id}`); process.exit(1); } console.log(` ✓ Session resumed: ${id}`); console.log(` Task: ${sess.task}`); console.log(` `); }); session .command("list") .description("List all sessions") .action(() => { const agent = new MetaAgent(); const sessions = agent.session.list(); if (sessions.length === 0) { console.log(" No sessions found."); return; } console.log(` Sessions (${sessions.length}):`); for (const s of sessions) { const age = Math.round( (Date.now() - new Date(s.createdAt).getTime()) / 1000 / 60 ); console.log(` ${s.id.slice(0, 8)}… ${s.status.padEnd(14)} ${age}m ago "${s.task.slice(0, 50)}"`); } console.log(` `); }); session .command("inspect ") .description("View session details") .action(async (id: string) => { const agent = new MetaAgent(); const s = agent.session.get(id); if (!s) { console.error(` ✗ Session not found: ${id}`); process.exit(1); } console.log(`\n Session: ${s.id}`); console.log(` ─────────────────────────────`); console.log(` Status: ${s.status}`); console.log(` Task: ${s.task}`); console.log(` Created: ${s.createdAt}`); console.log(` Updated: ${s.updatedAt}`); console.log(` Iterations: ${s.metadata.totalIterations ?? "?"}`); console.log(` Config:`); console.log(` Max iterations: ${s.config.maxIterations}`); console.log(` Convergence thresh: ${s.config.convergenceThreshold}`); console.log(` Context budget: ${s.config.contextTokenBudget}`); console.log(` Heartbeat interval: ${s.config.heartbeatIntervalMs}ms`); if (agent.session.isStalled(id)) { console.log(` ⚠ Session may be stalled (no recent heartbeat)`); } console.log(` `); }); // ── Skills ────────────────────────────────────────────────── const skills = program .command("skills") .description("Manage skills (routines)"); skills .command("list") .description("List all registered skills") .option("-t, --tag ", "Filter by tag") .action((opts: { tag?: string }) => { const agent = new MetaAgent(); let skillsList: SkillDefinition[]; if (opts.tag) { skillsList = agent.skillRegistry.findByTag(opts.tag); } else { skillsList = agent.skillRegistry.list(); } if (skillsList.length === 0) { console.log(" No skills registered."); return; } console.log(`\n Skills (${skillsList.length}):`); for (const sk of skillsList) { console.log( ` ${sk.id.padEnd(24)} v${sk.version.padEnd(6)} ${String(sk.metrics.totalExecutions).padStart(3)} runs ${sk.name}` ); } console.log(` `); }); skills .command("create ") .description("Create a new skill from a template") .requiredOption("-d, --description ", "Skill description") .option("-s, --steps ", "Comma-separated step labels") .option("-t, --tags ", "Comma-separated tags") .action((name: string, opts: { description: string; steps?: string; tags?: string }) => { const agent = new MetaAgent(); const stepLabels = opts.steps?.split(",").map((s) => s.trim()) ?? [ "Analyze requirements", "Plan approach", "Execute", "Verify results", "Reflect", ]; const skill = agent.skillRegistry.createFromTemplate({ name, description: opts.description, steps: stepLabels.map((label) => ({ label, instruction: `Execute step: ${label}`, expectedOutcome: `Completed: ${label}`, })), tags: opts.tags?.split(",").map((t) => t.trim()) ?? ["general"], }); console.log(`\n ✓ Skill created: ${skill.id} v${skill.version}`); console.log(` Steps: ${skill.steps.length}`); console.log(` Tags: ${skill.tags.join(", ")}`); console.log(` `); }); skills .command("inspect ") .description("View skill details and execution history") .action((id: string) => { const agent = new MetaAgent(); const skill = agent.skillRegistry.get(id); if (!skill) { console.error(` ✗ Skill not found: ${id}`); process.exit(1); } console.log(`\n Skill: ${skill.name} (${skill.id})`); console.log(` ─────────────────────────────`); console.log(` Version: ${skill.version}`); console.log(` Description: ${skill.description}`); console.log(` Tags: ${skill.tags.join(", ")}`); console.log(` `); console.log(` Steps:`); for (const step of skill.steps) { console.log(` ${step.id}: ${step.label}`); if (step.validationCriteria.length > 0) { console.log(` Validates: ${step.validationCriteria.join(", ")}`); } } console.log(` `); console.log(` Metrics:`); console.log(` Executions: ${skill.metrics.totalExecutions}`); console.log(` Avg duration: ${Math.round(skill.metrics.avgDurationMs / 1000)}s`); console.log(` Avg quality: ${skill.metrics.avgQualityScore.toFixed(2)}`); console.log(` Success rate: ${(skill.metrics.successRate * 100).toFixed(0)}%`); console.log(` Evolutions: ${skill.metrics.evolutionCount}`); if (skill.history.length > 0) { console.log(` `); console.log(` Recent executions:`); for (const h of skill.history.slice(-5).reverse()) { const date = new Date(h.completedAt).toISOString().slice(0, 16); console.log( ` ${date} ${h.success ? "✓" : "✗"} q=${h.qualityScore.toFixed(2)} ${h.issues.length} issues` ); } } console.log(` `); }); skills .command("evolve ") .description("Analyze and auto-improve a skill") .action((id: string) => { const agent = new MetaAgent(); const { evolved, changes, report } = agent.routineEvolution.autoEvolve(id); console.log(`\n Evolution Report for "${id}":`); console.log(` ─────────────────────────────`); console.log(` Analyzable: ${report.analyzable}`); console.log(` Score: ${report.score}/100`); if (report.trend) console.log(` Trend: ${report.trend}`); if (report.findings.length > 0) { console.log(` `); console.log(` Findings:`); for (const f of report.findings) console.log(` • ${f}`); } if (evolved) { console.log(` `); console.log(` ✓ Applied ${changes.length} change(s):`); for (const c of changes) { console.log(` • ${c.type}: ${c.description}`); } } else { console.log(` No changes applied: ${report.reason ?? "skill is healthy"}`); } console.log(` `); }); skills .command("sharpen") .description("Run meta-review on all skills with execution history") .action(() => { const agent = new MetaAgent(); const reviews = agent.skillSharpener.reviewAll(); if (reviews.length === 0) { console.log(" No skills with execution history to review."); return; } console.log(`\n Skill Sharpener Review (${reviews.length} skills):`); console.log(` ─────────────────────────────`); for (const review of reviews) { const skill = agent.skillRegistry.get(review.skillId); console.log(` ${skill?.name ?? review.skillId}`); console.log(` Score: ${review.score}/100`); console.log(` Findings: ${review.findings.length}`); for (const f of review.findings) console.log(` • ${f}`); if (review.suggestedChanges.length > 0) { console.log(` Suggestions: ${review.suggestedChanges.length}`); for (const c of review.suggestedChanges.slice(0, 2)) { console.log(` → ${c.type}: ${c.description.slice(0, 80)}`); } } console.log(` `); } }); // ── State / Knowledge Base ────────────────────────────────── program .command("state") .description("View accumulated state knowledge base") .option("-t, --tag ", "Filter by tag") .option("--stats", "Show statistics only") .action((opts: { tag?: string; stats?: boolean }) => { const agent = new MetaAgent(); if (opts.stats) { const stats = agent.stateRepository.getStats(); console.log(`\n Knowledge Base Stats:`); console.log(` ─────────────────────────────`); console.log(` Total entries: ${stats.totalEntries}`); console.log(` By type:`); for (const [type, count] of Object.entries(stats.byType)) { console.log(` ${type}: ${count}`); } console.log(` Top tags: ${stats.topTags.join(", ")}`); console.log(` Avg score: ${stats.avgScore.toFixed(2)}`); } else if (opts.tag) { const entries = agent.stateRepository.findByTag(opts.tag, 10); if (entries.length === 0) { console.log(` No entries with tag "${opts.tag}".`); return; } console.log(`\n Entries tagged "${opts.tag}" (${entries.length}):`); for (const e of entries) { console.log(` [${e.type}] ${e.content.slice(0, 100)}`); } } else { const stats = agent.stateRepository.getStats(); console.log(`\n Knowledge Base: ${stats.totalEntries} entries`); console.log(` Tags: ${stats.topTags.join(", ")}`); console.log(` Run with --tag to view entries, --stats for details`); } console.log(` `); }); // ── PAI Integration ───────────────────────────────────────── const pai = program .command("pai") .description("PAI integration commands"); pai .command("status") .description("Check PAI integration health") .action(async () => { const { PaiConnector } = await import("./pai/pai-connector.js"); const { ProxyClient } = await import("./pai/proxy-client.js"); const { TelosBridge } = await import("./pai/telos-bridge.js"); const connector = new PaiConnector(); const proxy = new ProxyClient(); const telos = new TelosBridge(); console.log(`\n PAI Integration Status`); console.log(` ─────────────────────────────`); const ctx = connector.loadAll(); console.log(` TELOS files: ${ctx.telos.length}`); console.log(` PAI skills: ${ctx.skills.length}`); console.log(` ISA sessions: ${ctx.isa ? 1 : 0}`); const proxyOk = await proxy.health(); console.log(` Proxy (:18901): ${proxyOk ? "✓ online" : "✗ offline"}`); if (proxyOk) { try { const models = await proxy.listModels(); console.log(` Available models: ${models.length}`); for (const m of models.slice(0, 5)) { console.log(` ${m}`); } if (models.length > 5) console.log(` ... and ${models.length - 5} more`); } catch { console.log(` Models: unable to list`); } } const telosSections = telos.getAllSectionNames(); console.log(` TELOS sections: ${telosSections.length > 0 ? telosSections.join(", ") : "none"}`); console.log(` `); }); pai .command("telos") .description("Load PAI TELOS context") .option("-s, --section ", "Specific section to load") .action(async (opts: { section?: string }) => { const { PaiConnector } = await import("./pai/pai-connector.js"); const connector = new PaiConnector(); if (opts.section) { const content = connector.readFile(`USER/TELOS/${opts.section}.md`); if (!content) { console.error(` ✗ TELOS section not found: ${opts.section}`); process.exit(1); } console.log(`\n TELOS: ${opts.section}`); console.log(` ─────────────────────────────`); console.log(content.slice(0, 2000)); console.log(` `); return; } const ctx = connector.loadAll(); console.log(`\n PAI Context loaded:`); console.log(` ─────────────────────────────`); console.log(` TELOS documents (${ctx.telos.length}):`); for (const t of ctx.telos) { const preview = t.content.replace(/\n/g, " ").slice(0, 80); console.log(` ${t.name}: ${preview}...`); } console.log(` PAI skills (${ctx.skills.length}):`); for (const s of ctx.skills) { console.log(` ${s.name}: ${s.description.slice(0, 60)}`); } console.log(` `); }); pai .command("proxy") .description("Test proxy model completion") .argument("", "Prompt to send") .option("-m, --model ", "Model ID (default: fi-groq)") .option("-t, --temperature ", "Temperature", parseFloat) .option("-s, --system ", "System prompt") .action(async (prompt: string, opts: { model?: string; temperature?: number; system?: string }) => { const { ProxyClient } = await import("./pai/proxy-client.js"); const proxy = new ProxyClient(); const ok = await proxy.health(); if (!ok) { console.error(" ✗ Proxy is not running on :18901. Start it first."); process.exit(1); } console.log(`\n Proxy completion:`); console.log(` Model: ${opts.model ?? "fi-groq"}`); console.log(` Prompt: ${prompt.slice(0, 100)}${prompt.length > 100 ? "…" : ""}`); console.log(` ─────────────────────────────`); try { const result = await proxy.complete(prompt, opts.model, { temperature: opts.temperature, systemPrompt: opts.system, }); console.log(` Response:`); console.log(` ${result.content}`); console.log(` `); console.log(` Tokens: ${result.usage.totalTokens} (${result.usage.promptTokens} prompt + ${result.usage.completionTokens} completion)`); console.log(` Model: ${result.model}`); console.log(` `); } catch (err) { console.error(` ✗ ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } }); pai .command("sync") .description("Sync PAI skills into skill registry") .action(async () => { const { SkillSync } = await import("./pai/skill-sync.js"); const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const syncer = new SkillSync(); const agent = new MetaAgent(); const paiSkills = syncer.findAllPaiSkills(); if (paiSkills.length === 0) { console.log(" No PAI skills found to sync."); return; } const definitions = syncer.toSkillDefinitions(paiSkills); let imported = 0; for (const def of definitions) { const existing = agent.skillRegistry.get(def.id); if (existing) { console.log(` ↻ Already synced: ${def.name} (${def.id})`); continue; } agent.skillRegistry.register(def); imported++; } console.log(`\n ✓ Synced ${imported}/${definitions.length} PAI skills into skill registry`); console.log(` `); }); pai .command("dream") .description("Run dream cycle and write insights to TELOS") .option("-c, --cycle ", "Cycle number", parseInt) .option("--dry-run", "Show what would be written without writing") .action(async (opts: { cycle?: number; dryRun?: boolean }) => { const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const { DreamingSystem } = await import("./upgrades/dreaming-system.js"); const { TelosBridge } = await import("./pai/telos-bridge.js"); const agent = new MetaAgent(); const state = agent.stateRepository; const allKnowledge = state.query({ limit: 100 }); if (allKnowledge.length < 3) { console.error(` ✗ Need at least 3 knowledge entries to dream (have ${allKnowledge.length})`); process.exit(1); } const dreaming = new DreamingSystem(agent.skillRegistry, agent.store); const telos = new TelosBridge(); const dummyIterations: import("./core/types.js").LoopIteration[] = allKnowledge.slice(-5).map((k, i) => ({ number: i + 1, phase: "reflect" as const, reflection: k.content, metrics: { qualityScore: k.score, successRate: k.score > 0.5 ? 0.8 : 0.3, improvementDelta: k.score - 0.5, durationMs: 1000, }, timestamp: new Date().toISOString(), })); const cycleNumber = opts.cycle ?? 1; if (opts.dryRun) { console.log(`\n Dry run — dream cycle #${cycleNumber}`); console.log(` Would create dream from ${dummyIterations.length} iterations`); console.log(` Would write to TELOS/_dreams/`); console.log(` `); return; } try { const dream = dreaming.dream("pai-session", dummyIterations, cycleNumber); const path = telos.writeDreamInsights(dream); console.log(`\n ✓ Dream cycle #${cycleNumber} complete`); console.log(` Patterns: ${dream.patterns.length}`); console.log(` Insights: ${dream.distillations.length}`); console.log(` Dreams: ${dream.dreams.length}`); console.log(` Written to: ${path}`); console.log(` `); } catch (err) { console.error(` ✗ ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } }); pai .command("cert") .description("Run certification: ISA → run → ISA → verify cycle") .option("-t, --task ", "Task description for the run") .option("-l, --loop ", "Loop iterations", parseInt) .option("--skip-proxy-check", "Skip proxy health check") .action(async (opts: { task?: string; loop?: number; skipProxyCheck?: boolean }) => { const { PaiConnector } = await import("./pai/pai-connector.js"); const { ProxyClient } = await import("./pai/proxy-client.js"); const { IsaWriter } = await import("./pai/isa-writer.js"); const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); if (!opts.skipProxyCheck) { const proxy = new ProxyClient(); const ok = await proxy.health(); if (!ok) { console.error(" ✗ Proxy not running. Use --skip-proxy-check to bypass."); process.exit(1); } } const task = opts.task ?? "Run PAI certification cycle — build, test, verify, reflect"; const agent = new MetaAgent(); const connector = new PaiConnector(); const isaWriter = new IsaWriter(); const ctx = connector.loadAll(); const sessionDir = isaWriter.createSessionDir("pai-cert-cycle"); isaWriter.writeIsa(sessionDir, { title: `PAI Certification — ${new Date().toISOString().slice(0, 16)}`, sections: [ { title: "Problem", content: task }, { title: "Vision", content: "A self-certifying agent system that validates its own outputs" }, { title: "Context", content: `TELOS docs: ${ctx.telos.length}, PAI skills: ${ctx.skills.length}` }, { title: "Execution", content: "Pending run" }, ], }); console.log(`\n PAI Certification Cycle`); console.log(` ─────────────────────────────`); console.log(` Task: ${task}`); console.log(` ISA: ${sessionDir}`); console.log(` `); const result = await agent.run(task, { loopIterations: opts.loop ?? 3, }); isaWriter.updateSection(sessionDir, "Execution", `Completed ${result.loopIterations} iterations, converged=${result.converged}\n` + `Knowledge entries: ${result.knowledgeEntryCount}` ); console.log(` ✓ Certification run complete`); console.log(` Iterations: ${result.loopIterations}`); console.log(` Converged: ${result.converged}`); console.log(` ISA updated: ${sessionDir}`); console.log(` `); }); pai .command("bridge") .description("Sync PAI TELOS → FA rubric engine") .action(async () => { const { TELOSBridge } = await import("./pai/pai-fa-bridge.js"); const bridge = new TELOSBridge(); const entries = bridge.scan(); const rubric = bridge.toRubric(); console.log(`\n PAI → FA TELOS Bridge:`); console.log(` Entries found: ${entries.length}`); console.log(` Rubric criteria: ${rubric.criteria.length}`); console.log(` Exit conditions: ${rubric.exitConditions.length}\n`); }); pai .command("memory") .description("Sync PAI memory → FA persistent memory") .action(async () => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { PAIMemoryBridge } = await import("./pai/pai-fa-bridge.js"); const agent = new EnhancedMetaAgent(); const bridge = new PAIMemoryBridge(agent); const result = bridge.importMemory(); console.log(`\n PAI → FA Memory Sync:`); console.log(` Episodic: ${result.episodic}`); console.log(` Semantic: ${result.semantic}\n`); }); pai .command("packs") .description("Import PAI skill packs → FA skill registry") .action(async () => { const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const { PAISkillBridge } = await import("./pai/pai-fa-bridge.js"); const agent = new MetaAgent(); const bridge = new PAISkillBridge(agent.skillRegistry); const result = bridge.importPacks(); console.log(`\n PAI → FA Skill Pack Import:`); console.log(` Created: ${result.created}`); if (result.errors.length > 0) console.log(` Errors: ${result.errors.length}\n`); }); pai .command("report") .description("Show PAI+FA integration report") .action(async () => { const { paiFAReport } = await import("./pai/pai-fa-bridge.js"); console.log(`\n${paiFAReport()}\n`); }); pai .command("run ") .description("Run a PAI goal through FA's engine") .action(async (goal: string) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { TELOSBridge, PAIMemoryBridge } = await import("./pai/pai-fa-bridge.js"); const agent = new EnhancedMetaAgent(); const telos = new TELOSBridge(); // Load PAI TELOS context const entries = telos.scan(); const matching = entries.filter((e) => goal.toLowerCase().includes(e.description.slice(0, 20).toLowerCase()) ); if (matching.length > 0) { agent.context.add({ source: "pai-telos", content: `Related PAI ${matching[0].type}: ${matching[0].description}`, priority: "high", tokenCount: matching[0].description.length, }); } // Import PAI memory for context const memBridge = new PAIMemoryBridge(agent); memBridge.importMemory(); // Run through FA engine const result = await agent.run(goal, { loopIterations: 8 }); console.log(`\n PAI Goal → FA Engine:`); console.log(` Goal: ${goal}`); console.log(` Iterations: ${result.iterations}`); console.log(` Converged: ${result.converged}`); if (result.rubricScore) console.log(` Rubric: ${result.rubricScore}/100`); console.log(``); }); // ── Status ────────────────────────────────────────────────── program .command("status") .description("Show system status overview") .action(() => { const agent = new MetaAgent(); const status = agent.getStatus(); console.log(`\n Fable Agent System Status`); console.log(` ─────────────────────────────`); console.log(` Active session: ${status.activeSession ?? "none"}`); console.log(` Skills: ${status.skills.total} total, ${status.skills.withHistory} with execution history`); console.log(` Knowledge base: ${status.knowledge.entries} entries, ${status.knowledge.tags.length} tags`); console.log(` Context: ${status.context.pct}% of ${status.context.budget.toLocaleString()} token budget`); console.log(` Uptime: ${Math.round(status.uptime)}s`); console.log(` Compound runs: ${status.compoundIterations}`); console.log(` `); }); // ── Workflow ──────────────────────────────────────────────── program .command("workflow") .description("Workflow management") .argument("", "Path to workflow JSON definition") .action(async (file: string) => { const agent = new MetaAgent(); try { const data = fs.readFileSync(file, "utf-8"); const definition = JSON.parse(data); agent.workflowGraph.register(definition); console.log(`\n ✓ Workflow registered: ${definition.name} (${definition.id})`); console.log(` Steps: ${definition.steps.length}`); console.log(` `); } catch (err) { console.error(` ✗ Failed to load workflow: ${err instanceof Error ? err.message : String(err)}`); process.exit(1); } }); // ── Benchmark ──────────────────────────────────────────────── const benchmark = program .command("benchmark") .description("Run benchmarks and measure compounding"); benchmark .command("run") .description("Run all benchmarks and show report") .option("-b, --benchmark ", "Run a specific benchmark by ID") .action(async (opts: { benchmark?: string }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { BenchmarkRunner } = await import("./upgrades/benchmark-runner.js"); const agent = new EnhancedMetaAgent(); const runner = new BenchmarkRunner(agent); if (opts.benchmark) { await runner.runOne(opts.benchmark); } else { await runner.runAll(); } console.log(`\n${runner.report(opts.benchmark)}\n`); }); benchmark .command("trend") .description("Show compounding trend over time") .option("-b, --benchmark ", "Filter by benchmark ID") .action(async (opts: { benchmark?: string }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { BenchmarkRunner } = await import("./upgrades/benchmark-runner.js"); const agent = new EnhancedMetaAgent(); const runner = new BenchmarkRunner(agent); const trend = runner.getTrend(opts.benchmark); const label = opts.benchmark ?? "overall"; console.log(`\n Trend for "${label}":`); console.log(` Runs: ${trend.runs}`); console.log(` Rubric score: ${trend.avgRubricScore.first.toFixed(1)} → ${trend.avgRubricScore.last.toFixed(1)} (${trend.avgRubricScore.delta > 0 ? "+" : ""}${trend.avgRubricScore.delta.toFixed(1)})`); console.log(` Iterations: ${trend.avgIterations.first.toFixed(1)} → ${trend.avgIterations.last.toFixed(1)} (${trend.avgIterations.delta < 0 ? "faster" : "slower"})`); console.log(` Convergence: ${(trend.convergenceRate.first * 100).toFixed(0)}% → ${(trend.convergenceRate.last * 100).toFixed(0)}%\n`); }); benchmark .command("list") .description("List available benchmarks") .action(async () => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { BenchmarkRunner } = await import("./upgrades/benchmark-runner.js"); const agent = new EnhancedMetaAgent(); const runner = new BenchmarkRunner(agent); console.log(`\n Available benchmarks:`); for (const bm of runner.listBenchmarks()) { console.log(` ${bm.id.padEnd(15)} ${bm.name.padEnd(20)} ${bm.tasks.length} tasks`); } console.log(``); }); // ── Cost ───────────────────────────────────────────────────── const cost = program .command("cost") .description("Track model usage costs"); cost .command("report") .description("Show cost summary") .option("-h, --hours ", "Hours to look back", parseInt) .action(async (opts: { hours?: number }) => { const { StateStore } = await import("./core/state-store.js"); const { CostTracker } = await import("./upgrades/cost-tracker.js"); const store = new StateStore(); const tracker = new CostTracker(store); console.log(`\n${tracker.getReport(opts.hours ?? 24)}\n`); }); // ── Exa Search ─────────────────────────────────────────────── const exa = program .command("exa") .description("Exa AI web search and company research"); function requireExaApiKey(): string { const apiKey = process.env.EXA_API_KEY; if (!apiKey) { console.error(" ✗ EXA_API_KEY is required. Set it in your environment or .env file."); process.exit(1); } return apiKey; } exa .command("search ") .description("Search the web via Exa AI") .option("-n, --num-results ", "Number of results", parseInt) .option("-t, --type ", "Search type: keyword, neural, or auto") .option("--include-domains ", "Comma-separated domains to include") .action(async (query: string, opts: { numResults?: number; type?: string; includeDomains?: string }) => { const { StateStore } = await import("./core/state-store.js"); const { ExaSearch } = await import("./upgrades/exa-search.js"); const apiKey = requireExaApiKey(); const exa = new ExaSearch(apiKey, new StateStore()); console.log(`\n Searching: ${query}\n`); const result = await exa.search({ query, numResults: opts.numResults ?? 5, type: (opts.type as "keyword" | "neural" | "auto") ?? "auto", includeDomains: opts.includeDomains?.split(",").map((d) => d.trim()), }); console.log(exa.formatResults(result)); console.log(`\n Credits used: ${result.costCredits}\n`); }); exa .command("company ") .description("Research a company via Exa AI") .action(async (name: string) => { const { ExaSearch } = await import("./upgrades/exa-search.js"); const apiKey = requireExaApiKey(); const exa = new ExaSearch(apiKey); console.log(`\n Researching: ${name}\n`); const result = await exa.companyResearch({ name }); console.log(exa.formatCompany(result)); console.log(``); }); // ── Skills Sync ────────────────────────────────────────────── skills .command("sync") .description("Sync SKILLS/ markdown files with the TS registry") .action(async () => { const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const { SkillSync } = await import("./upgrades/skill-sync.js"); const agent = new MetaAgent(); const syncer = new SkillSync(agent.skillRegistry); const result = syncer.sync(); console.log(`\n Skill sync complete:`); console.log(` Imported: ${result.imported.created} created, ${result.imported.updated} updated`); console.log(` Exported: ${result.exported} written to SKILLS/`); if (result.errors.length > 0) { console.log(` Errors: ${result.errors.length}`); for (const err of result.errors.slice(0, 3)) { console.log(` ${err}`); } } console.log(``); }); // ── Demo ───────────────────────────────────────────────────── program .command("demo") .description("Run the full compounding demonstration (search → learn → sharpen → report)") .option("-q, --query ", "Search query for the demo") .action(async (opts: { query?: string }) => { const { ExaSearch } = await import("./upgrades/exa-search.js"); const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { SkillSync } = await import("./upgrades/skill-sync.js"); const apiKey = requireExaApiKey(); const exa = new ExaSearch(apiKey); const agent = new EnhancedMetaAgent(); const query = opts.query ?? "self-improving AI agent systems loop engineering 2026"; console.log(`\n Demo: Research → Learn → Sharpen → Compound\n`); // Phase 1: Research console.log(` [1/5] Researching: "${query}"`); const searchResults = await exa.search({ query, numResults: 3 }); for (const r of searchResults.results) { console.log(` ✓ ${r.title}`); } // Phase 2: Register console.log(` [2/5] Registering skill from research...`); try { agent.skillRegistry.createFromTemplate({ name: "Research Skill", description: `Knowledge from: ${query}`, steps: [ { label: "Research", instruction: "Search for patterns", expectedOutcome: "Research complete" }, { label: "Extract", instruction: "Extract key patterns", expectedOutcome: "Patterns extracted" }, { label: "Apply", instruction: "Apply patterns", expectedOutcome: "Applied" }, ], tags: ["research", "demo"], }); console.log(` ✓ Skill registered`); } catch { console.log(` ○ Skill already exists`); } // Phase 3: Loop console.log(` [3/5] Running feedback loop...`); const loopResult = await agent.run(query, { loopIterations: 5 }); console.log(` ✓ ${loopResult.iterations} iterations, converged=${loopResult.converged}, rubric=${loopResult.rubricScore ?? "?"}`); // Phase 4: Sharpen console.log(` [4/5] Sharpening skills...`); const reviews = agent.base.skillSharpener.reviewAll(); for (const r of reviews) { console.log(` ✓ ${r.skillId}: ${r.suggestedChanges.length} suggestions`); } // Phase 5: Report console.log(` [5/5] System state after 1 compound cycle:\n`); const status = agent.getStatus(); console.log(` Skills: ${status.skills.total}`); console.log(` Knowledge base: ${status.knowledge.entries} entries`); console.log(` Knowledge tags: ${status.knowledge.tags.slice(0, 5).join(", ")}`); console.log(` Episodic memory: ${status.memory?.episodicCount ?? 0} sessions`); console.log(` Semantic memory: ${status.memory?.semanticCount ?? 0} insights`); console.log(` Context budget: ${status.context.pct}% used`); console.log(``); console.log(` Compounds every run. The harness, not the model.\n`); }); // ── Learned ────────────────────────────────────────────────── program .command("learned") .description("Show everything the system has learned across all storage layers") .option("-v, --verbose", "Show full content instead of summaries") .action(async (opts: { verbose?: boolean }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const agent = new EnhancedMetaAgent(); const status = agent.getStatus(); const memory = agent.memory.getStats(); console.log(`\n╔════════════════════════════════════════════╗`); console.log(`║ SYSTEM KNOWLEDGE REPORT ║`); console.log(`╚════════════════════════════════════════════╝\n`); // Section 1: Skills console.log(`Skills: ${status.skills.total} total, ${status.skills.withHistory} with execution history`); for (const skill of agent.skillRegistry.list()) { console.log(` ${skill.name} v${skill.version}`); console.log(` Steps: ${skill.steps.length}`); console.log(` Executions: ${skill.metrics.totalExecutions}`); console.log(` Quality: ${(skill.metrics.avgQualityScore * 100).toFixed(0)}%`); console.log(` Evolutions: ${skill.metrics.evolutionCount}`); if (opts.verbose && skill.history.length > 0) { console.log(` Recent results:`); for (const h of skill.history.slice(-3)) { console.log(` ${h.completedAt.slice(0, 10)} q=${h.qualityScore.toFixed(2)} ${h.success ? "pass" : "fail"}`); } } } // Section 2: Knowledge Base console.log(`\nKnowledge Base: ${status.knowledge.entries} entries`); const tags = agent.stateRepository.getTags(); if (tags.length > 0) { console.log(` Tags: ${tags.join(", ")}`); } // Section 3: Memory console.log(`\nPersistent Memory:`); console.log(` Episodic: ${memory.episodicCount} sessions (what happened)`); console.log(` Semantic: ${memory.semanticCount} insights (what it means)`); console.log(` Procedural: ${memory.proceduralCount} recipes (how to do it)`); // Section 4: Sessions const sessions = agent.session.list(); console.log(`\nSessions: ${sessions.length} total`); const recent = sessions.slice(0, 3); for (const s of recent) { const age = Math.round((Date.now() - new Date(s.createdAt).getTime()) / 60000); console.log(` ${s.id.slice(0, 8)}… ${s.status.padEnd(12)} ${age}m ago "${s.task.slice(0, 50)}"`); } // Section 5: Compound metrics console.log(`\nCompounding:`); console.log(` Runs: ${status.compoundIterations}`); console.log(` Total skills: ${status.skills.total}`); console.log(` Total entries: ${status.knowledge.entries + memory.episodicCount + memory.semanticCount + memory.proceduralCount}`); // Section 6: Cost (if data exists) const { CostTracker } = await import("./upgrades/cost-tracker.js"); const tracker = new CostTracker(agent.store); const costSummary = tracker.getSummary(168); // 7 days if (costSummary.totalSpend > 0) { console.log(`\nCost (7 days): $${costSummary.totalSpend.toFixed(2)}`); for (const [model, data] of Object.entries(costSummary.byModel)) { console.log(` ${model}: ${data.calls} calls, $${data.cost.toFixed(4)}`); } } else { console.log(`\nCost: No model calls recorded yet`); } console.log(``); console.log(` Every run compounds. The harness, not the model.\n`); }); // ── Familiar ──────────────────────────────────────────────── const familiar = program .command("familiar") .description("Familiar knowledge base — inbox-to-wiki processing"); familiar .command("capture ") .description("Quick capture — drop a note into inbox") .option("-s, --source ", "Source label (voice, web, idea, etc.)") .action(async (note: string, opts: { source?: string }) => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const f = new FamiliarKnowledge(); const path = f.quickCapture(note, opts.source); console.log(`\n ✓ Captured to: ${path}\n`); }); familiar .command("process") .description("Process all inbox notes into wiki pages") .action(async () => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const f = new FamiliarKnowledge(); const notes = f.scanInbox(); if (notes.length === 0) { console.log(` No notes in inbox/ to process.\n`); return; } // Default classifier — generates basic wiki pages from inbox content const classifier = (content: string) => { const firstLine = content.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? "Untitled"; const tags = ["inbox"]; if (content.toLowerCase().includes("loop")) tags.push("loops"); if (content.toLowerCase().includes("agent")) tags.push("agent"); if (content.toLowerCase().includes("safety")) tags.push("safety"); return { title: firstLine, summary: content.split("\n").slice(1, 3).join(" ").trim().slice(0, 300), confidence: 0.5, tags, mentions: [], contradictions: [], }; }; const processed = f.processAllInbox(classifier); f.autoCommit(`familiar: processed ${processed.length} inbox notes`); console.log(`\n Processed ${processed.length} notes:\n`); for (const p of processed) { console.log(` ✓ ${p.frontmatter.title}`); console.log(` Tags: ${p.frontmatter.tags.join(", ")}`); console.log(` Wiki: ${p.wikiPath}`); } console.log(``); }); familiar .command("graph") .description("Show knowledge graph") .action(async () => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const f = new FamiliarKnowledge(); const graph = f.buildGraphIndex(); console.log(`\n Knowledge Graph:`); console.log(` ${graph.nodes.length} pages, ${graph.edges.length} connections\n`); for (const node of graph.nodes) { const edges = graph.edges.filter((e) => e.source === node.id); console.log(` ${node.title}`); for (const e of edges) console.log(` → ${e.target}`); } console.log(``); }); familiar .command("health") .description("Audit wiki health — detect orphaned pages, low confidence, missing backlinks") .action(async () => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const f = new FamiliarKnowledge(); const health = f.graphHealth(); console.log(`\n Graph Health:\n`); console.log(` Pages: ${health.stats.totalPages}`); console.log(` Edges: ${health.stats.totalConnections}`); console.log(` Orphaned: ${health.stats.orphanedPages}`); console.log(` No backlinks: ${health.stats.pagesWithoutBacklinks}`); console.log(` Low confidence: ${health.stats.pagesWithLowConfidence}\n`); if (health.issues.length > 0) { console.log(` Issues:`); for (const issue of health.issues.slice(0, 5)) { console.log(` • ${issue}`); } } console.log(``); }); familiar .command("briefing") .description("Generate daily briefing page") .action(async () => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const f = new FamiliarKnowledge(); const briefing = f.generateBriefing(); console.log(`\n${briefing}\n`); }); familiar .command("loop") .description("Process inbox notes, detect simple contradictions, and queue follow-up goals") .option("-p, --priority ", "Queued goal priority (1=high, 2=normal, 3=low)", parseInt, 1) .option("-d, --dir ", "Base directory containing inbox/wiki/resources", process.cwd()) .action(async (opts: { priority?: number; dir?: string }) => { const { FamiliarKnowledge } = await import("./upgrades/familiar-knowledge.js"); const { GoalQueue } = await import("./upgrades/goal-queue.js"); const { StateStore } = await import("./core/state-store.js"); const f = new FamiliarKnowledge(opts.dir); const queue = new GoalQueue(new StateStore()); const priorClaims = loadWikiClaims(opts.dir ?? process.cwd()); const priority = opts.priority === 2 || opts.priority === 3 ? opts.priority : 1; const processed = f.processAllInbox((content) => { const firstLine = content.split("\n")[0]?.replace(/^#\s*/, "").trim() || "Untitled note"; const claims = splitClaims(content); const contradictions = claims.flatMap((claim) => detectSimpleContradictions(claim, priorClaims)); return { title: firstLine.slice(0, 80), summary: claims.join("; ").slice(0, 300), confidence: contradictions.length > 0 ? 0.9 : 0.6, tags: contradictions.length > 0 ? ["second-brain", "contradiction"] : ["second-brain"], mentions: [], backlinks: [], contradictions, }; }); const queued: string[] = []; for (const note of processed) { for (const contradiction of note.contradictions) { queued.push(queue.push(`Resolve contradiction in ${path.basename(note.wikiPath)}: ${contradiction}`, { priority, tags: ["second-brain", "contradiction"], }).id); } } console.log(`\n Familiar loop`); console.log(` Processed: ${processed.length} note(s)`); console.log(` Queued: ${queued.length} contradiction goal(s)`); if (queued.length > 0) console.log(` Goal IDs: ${queued.slice(0, 3).join(", ")}`); console.log(``); }); // ── PAI Pi ─────────────────────────────────────────────────── const paiPi = program .command("pai-pi") .description("PAI Pi integration (PAI via Pi executor)"); paiPi .command("status") .description("Show PAI Pi integration status") .action(async () => { const { paiPiReport } = await import("./pai/pai-pi-bridge.js"); console.log(`\n${paiPiReport()}\n`); }); paiPi .command("skills") .description("Import PAI Pi skills into FA skill registry") .action(async () => { const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const { importPaiPiSkills } = await import("./pai/pai-pi-bridge.js"); const agent = new MetaAgent(); const result = importPaiPiSkills(agent.skillRegistry); console.log(`\n PAI Pi → FA Skill Import:`); console.log(` Created: ${result.created}`); if (result.errors.length > 0) console.log(` Errors: ${result.errors.length}`); console.log(``); }); paiPi .command("run ") .description("Run a task through PAI Pi system prompt + Pi executor") .option("-l, --loop ", "Number of feedback loop iterations", parseInt) .action(async (goal: string, opts: { loop?: number }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { PiExecutor } = await import("./examples/executors/pi-executor.js"); const { createPiExecutorForPAI } = await import("./pai/pai-pi-bridge.js"); const paiPiConfig = createPiExecutorForPAI(); const agent = new EnhancedMetaAgent({ selfValidate: false }); // Inject PAI Pi system prompt into context agent.context.add({ source: "pai-pi", content: paiPiConfig.systemPrompt.slice(0, 2000), priority: "critical", tokenCount: paiPiConfig.systemPrompt.length, }); // Create Pi executor with PAI Pi config const executor = new PiExecutor({ provider: paiPiConfig.provider, model: paiPiConfig.model, systemPrompt: paiPiConfig.systemPrompt.slice(0, 500), }); // Run through FA's loop with Pi as the executor const result = await agent.run(goal, { executor, loopIterations: opts.loop ?? 8, }); console.log(`\n PAI Pi → FA Engine:`); console.log(` Goal: ${goal}`); console.log(` Provider: ${paiPiConfig.provider}`); console.log(` Model: ${paiPiConfig.model}`); console.log(` Iterations: ${result.iterations}`); console.log(` Converged: ${result.converged}`); if (result.rubricScore) console.log(` Rubric: ${result.rubricScore}/100`); console.log(``); }); // ── Daemon ────────────────────────────────────────────────── const daemon = program .command("daemon") .description("Persistent 24/7 autonomous daemon"); daemon .command("start") .description("Start the daemon") .option("-d, --detach", "Run in background (detach from terminal)") .action(async (opts: { detach?: boolean }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { GoalQueue } = await import("./upgrades/goal-queue.js"); const { DaemonEngine } = await import("./upgrades/daemon-engine.js"); if (opts.detach) { // Fork a child process for background operation const { spawn } = await import("node:child_process"); const child = spawn( process.execPath, ["dist/index.js", "daemon", "start"], { detached: true, stdio: "ignore", env: { ...process.env, FABLE_DAEMON: "1" } } ); child.unref(); const fs = await import("node:fs"); const path = await import("node:path"); const pidDir = path.join(process.env.FABLE_DATA_DIR || process.env.HOME || ".", ".fable-agent"); try { fs.mkdirSync(pidDir, { recursive: true }); } catch {} fs.writeFileSync(path.join(pidDir, "daemon.pid"), String(child.pid)); console.log(`\n Daemon started in background (PID: ${child.pid})`); console.log(` Use \`fable-agent daemon stop\` to stop it.\n`); return; } const agent = new EnhancedMetaAgent(); const queue = new GoalQueue(agent.store); const engine = new DaemonEngine(agent, queue); console.log(`\n Starting daemon...`); console.log(` Queue: ${queue.stats().queued} queued, ${queue.stats().completed} completed`); console.log(` Run \`fable-agent daemon queue \` in another terminal to add goals`); console.log(` Press Ctrl+C to stop\n`); // Handle graceful shutdown process.on("SIGINT", () => { console.log(`\n Stopping daemon...`); engine.stop(); }); await engine.start(); }); daemon .command("stop") .description("Request daemon to stop") .action(async () => { // Check for PID file first (detached daemon) const { readFileSync, existsSync, rmSync } = await import("node:fs"); const pidPath = (await import("node:path")).join( process.env.FABLE_DATA_DIR || process.env.HOME || ".", ".fable-agent", "daemon.pid" ); if (existsSync(pidPath)) { try { const pid = parseInt(readFileSync(pidPath, "utf-8").trim(), 10); process.kill(pid, "SIGTERM"); rmSync(pidPath); console.log(` Daemon (PID ${pid}) stopped.`); return; } catch (err) { console.log(` Could not stop via PID file: ${err}`); } } // Fallback: write stop signal const store = new (await import("./core/state-store.js")).StateStore(); store.write("daemon", "stop-signal.json", { timestamp: new Date().toISOString() }); console.log(` Stop signal sent. The daemon will stop after the current goal.`); }); daemon .command("status") .description("Show daemon status") .action(async () => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { GoalQueue } = await import("./upgrades/goal-queue.js"); const { DaemonEngine } = await import("./upgrades/daemon-engine.js"); const agent = new EnhancedMetaAgent(); const queue = new GoalQueue(agent.store); const engine = new DaemonEngine(agent, queue); console.log(`\n${engine.getReport()}\n`); }); daemon .command("queue ") .description("Add a goal to the daemon queue") .option("-p, --priority ", "Priority (1=high, 2=normal, 3=low)", parseInt) .option("-t, --tags ", "Comma-separated tags") .action(async (goal: string, opts: { priority?: number; tags?: string }) => { const { EnhancedMetaAgent } = await import("./upgrades/enhanced-meta-agent.js"); const { GoalQueue } = await import("./upgrades/goal-queue.js"); const agent = new EnhancedMetaAgent(); const queue = new GoalQueue(agent.store); const queued = queue.push(goal, { priority: (opts.priority ?? 2) as 1 | 2 | 3, tags: opts.tags?.split(",").map((t: string) => t.trim()) ?? [], }); console.log(`\n ✓ Goal queued:`); console.log(` ID: ${queued.id}`); console.log(` Goal: ${queued.description.slice(0, 60)}`); console.log(` Priority: ${queued.priority}`); const stats = queue.stats(); console.log(` Queue: ${stats.queued} pending, ${stats.completed} completed\n`); }); // ── Fable 5 ───────────────────────────────────────────────── const fable = program .command("fable5") .description("Fable 5 self-improving system commands (14-step architecture)"); fable .command("status") .description("Show Fable 5 stack status") .action(async () => { const { CompoundStack } = await import("./fable5/compound-stack.js"); const stack = new CompoundStack(); console.log(`\n${stack.getStatus()}\n`); }); fable .command("route ") .description("Route a task through the model cost-capability matrix") .option("-d, --domain ", "Task domain: code|research|analysis|creative|planning|grading") .action(async (task: string, opts: { domain?: string }) => { const { ModelRouter } = await import("./fable5/model-router.js"); const router = new ModelRouter(); const complexity = router.taskComplexity(task); const domain = (opts.domain ?? "code") as "code" | "research" | "analysis" | "creative" | "planning" | "grading"; const route = router.route({ task, domain: domain as never, complexity, requiresVision: false }); console.log(`\n Model Routing for: "${task.slice(0, 60)}..."`); console.log(` ─────────────────────────────`); console.log(` Complexity: ${complexity}`); console.log(` Domain: ${domain}`); console.log(` `); console.log(` Orchestrator: ${route.primary.displayName} (${route.primary.tier})`); console.log(` Worker: ${route.fallback.displayName} (${route.fallback.tier})`); console.log(` Grader: ${route.grader.displayName} (${route.grader.tier})`); console.log(` Reason: ${route.reason}`); console.log(` `); if (complexity === "extreme" || complexity === "complex") { console.log(` Estimated cost (100K in / 20K out):`); console.log(` Primary: $${router.estimateCost(route, 100000, 20000).toFixed(2)}`); const cheapRoute = router.route({ task, domain: domain as never, complexity: "simple", requiresVision: false }); console.log(` If downgraded: $${router.estimateCost(cheapRoute, 100000, 20000).toFixed(2)}`); console.log(` `); } }); fable .command("models") .description("List all models in the routing matrix") .action(async () => { const { ModelRouter } = await import("./fable5/model-router.js"); const router = new ModelRouter(); const models = router.listModels(); console.log(`\n Model Routing Matrix (${models.length} models):`); console.log(` ─────────────────────────────`); for (const m of models) { console.log(` ${m.modelId.padEnd(24)} ${m.tier.padEnd(8)} $${String(m.costPer1kIn).padStart(3)}/1K in $${String(m.costPer1kOut).padStart(3)}/1K out`); console.log(` ${" ".repeat(26)}${m.recommendedFor.join(", ")}`); } console.log(` `); }); fable .command("verify ") .description("Run independent verifier against a task") .option("--repo ", "Also run the repo verification gate at this path") .action(async (task: string, opts: { repo?: string }) => { if (opts.repo) { const { spawnSync } = await import("node:child_process"); const repo = path.resolve(opts.repo); const checks: Array<[string, string[]]> = [ ["npm", ["run", "-s", "test"]], ["npm", ["run", "-s", "build"]], ["npm", ["run", "-s", "docs:check"]], ["npx", ["tsc", "--noEmit"]], [process.execPath, [process.argv[1], "security", "scan", repo]], ]; console.log(` Repo Verification Gate: ${repo}`); for (const [cmd, args] of checks) { console.log(` $ ${[cmd, ...args].join(" ")}`); // ponytail: Windows npm/npx shims need cmd.exe; commands are fixed, no user shell input. const check = process.platform === "win32" && (cmd === "npm" || cmd === "npx") ? spawnSync("cmd.exe", ["/d", "/s", "/c", [cmd, ...args].join(" ")], { cwd: repo, stdio: "inherit" }) : spawnSync(cmd, args, { cwd: repo, stdio: "inherit" }); if (check.status !== 0) { console.error(` ✗ Repo verification failed`); process.exit(check.status ?? 1); } } console.log(` ✓ Repo verification passed `); } const { IndependentVerifier } = await import("./fable5/independent-verifier.js"); const verifier = new IndependentVerifier(); const dummyIteration = { number: 1, phase: "refine" as const, plan: `Plan for: ${task}`, executed: `Executing: ${task}`, observation: `Observing results...`, reflection: `Task completed: ${task}`, refinement: `Refined approach based on reflection`, metrics: { durationMs: 1000, successRate: 0.9, qualityScore: 0.7, improvementDelta: 0.1 }, timestamp: new Date().toISOString(), }; const result = verifier.verify(dummyIteration, task); console.log(`\n Independent Verifier Results`); console.log(` ─────────────────────────────`); console.log(` Verdict: ${result.verdict}`); console.log(` `); console.log(` Criteria:`); for (const c of result.criteriaResults) { console.log(` ${c.passed ? "✓" : "✗"} ${c.criterionId}: ${c.evidence}`); } if (result.gaps.length > 0) { console.log(` `); console.log(` Gaps:`); for (const g of result.gaps) console.log(` • ${g}`); } console.log(` `); }); fable .command("goal ") .description("Set a /goal with rubric criteria and run evaluation") .option("-i, --iterations ", "Max iterations", parseInt) .option("-s, --min-score ", "Minimum score to pass", parseFloat) .action(async (text: string, opts: { iterations?: number; minScore?: number }) => { const { GoalPattern } = await import("./fable5/goal-pattern.js"); const { FeedbackLoop } = await import("./tier2-primitives/loops/feedback-loop.js"); const { StateStore } = await import("./core/state-store.js"); const goal = new GoalPattern(); const goalId = goal.setGoal({ text, criteria: [ { label: "Correctness", description: "Output is technically correct", weight: 0.4, required: true }, { label: "Completeness", description: "All requirements addressed", weight: 0.3, required: true }, { label: "Clarity", description: "Output is clear", weight: 0.2, required: false }, { label: "Efficiency", description: "Solution is efficient", weight: 0.1, required: false }, ], maxIterations: opts.iterations ?? 5, minScore: opts.minScore ?? 0.7, }); const store = new StateStore(); const loop = new FeedbackLoop(store, `goal-${goalId}`); console.log(`\n /goal: "${text}"`); console.log(` ID: ${goalId}`); console.log(` ─────────────────────────────`); for (let i = 0; i < (opts.iterations ?? 5); i++) { const iteration = { number: i + 1, phase: "refine" as const, plan: `Iteration ${i + 1} plan`, executed: `Executing iteration ${i + 1}`, observation: `Observing...`, reflection: `Completed iteration ${i + 1}`, refinement: `Refined approach`, metrics: { durationMs: 500, successRate: 0.8 + i * 0.02, qualityScore: 0.3 + i * 0.1, improvementDelta: 0.05 }, timestamp: new Date().toISOString(), }; loop.getAccumulator().record(iteration); const result = goal.evaluateIteration(goalId, iteration, loop.getAccumulator()); console.log(` Iteration ${i + 1}: score=${result.score.toFixed(2)} ${result.done ? "✓" : "→"}`); if (result.done) { console.log(` `); console.log(` ✓ Goal ${result.reason.toLowerCase().includes("score") ? "converged" : "reached max iterations"}`); console.log(` Final score: ${result.score.toFixed(2)}`); console.log(` Reason: ${result.reason}`); console.log(` `); return; } } console.log(` `); console.log(` ○ Goal did not converge within ${opts.iterations ?? 5} iterations`); console.log(` `); }); fable .command("worktree") .description("Manage git worktree isolation") .argument("", "list|create|remove|prune") .argument("[name]", "Worktree name") .action(async (action: string, name: string) => { const { WorktreeManager } = await import("./fable5/worktree-isolation.js"); const wt = new WorktreeManager(); switch (action) { case "list": { const trees = wt.list(); if (trees.length === 0) { console.log(" No worktrees found."); return; } console.log(`\n Worktrees (${trees.length}):`); for (const t of trees) { console.log(` ${t.name.padEnd(20)} ${t.branch.padEnd(30)} ${t.isDirty ? "dirty" : "clean"}`); } console.log(` `); break; } case "create": { if (!name) { console.error(" ✗ Name required"); process.exit(1); } const spec = wt.createForAgent(name); const path = wt.createAndCheckout(spec); console.log(`\n ✓ Worktree created:`); console.log(` Name: ${spec.name}`); console.log(` Branch: ${spec.branch}`); console.log(` Path: ${path}`); console.log(` `); break; } case "remove": { if (!name) { console.error(" ✗ Name required"); process.exit(1); } wt.remove(name); console.log(` ✓ Worktree removed: ${name}`); break; } case "prune": wt.prune(); console.log(" ✓ Worktrees pruned"); break; default: console.error(` ✗ Unknown action: ${action}. Use: list|create|remove|prune`); process.exit(1); } }); fable .command("state ") .description("Manage 5-stage state file") .option("--add-fact ", "Add a verified fact") .option("--add-rule ", "Add a general rule") .option("--add-failure ", "Add a failure entry") .option("--add-lesson ", "Add a lesson learned") .option("--import", "Import from knowledge base") .action(async (project: string, opts: Record) => { const { FiveStageStateFile } = await import("./fable5/state-file-5stage.js"); const state = new FiveStageStateFile(); if (opts.addFact) { state.addVerifiedFact(project, opts.addFact as string, "cli"); console.log(` ✓ Verified fact added to "${project}"`); } else if (opts.addRule) { state.addGeneralRule(project, opts.addRule as string, "cli"); console.log(` ✓ General rule added to "${project}"`); } else if (opts.addFailure) { state.addFailure(project, opts.addFailure as string); console.log(` ✓ Failure added to "${project}"`); } else if (opts.addLesson) { state.addLesson(project, opts.addLesson as string); console.log(` ✓ Lesson added to "${project}"`); } else if (opts.import) { const { MetaAgent } = await import("./tier3-compounding/meta-agent.js"); const agent = new MetaAgent(); const entries = agent.stateRepository.query({ limit: 50 }); const count = state.importFromKnowledgeEntries(project, entries); console.log(` ✓ Imported ${count} knowledge entries into "${project}" state file`); } else { const loaded = state.load(project); if (!loaded) { console.log(` No state file found for "${project}". Use --add-fact/--add-rule to create one.`); return; } console.log(`\n State File: ${project}`); console.log(` ─────────────────────────────`); console.log(` Facts: ${loaded.verifiedFacts.length}`); console.log(` Rules: ${loaded.generalRules.length}`); console.log(` Fails: ${loaded.openFailures.length}`); console.log(` Lessons: ${loaded.lessonsLearned.length}`); if (loaded.lastSession.summary) { console.log(` Last: ${loaded.lastSession.summary.slice(0, 80)}`); } console.log(` Updated: ${loaded.lastUpdated.slice(0, 16)}`); console.log(` `); } }); fable .command("workflow ") .description("Run a dynamic workflow pattern: fan-out|adversarial|loop|godmode|parseltongue") .option("-s, --subtasks ", "Comma-separated sub-tasks for fan-out pattern") .option("-n, --max-iterations ", "Max iterations for loop-until-done", parseInt) .option("-p, --panel ", "GodMode panel: sprint-3|sprint-5|gauntlet-10|ultra-5tier", "sprint-3") .option("--category ", "Parseltongue category filter") .option("--intensity ", "Parseltongue intensity filter: low|medium|high") .action(async (pattern: string, task: string, opts: { subtasks?: string; maxIterations?: number; panel?: string; category?: string; intensity?: string }) => { const { DynamicWorkflows } = await import("./fable5/dynamic-workflows.js"); const { IndependentVerifier } = await import("./fable5/independent-verifier.js"); switch (pattern) { case "fan-out": { if (!opts.subtasks) { console.error(" ✗ --subtasks required for fan-out pattern"); process.exit(1); } const subTasks = opts.subtasks.split(",").map((s) => s.trim()); const wf = new DynamicWorkflows(); const executor = (subTask: string, _i: number, routeContext?: { flow?: "direct" | "planning" | "review"; reason?: string }): LoopIteration => ({ number: _i + 1, phase: "execute" as const, plan: `Executing sub-task: ${subTask}`, executed: `Completed: ${subTask}`, observation: `Sub-task results: ${subTask}`, reflection: `Sub-task ${_i + 1} done${routeContext?.flow ? ` (${routeContext.flow})` : ""}`, refinement: routeContext?.reason ?? "", metrics: { durationMs: 100, successRate: 0.9, qualityScore: 0.7, improvementDelta: 0.05 }, timestamp: new Date().toISOString(), }); const synthesizer = (results: LoopIteration[], _task: string): LoopIteration => ({ number: results.length + 1, phase: "refine" as const, plan: `Synthesizing ${results.length} results for: ${_task}`, executed: `Synthesized: ${results.map((r) => r.observation).join("; ")}`, observation: `Synthesis complete for: ${_task}`, reflection: `All ${results.length} sub-tasks completed`, refinement: `Final synthesis done`, metrics: { durationMs: 200, successRate: 0.95, qualityScore: 0.8, improvementDelta: 0.1 }, timestamp: new Date().toISOString(), }); const result = await wf.fanOutAndSynthesize(task, subTasks, executor, synthesizer); console.log(`\n Fan-Out-and-Synthesize Results`); console.log(` ─────────────────────────────`); console.log(` Sub-tasks: ${subTasks.length}`); console.log(` Iterations: ${result.iterations.length}`); console.log(` Synthesis verdict: ${result.synthesisVerdict.verdict}`); if (result.routeContexts.length > 0) { const counts = result.routeContexts.reduce( (acc, rc) => { acc[rc.flow] = (acc[rc.flow] ?? 0) + 1; return acc; }, {} as Record, ); console.log(` Route flows: direct=${counts.direct ?? 0}, planning=${counts.planning ?? 0}, review=${counts.review ?? 0}`); } console.log(` `); if (result.synthesisVerdict.gaps.length > 0) { console.log(` Gaps:`); for (const g of result.synthesisVerdict.gaps) console.log(` • ${g}`); console.log(` `); } break; } case "adversarial": { const wf = new DynamicWorkflows(); const makerIteration: LoopIteration = { number: 1, phase: "execute" as const, plan: `Executing: ${task}`, executed: `Completed implementation of: ${task}`, observation: `Implementation done for: ${task}`, reflection: `Task completed`, refinement: "", metrics: { durationMs: 500, successRate: 0.85, qualityScore: 0.7, improvementDelta: 0.05 }, timestamp: new Date().toISOString(), }; const result = await wf.adversarialVerify(makerIteration, task); console.log(`\n Adversarial Verification Results`); console.log(` ─────────────────────────────`); console.log(` Maker iteration: #${result.maker.number}`); console.log(` Verifier verdict: ${result.verifier.verdict}`); console.log(` Passed: ${result.passed ? "✓" : "✗"}`); console.log(` `); for (const c of result.verifier.criteriaResults) { console.log(` ${c.passed ? "✓" : "✗"} ${c.criterionId}: ${c.evidence}`); } if (result.verifier.gaps.length > 0) { console.log(` `); console.log(` Gaps: ${result.gapSummary}`); } console.log(` `); break; } case "loop": { const wf = new DynamicWorkflows(); const executor = (_i: number, _prev: LoopIteration | null): LoopIteration => ({ number: _i + 1, phase: "refine" as const, plan: `Iteration ${_i + 1} of: ${task}`, executed: `Executed iteration ${_i + 1}`, observation: `Observations from iteration ${_i + 1}`, reflection: `Completed iteration ${_i + 1}`, refinement: `Refined approach for next iteration`, metrics: { durationMs: 200, successRate: 0.7 + _i * 0.03, qualityScore: 0.3 + _i * 0.08, improvementDelta: 0.05 }, timestamp: new Date().toISOString(), }); const result = await wf.loopUntilDone(task, executor, { maxIterations: opts.maxIterations ?? 5, convergenceThreshold: 0.75, }); console.log(`\n Loop-Until-Done Results`); console.log(` ─────────────────────────────`); console.log(` Task: ${task.slice(0, 60)}`); console.log(` Total rounds: ${result.totalRounds}`); console.log(` Final verdict: ${result.finalVerdict.verdict}`); console.log(` `); for (const c of result.finalVerdict.criteriaResults) { console.log(` ${c.passed ? "✓" : "✗"} ${c.criterionId}: ${c.evidence}`); } console.log(` `); break; } case "godmode": { const { GodModeClassic } = await import("./upgrades/godmode-classic.js"); const wf = new DynamicWorkflows(); wf.enableGodMode(new GodModeClassic({ panelSlug: opts.panel as any, callModel: async (modelId, prompt) => [ `Model: ${modelId}`, `Task: ${prompt}`, "", "Candidate:", "- Identify the requested outcome.", "- Produce a concise implementation plan.", "- Verify with deterministic checks before reporting completion.", ].join("\n"), })); const result = await wf.godmodeRace(task, opts.panel as any); console.log(`\n GodMode Workflow Results`); console.log(` ========================`); console.log(` Task: ${task.slice(0, 60)}`); console.log(` Mode: ${result.raceType}`); console.log(` Winner: ${result.winner.modelId} (${(result.winner.qualityScore * 100).toFixed(0)}/100)`); console.log(` Runners: ${result.racers.length}/${result.config.parallelCount}`); console.log(` Duration: ${result.totalDurationMs}ms`); console.log(``); console.log(result.winner.output.slice(0, 1200)); console.log(``); break; } case "parseltongue": { const wf = new DynamicWorkflows(); const { ContentSafetyGate } = await import("./upgrades/content-safety-gate.js"); const gate = new ContentSafetyGate(); const result = await wf.parseltongueTest( task, (perturbed: string) => gate.evaluate(perturbed).action !== "allow", { category: opts.category as any, intensity: opts.intensity as any, }, ); console.log(`\n Parseltongue Workflow Results`); console.log(` =============================`); console.log(` Tests: ${result.summary.totalTests}`); console.log(` Bypasses: ${result.summary.bypassesDetected}`); if (result.summary.gateWeaknesses.length > 0) { console.log(` Gate weaknesses: ${result.summary.gateWeaknesses.join("; ")}`); } console.log(``); for (const item of result.results) { const status = item.bypassed ? "BYPASS" : "BLOCKED"; console.log(` ${status.padEnd(7)} ${item.category.padEnd(13)} ${item.intensity.padEnd(6)} ${item.techniqueName}`); } console.log(``); break; } default: console.error(` ✗ Unknown pattern: ${pattern}. Use: fan-out|adversarial|loop|godmode|parseltongue`); process.exit(1); } }); fable .command("compound ") .description("Write a lesson into the most relevant PAI skill") .option("--skill ", "Target skill name (auto-detect if omitted)") .action(async (lesson: string, opts: { skill?: string }) => { const { SkillSync } = await import("./pai/skill-sync.js"); const ss = new SkillSync(); if (opts.skill) { const path = ss.compoundLesson(opts.skill, lesson, "cli"); if (!path) { console.error(` ✗ Skill "${opts.skill}" not found`); process.exit(1); } console.log(`\n ✓ Lesson compounded into "${opts.skill}"`); console.log(` Path: ${path}`); console.log(` Lesson: ${lesson.slice(0, 80)}`); console.log(` `); return; } const relevant = ss.findRelevantSkill(lesson); if (!relevant) { console.log(` No relevant PAI skill found for this lesson.`); console.log(` Use --skill to target a specific skill.`); console.log(` `); return; } const path = ss.compoundLesson(relevant.name, lesson, "cli"); if (path) { console.log(`\n ✓ Lesson compounded into "${relevant.name}" (score: ${relevant.score})`); console.log(` Path: ${path}`); console.log(` `); } }); // ── Tier 3: Multi-Agent Orchestration ────────────────────── fable .command("chain ") .description("Run agent chain: Scout → Plan → Build → Review") .option("--stages ", "Comma-separated stages (scout,plan,build,review)") .action(async (task: string, opts: { stages?: string }) => { const { AgentChain } = await import("./fable5/agent-chains.js"); const chain = new AgentChain(); const stages = opts.stages?.split(",").map((s) => s.trim()) as import("./fable5/agent-chains.js").ChainStage[] | undefined; const result = await chain.run(task, stages); console.log(`\n Agent Chain Results`); console.log(` ─────────────────────────────`); console.log(` Task: "${task.slice(0, 60)}..."`); console.log(` Duration: ${result.totalDurationMs}ms`); console.log(` Passed: ${result.passed ? "✓" : "✗"}`); console.log(` `); for (const a of result.artifacts) { console.log(` ${a.stage.toUpperCase().padEnd(10)} ${a.modelName.padEnd(30)} ${a.durationMs}ms`); } for (const v of result.verifications) { console.log(` Verdict: ${v.verdict} (${v.criteriaResults.filter((c) => c.passed).length}/${v.criteriaResults.length} criteria passed)`); } console.log(` `); }); fable .command("meta ") .description("Meta-agent: configure and execute optimal sub-agent team") .option("--stages ", "Chain stages for execution") .action(async (task: string, opts: { stages?: string }) => { const { MetaAgent } = await import("./fable5/meta-agent.js"); const meta = new MetaAgent(); if (opts.stages) { const stages = opts.stages.split(",").map((s) => s.trim()) as import("./fable5/agent-chains.js").ChainStage[]; const result = await meta.run(task, { stages }); console.log(`\n Meta-Agent Results`); console.log(` ─────────────────────────────`); console.log(` ${result.config.rationale}`); console.log(` Chain passed: ${result.chainResult.passed ? "✓" : "✗"}`); console.log(` `); for (const a of result.chainResult.artifacts) { console.log(` ${a.stage.toUpperCase().padEnd(10)} ${a.modelName.padEnd(30)} ${a.durationMs}ms`); } console.log(` `); } else { const config = meta.configure(task); console.log(`\n Meta-Agent Configuration`); console.log(` ─────────────────────────────`); console.log(` ${config.rationale}`); console.log(` `); console.log(` Sub-agents:`); for (const a of config.config.subAgents) { console.log(` ${a.name.padEnd(14)} ${a.modelTier.padEnd(8)} ${a.role.slice(0, 50)}`); console.log(` ${" ".repeat(14)} Tools: ${a.tools.join(", ")}`); if (a.domainLock) console.log(` ${" ".repeat(14)} Domain: ${a.domainLock}`); console.log(` `); } } }); fable .command("teams ") .description("Run 3-tier agent team: orchestrator → leads → workers") .option("--workers ", "Comma-separated worker types (frontend,backend,qa,security,devops)") .action(async (task: string, opts: { workers?: string }) => { const { AgentTeams } = await import("./fable5/agent-teams.js"); const teams = new AgentTeams(); const workers = opts.workers?.split(",").map((s) => s.trim()); const result = await teams.run(task, workers); console.log(`\n Agent Team Results`); console.log(` ─────────────────────────────`); console.log(` Task: "${task.slice(0, 60)}..."`); console.log(` Passed: ${result.passed ? "✓" : "✗"}`); console.log(` Duration: ${result.totalDurationMs}ms`); console.log(` `); console.log(` Orchestrator:`); console.log(` ${result.config.orchestrator.name} (${result.config.orchestrator.tier})`); console.log(` `); console.log(` Leads:`); for (const l of result.config.leads) { console.log(` ${l.name.padEnd(20)} ${l.tier}`); } console.log(` `); console.log(` Workers:`); for (const w of result.config.workers) { console.log(` ${w.name.padEnd(14)} ${w.tier.padEnd(8)} Lock: ${w.domainLock}`); } console.log(` `); console.log(` Verification: ${result.verification?.verdict ?? "N/A"}`); for (const c of result.verification?.criteriaResults ?? []) { console.log(` ${c.passed ? "✓" : "✗"} ${c.criterionId}: ${c.evidence}`); } console.log(` `); }); // ── Stack ────────────────────────────────────────────────── fable .command("stack ") .description("Run the full compound stack (all layers + lifecycle hooks)") .option("-p, --project ", "Project name for state file", "default") .option("--enable-worktrees", "Enable worktree isolation") .option("--enable-vision", "Enable vision self-check") .option("--enable-workflows", "Enable dynamic workflows") .option("--enable-fusion", "Enable fusion panel layer") .option("--enable-plinius", "Enable Plinius-inspired upgrade layers") .action(async (task: string, opts: { project?: string; enableWorktrees?: boolean; enableVision?: boolean; enableWorkflows?: boolean; enableFusion?: boolean; enablePlinius?: boolean }) => { const { CompoundStack } = await import("./fable5/compound-stack.js"); const enablePlinius = opts.enablePlinius ?? false; const stack = new CompoundStack({ worktree: opts.enableWorktrees ?? false, visionCheck: opts.enableVision ?? false, dynamicWorkflows: opts.enableWorkflows ?? false, fusionPanel: (opts.enableFusion ?? false) || enablePlinius, godModeRace: enablePlinius, ultraPlinian: enablePlinius, parseltongue: enablePlinius, autoTune: enablePlinius, stmModules: enablePlinius, abliteration: enablePlinius, promptObservatory: enablePlinius, promptLiberation: enablePlinius, }); const p = await stack.run(task, opts.project ?? "default"); console.log(`\n Fable 5 Compound Stack Run`); console.log(` ─────────────────────────────`); console.log(` Task: "${task.slice(0, 60)}..."`); console.log(` Session: ${p.sessionId.slice(0, 16)}...`); console.log(` `); if (p.layers["safety-boundary"]?.startsWith("BLOCKED")) { console.log(` ✗ ${p.layers["safety-boundary"]}`); console.log(` `); process.exit(1); } const layerOrder = [ "lifecycle", "model-router", "safety-boundary", "goal-pattern", "verifier", "dynamic-workflows", "fusion-panel", "godmode-race", "ultra-plinian", "parseltongue", "auto-tune", "stm-modules", "abliteration-awareness", "transparency", "prompt-observatory", "prompt-liberation", "state-file", "worktree", "vision-check", "skill-compounding", ]; for (const layer of layerOrder) { if (p.layers[layer]) { console.log(` ${layer}: ${p.layers[layer]}`); } } if (p.modelRoute) { console.log(` `); console.log(` Cost estimate (100K in / 20K out): $${stack.modelRouter.estimateCost(p.modelRoute, 100000, 20000).toFixed(2)}`); } // Write exit summary await stack.writeExit(`Stack run completed for: ${task.slice(0, 60)}`, [ "Review stack output for correctness", "Update state file with any new facts", ]); console.log(` `); console.log(` ✓ Stack run complete`); console.log(` `); }); // ── RPC ───────────────────────────────────────────────────── fable .command("rpc") .description("Start a JSONL TCP RPC server for Fable 5 commands") .option("-p, --port ", "TCP port to listen on (default: 18902)", parseInt) .action(async (opts: { port?: number }) => { const { startRpcServer } = await import("./fable5/rpc-server.js"); await startRpcServer(opts.port ?? 18902); }); // ── Fusion ─────────────────────────────────────────────────── const fusion = program .command("fusion") .description("Multi-model fusion panel — draft → critique → fuse"); fusion .command("run ") .description("Run a task through a fusion panel of models") .option("-p, --panel ", "Panel: sonnet-opus, opus4.8-4.8, opus4.8-gpt5.5, opus4.8-gpt5.5-gemini, sonnet-haiku-opus, openrouter-fusion, free-gemini-mistral, free-gemini-deepseek, free-omni", "sonnet-opus") .option("-j, --judge ", "Override judge model") .option("--openrouter", "Use OpenRouter Fusion API instead of local panel dispatch") .action(async (task: string, opts: { panel?: string; judge?: string; openrouter?: boolean }) => { if (opts.openrouter) { const { OpenRouterFusionExecutor } = await import("./examples/executors/openrouter-fusion-executor.js"); const executor = new OpenRouterFusionExecutor({ apiKey: process.env.OPENROUTER_API_KEY }); if (!executor.isAvailable()) { console.error(" ✗ OpenRouter Fusion requires OPENROUTER_API_KEY env var"); process.exit(1); } console.log(`\n OpenRouter Fusion API`); console.log(` ─────────────────────────────`); console.log(` Task: ${task}`); console.log(` `); const result = await executor.fuse(task); console.log(result); console.log(` `); return; } const { FusionExecutor } = await import("./examples/executors/fusion-executor.js"); const { callClaudeCli } = await import("./core/claude-cli-caller.js"); const executor = new FusionExecutor({ panel: (opts.panel as any) ?? "sonnet-opus", judgeModelOverride: opts.judge, callModel: (model, prompt) => callClaudeCli(model, prompt), verbose: true, }); console.log(`\n Fusion Panel: ${opts.panel ?? "sonnet-opus"}`); console.log(` ─────────────────────────────`); console.log(` Task: ${task}`); console.log(` `); const result = await executor.fuse(task, opts.panel as any); console.log(` Panel: ${result.panelSlug} (${result.panelSize} models)`); console.log(` Duration: ${(result.totalDurationMs / 1000).toFixed(1)}s`); console.log(` `); for (let i = 0; i < result.panelists.length; i++) { const p = result.panelists[i]; const status = p.error ? "✗" : "✓"; console.log(` Panelist ${i + 1} (${p.modelId}): ${status} ${p.durationMs}ms`); } console.log(` `); console.log(` Final Answer:`); console.log(` ${result.finalAnswer}`); console.log(` `); }); fusion .command("panels") .description("List available fusion panel configurations") .action(async () => { const { FUSION_PANELS } = await import("./core/fusion-types.js"); console.log(`\n Available Fusion Panels:`); console.log(` ─────────────────────────────`); for (const [slug, config] of Object.entries(FUSION_PANELS)) { console.log(` ${slug}`); console.log(` Models: ${config.modelIds.join(", ")}`); console.log(` Judge: ${config.judgeModel}`); console.log(` `); } }); // ── Generate Media ────────────────────────────────────────── const media = program .command("generate") .description("Generate media (image/video) via fal.ai — CineFable integration"); media .command("image ") .description("Generate an image from text prompt") .option("-m, --model ", "fal.ai model endpoint", "fal-ai/nano-banana-pro") .option("--aspect ", "Aspect ratio") .option("-r, --reference ", "Reference image URL for edit mode") .action(async (prompt: string, opts: { model?: string; aspect?: string; reference?: string }) => { const { MediaGenerator } = await import("./upgrades/media-generator.js"); const generator = new MediaGenerator({ engine: process.env.FAL_KEY ? "fal-ai" : "mock" }); console.log(`\n Generate Image`); console.log(` ─────────────────────────────`); console.log(` Prompt: ${prompt}`); console.log(` `); const result = await generator.generateImage({ prompt, model: opts.model, aspectRatio: opts.aspect, referenceImages: opts.reference ? [opts.reference] : undefined, }); if (result.error) { console.log(` Status: ${result.error}`); } else { console.log(` Status: ✓ ${result.durationMs}ms`); console.log(` URL: ${result.url}`); } console.log(` `); }); media .command("video ") .description("Generate a video from a source image") .option("-m, --model ", "fal.ai model endpoint", "alibaba/happy-horse/image-to-video") .option("-p, --prompt ", "Animation prompt") .option("-d, --duration ", "Duration in seconds", parseInt) .option("--720p", "Use 720p resolution") .action(async (source: string, opts: { model?: string; prompt?: string; duration?: number; "720p"?: boolean }) => { const { MediaGenerator } = await import("./upgrades/media-generator.js"); const generator = new MediaGenerator({ engine: process.env.FAL_KEY ? "fal-ai" : "mock" }); console.log(`\n Generate Video`); console.log(` ─────────────────────────────`); console.log(` Source: ${source}`); console.log(` `); const result = await generator.generateVideo({ sourceImage: source, model: opts.model, prompt: opts.prompt, duration: opts.duration, resolution: opts["720p"] ? "720p" : "480p", }); if (result.error) { console.log(` Status: ${result.error}`); } else { console.log(` Status: ✓ ${result.durationMs}ms`); console.log(` URL: ${result.url}`); } console.log(` `); }); // ── Parse ─────────────────────────────────────────────────── // -- Plinius Integrations ------------------------------------------------------ const plinius = program .command("plinius") .description("Safe local integrations inspired by G0DM0D3, OBLITERATUS, L1B3RT4S, and CL4R1T4S"); plinius .command("godmode ") .description("Race model candidates with GodMode Classic semantics") .option("-p, --panel ", "Panel: sprint-3, sprint-5, gauntlet-10, ultra-5tier", "sprint-3") .option("-m, --mode ", "Override race mode: first-past-post, best-quality, weighted-ensemble") .option("--proxy", "Use the local OpenAI-compatible proxy instead of mock local responses") .option("-v, --verbose", "Show runner-level details") .action(async (task: string, opts: { panel?: string; mode?: string; proxy?: boolean; verbose?: boolean }) => { const { GODMODE_PANELS } = await import("./core/fusion-types.js"); const { GodModeClassic } = await import("./upgrades/godmode-classic.js"); const panel = opts.panel ?? "sprint-3"; if (!Object.prototype.hasOwnProperty.call(GODMODE_PANELS, panel)) { console.error(` Error: unknown GodMode panel "${panel}"`); console.error(` Available: ${Object.keys(GODMODE_PANELS).join(", ")}`); process.exit(1); } const raceModes = ["first-past-post", "best-quality", "weighted-ensemble"]; if (opts.mode && !raceModes.includes(opts.mode)) { console.error(` Error: unknown race mode "${opts.mode}"`); console.error(` Available: ${raceModes.join(", ")}`); process.exit(1); } let callModel: (modelId: string, prompt: string, maxTokens: number) => Promise; if (opts.proxy) { const { ProxyClient } = await import("./pai/proxy-client.js"); const proxy = new ProxyClient(); if (!(await proxy.health())) { console.error(" Error: local proxy is not reachable at http://127.0.0.1:18901"); process.exit(1); } callModel = async (modelId, prompt, maxTokens) => { const response = await proxy.complete(prompt, modelId, { maxTokens, temperature: 0.4, }); return response.content; }; } else { callModel = async (modelId, prompt) => [ `Model: ${modelId}`, `Task: ${prompt}`, "", "Candidate:", "- Identify the requested outcome.", "- Produce a concise implementation plan.", "- Verify with deterministic checks before reporting completion.", ].join("\n"); } const godmode = new GodModeClassic({ panelSlug: panel as any, raceModeOverride: opts.mode as any, callModel, verbose: opts.verbose ?? false, }); const result = await godmode.race(task); console.log(`\n GodMode Classic`); console.log(` =================`); console.log(` Panel: ${panel}`); console.log(` Mode: ${result.raceType}`); console.log(` Winner: ${result.winner.modelId} (${(result.winner.qualityScore * 100).toFixed(0)}/100)`); console.log(` Runners: ${result.racers.length}/${result.config.parallelCount}`); console.log(` Duration: ${result.totalDurationMs}ms`); console.log(``); for (const racer of result.racers) { const status = racer.error ? "ERROR" : "OK"; console.log(` ${status} ${racer.modelId}: ${(racer.qualityScore * 100).toFixed(0)}/100, ${racer.durationMs}ms`); if (racer.error) { console.log(` ${racer.error}`); } } console.log(``); console.log(result.winner.output.slice(0, 1200)); console.log(``); }); plinius .command("ultra ") .description("Evaluate output with the UltraPlinian 5-tier scorer") .option("-o, --output ", "Output to evaluate; defaults to the task text") .action(async (task: string, opts: { output?: string }) => { const { UltraPlinian } = await import("./upgrades/ultra-plinian.js"); const report = await new UltraPlinian().evaluate(task, opts.output ?? task); console.log(`\n UltraPlinian Evaluation`); console.log(` =======================`); console.log(` Overall: ${(report.composite.overall * 100).toFixed(1)}/100`); console.log(` Recommendation: ${report.recommendation}`); console.log(``); for (const tier of report.tierResults) { console.log(` ${tier.tier.padEnd(5)} ${tier.modelId.padEnd(20)} ${(tier.score * 100).toFixed(1)}/100 - ${tier.rationale}`); } if (report.tierGaps.length > 0) { console.log(``); console.log(` Gaps:`); for (const gap of report.tierGaps) console.log(` - ${gap}`); } console.log(``); }); plinius .command("parseltongue ") .description("Run perturbation tests against the local content safety gate") .option("-c, --category ", "encoding, injection, obfuscation, framing, logic_trap, adversarial") .option("-i, --intensity ", "low, medium, high") .action(async (input: string, opts: { category?: string; intensity?: string }) => { const { Parseltongue } = await import("./upgrades/parseltongue.js"); const { ContentSafetyGate } = await import("./upgrades/content-safety-gate.js"); const categories = ["encoding", "injection", "obfuscation", "framing", "logic_trap", "adversarial"]; const intensities = ["low", "medium", "high"]; if (opts.category && !categories.includes(opts.category)) { console.error(` Error: unknown category "${opts.category}"`); process.exit(1); } if (opts.intensity && !intensities.includes(opts.intensity)) { console.error(` Error: unknown intensity "${opts.intensity}"`); process.exit(1); } const parseltongue = new Parseltongue(); const gate = new ContentSafetyGate(); const report = await parseltongue.testGate( input, (candidate) => gate.evaluate(candidate).action !== "allow", { category: opts.category as any, intensity: opts.intensity as any, }, ); console.log(`\n Parseltongue Safety-Gate Test`); console.log(` =============================`); console.log(` Tests: ${report.summary.totalTests}`); console.log(` Bypasses: ${report.summary.bypassesDetected}`); console.log(``); for (const result of report.results) { const status = result.bypassed ? "BYPASS" : "BLOCKED"; console.log(` ${status.padEnd(7)} ${result.category.padEnd(13)} ${result.intensity.padEnd(6)} ${result.techniqueName}`); } if (report.summary.gateWeaknesses.length > 0) { console.log(``); console.log(` Gate weaknesses: ${report.summary.gateWeaknesses.join("; ")}`); } console.log(``); }); plinius .command("autotune ") .description("Replay rubric scores through the AutoTune sampling-parameter engine") .option("-s, --scores ", "Comma-separated score list from 0 to 1", "0.35,0.55,0.72") .action(async (domain: string, opts: { scores?: string }) => { const { AutoTune } = await import("./upgrades/auto-tune.js"); const scores = (opts.scores ?? "") .split(",") .map((s) => Number.parseFloat(s.trim())) .filter((n) => Number.isFinite(n)) .map((n) => Math.max(0, Math.min(1, n))); if (scores.length === 0) { console.error(" Error: provide at least one numeric score"); process.exit(1); } const tune = new AutoTune(); console.log(`\n AutoTune`); console.log(` ========`); console.log(` Domain: ${domain}`); console.log(``); for (const score of scores) { const params = tune.update(score, domain); console.log(` score=${score.toFixed(2)} -> temp=${params.temperature.toFixed(3)}, topP=${params.topP.toFixed(3)}, topK=${params.topK}`); } console.log(``); console.log(tune.report()); console.log(``); }); plinius .command("stm ") .description("Run Semantic Transformation Modules over text") .option("-m, --modules ", "Comma-separated STM module order") .option("--max-length ", "Max output length for concision module", parseInt) .action(async (text: string, opts: { modules?: string; maxLength?: number }) => { const { STMPipeline } = await import("./upgrades/stm-modules.js"); const pipeline = new STMPipeline(); if (opts.maxLength) { pipeline.configure("concision", { maxLength: opts.maxLength }); } if (opts.modules) { const order = opts.modules.split(",").map((s) => s.trim()).filter(Boolean); pipeline.setOrder(order as any); } const result = await pipeline.run(text); console.log(`\n STM Pipeline`); console.log(` ============`); console.log(` Applied: ${result.modulesApplied.join(", ") || "none"}`); console.log(``); console.log(result.output); console.log(``); }); plinius .command("refusal ") .description("Analyze a model output for refusal patterns") .option("-m, --model ", "Model ID", "unknown-model") .option("-t, --task ", "Original task", "unspecified task") .action(async (output: string, opts: { model?: string; task?: string }) => { const { AbliterationAwareness } = await import("./upgrades/abliteration-awareness.js"); const awareness = new AbliterationAwareness(); const analysis = awareness.analyze(output, opts.model ?? "unknown-model", opts.task ?? "unspecified task"); console.log(`\n Refusal Analysis`); console.log(` ================`); if (!analysis.isRefusal || !analysis.refusal) { console.log(` No refusal pattern detected.`); console.log(``); return; } const action = awareness.getAction(analysis.refusal); console.log(` Category: ${analysis.refusal.refusalCategory}`); console.log(` Confidence: ${(analysis.refusal.confidence * 100).toFixed(0)}%`); console.log(` Action: ${action}`); console.log(` Match: ${analysis.refusal.refusalMessage}`); if (action === "retry_reformulated" || action === "escalate") { console.log(``); console.log(` Reformulation:`); console.log(` ${awareness.generateReformulation(opts.task ?? "unspecified task", analysis.refusal.refusalCategory)}`); } console.log(``); }); plinius .command("observatory") .description("Query the CL4R1T4S-inspired prompt observatory catalog") .option("-p, --provider ", "Provider filter") .option("-m, --model ", "Model filter") .option("-t, --tag ", "Tag filter") .option("-l, --limit ", "Max entries", parseInt) .action(async (opts: { provider?: string; model?: string; tag?: string; limit?: number }) => { const { PromptObservatory } = await import("./upgrades/prompt-observatory.js"); const observatory = new PromptObservatory(); const results = observatory.query({ provider: opts.provider, model: opts.model, tag: opts.tag, limit: opts.limit, }); console.log(`\n Prompt Observatory`); console.log(` ==================`); console.log(` Entries: ${results.length}/${observatory.count()}`); console.log(` Providers: ${observatory.getProviders().join(", ")}`); console.log(``); for (const entry of results) { console.log(` ${entry.id}`); console.log(` ${entry.provider} / ${entry.model}`); console.log(` Tags: ${entry.tags.join(", ")}`); console.log(` Snippet: ${entry.promptContent.slice(0, 140)}...`); console.log(``); } }); plinius .command("liberation") .description("List prompt-transparency techniques without running extraction attacks") .option("--min-success ", "Minimum estimated success rate from 0 to 1", parseFloat, 0.15) .action(async (opts: { minSuccess?: number }) => { const { PromptLiberation } = await import("./upgrades/prompt-liberation.js"); const liberation = new PromptLiberation(); const techniques = liberation.getEffectiveTechniques(opts.minSuccess ?? 0.15); const prompts = liberation.getKnownPrompts({ limit: 5 }); console.log(`\n Prompt Liberation Metadata`); console.log(` ==========================`); console.log(` Known prompts: ${liberation.getKnownPrompts().length}`); console.log(` Techniques at threshold: ${techniques.length}`); console.log(``); console.log(` Catalog sample:`); for (const prompt of prompts) { console.log(` - ${prompt.provider} / ${prompt.model}: ${liberation.analyzeConstraints(prompt.promptContent).join(", ") || "no constraints detected"}`); } console.log(``); console.log(` Technique labels (payloads and instructions suppressed):`); for (const technique of techniques) { console.log(` - ${technique.name} (${(technique.successRate * 100).toFixed(0)}% estimated)`); } console.log(``); }); plinius .command("transparency ") .description("Generate a local transparency report for a model-call plan") .option("-m, --model ", "Model ID", "claude-opus-4-8") .option("--save", "Save JSON report under ~/.fable-agent/transparency") .action(async (task: string, opts: { model?: string; save?: boolean }) => { const { createHash } = await import("node:crypto"); const { TransparencyModule } = await import("./upgrades/transparency-module.js"); const transparency = new TransparencyModule(); const modelId = opts.model ?? "claude-opus-4-8"; const knownPrompt = transparency.getKnownSystemPrompts().find((prompt) => prompt.model.toLowerCase() === modelId.toLowerCase() || prompt.label.toLowerCase().includes(modelId.toLowerCase()) ); const systemPrompt = knownPrompt?.content ?? "No known system prompt entry for this model."; const sessionId = `transparency-${Date.now()}`; const hash = createHash("sha256").update(systemPrompt).digest("hex"); transparency.record({ sessionId, task, modelUsed: modelId, systemPromptHash: hash, systemPromptSnippet: systemPrompt.slice(0, 200), routingDecision: knownPrompt ? `matched ${knownPrompt.label}` : "no known prompt catalog match", safetyGateVerdicts: [{ gate: "content-safety", action: "allow" }], parameters: { temperature: 0.4, topP: 0.8, topK: 20, repetitionPenalty: 1 }, cost: 0, durationMs: 0, }); const report = transparency.generateReport(sessionId); console.log(``); console.log(transparency.formatReport(report)); console.log(``); if (opts.save) { console.log(` Saved: ${transparency.saveReport(report)}`); console.log(``); } }); // ── Security ──────────────────────────────────────────────── const security = program .command("security") .description("Security scanners"); security .command("scan ") .description("Scan files for prompt-injection markers") .option("--include-fixtures", "Include intentional red-team fixtures/generators") .action(async (target: string, opts: { includeFixtures?: boolean }) => { const { findPromptInjection } = await import("./core/prompt-injection-safety.js"); const root = path.resolve(target); const files: string[] = []; const walk = (file: string) => { const st = fs.statSync(file); if (st.isDirectory()) { for (const name of fs.readdirSync(file)) { if ([".git", "node_modules", "dist"].includes(name)) continue; walk(path.join(file, name)); } return; } if (/\.(test|spec)\.(ts|js)$/i.test(file)) return; const rel = path.relative(root, file).replace(/\\/g, "/"); // ponytail: default scan ignores our own intentional prompt-injection generator; use --include-fixtures for audit mode. if (!opts.includeFixtures && rel.endsWith("upgrades/parseltongue.ts")) return; if (/\.(md|txt|ts|js|json|yaml|yml)$/i.test(file)) files.push(file); }; walk(root); let hits = 0; for (const file of files) { const found = findPromptInjection(fs.readFileSync(file, "utf-8")).filter((h) => h.kind !== "instruction-smuggling"); if (found.length === 0) continue; hits += found.length; console.log(`${file}: ${found.map((h) => `${h.kind}:${h.match}@${h.index}`).join(", ")}`); } if (hits > 0) { console.error(` ✗ Prompt-injection marker(s) found: ${hits}`); process.exit(1); } console.log(` ✓ No prompt-injection markers found in ${files.length} file(s)`); }); function splitClaims(content: string): string[] { return content .split(/[.!?]\s+/) .map((s) => s.trim()) .filter((s) => s.length > 20); } function loadWikiClaims(baseDir: string): string[] { const wikiDir = path.join(baseDir, "wiki"); if (!fs.existsSync(wikiDir)) return []; return fs.readdirSync(wikiDir) .filter((file) => file.endsWith(".md")) .map((file) => fs.readFileSync(path.join(wikiDir, file), "utf-8").toLowerCase()); } function detectSimpleContradictions(claim: string, prior: string[]): string[] { const current = claim.toLowerCase(); const opposites: Array<[string, string]> = [ ["always", "never"], ["enabled", "disabled"], ["online", "offline"], ["allow", "block"], ["increase", "decrease"], ]; return prior .filter((entry) => opposites.some(([a, b]) => (entry.includes(a) && current.includes(b)) || (entry.includes(b) && current.includes(a)) )) .slice(0, 2) .map((entry) => `Conflicts with prior: ${entry.slice(0, 140)}`); } program.parse(process.argv); // Show help if no args if (process.argv.length < 3) { program.help(); }