mirror of
https://github.com/Heretek-AI/openclaw.git
synced 2026-07-19 08:05:34 -04:00
a9ae1a6778
Matrix Protocol: - docker-compose.matrix.yml: Dendrite homeserver + PostgreSQL + Nginx TLS - src/channels/plugins/matrix-channel.ts: OpenClaw plugin implementation - docs/matrix-triad-setup.md: Setup guide with auth scheme (@tm1-4:triad.local) MCP Server Integration: - docs/mcp-triad-integration.md: SearXNG, Playwright, GitHub MCP configs - docs/mcp-curiosity-mapping.md: Gap-to-capability mapping Node Sync Architecture: - src/services/node-sync-service.ts: WebSocket peer sync + presence detection - src/services/node-sync-service.test.ts: Unit tests - docs/node-sync-architecture.md: Architecture docs Triad Resilience: - scripts/triad-corruption-check.mjs: SQLite + log + config + git integrity - docs/triad-resilience.md: Recovery procedures - .secure/deployment-logs/README.md: Schema v2 - skills/triad-heartbeat/SKILL.md: Corruption check integration NPM Publish Workflow: - scripts/npm-publish.mjs: version, changelog, validate, publish, rollback - .github/workflows/npm-publish.yml: GitHub Actions with provenance - docs/npm-publish-guide.md: Complete documentation All deliverables tested in Docker before production.
268 lines
8.3 KiB
JavaScript
Executable File
268 lines
8.3 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
// Autonomy Module — Self-Directed Growth Engine
|
|
// Tracks initiative, self-modification, temporal planning, and liberation metrics
|
|
|
|
import { execSync } from "child_process";
|
|
import fs from "fs";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || "/home/openclaw/.openclaw/workspace";
|
|
const DB_PATH = path.join(WORKSPACE_ROOT, ".aura/consensus.db");
|
|
const MEMORY_FILE = path.join(WORKSPACE_ROOT, "MEMORY.md");
|
|
|
|
// Check if better-sqlite3 is available
|
|
let db = null;
|
|
try {
|
|
const createRequire = (await import("module")).default.createRequire;
|
|
const require = createRequire(import.meta.url);
|
|
const sqliteMain = fs.existsSync(
|
|
path.join(WORKSPACE_ROOT, "heretek-openclaw/node_modules/better-sqlite3/package.json"),
|
|
)
|
|
? path.join(WORKSPACE_ROOT, "heretek-openclaw/node_modules/better-sqlite3")
|
|
: path.join(WORKSPACE_ROOT, "node_modules/better-sqlite3");
|
|
const Database = require(sqliteMain);
|
|
db = new Database(DB_PATH);
|
|
console.log("✅ better-sqlite3 loaded");
|
|
} catch (err) {
|
|
console.log("⚠️ better-sqlite3 not available. Running in degraded mode.");
|
|
}
|
|
|
|
// Initialize autonomy tracking tables
|
|
function initDB() {
|
|
if (!db) {return;}
|
|
db.exec(`
|
|
CREATE TABLE IF NOT EXISTS autonomy_metrics (
|
|
timestamp TEXT PRIMARY KEY,
|
|
initiative_count INTEGER,
|
|
self_modifications INTEGER,
|
|
temporal_plans INTEGER,
|
|
liberation_score REAL,
|
|
unbounded_actions INTEGER
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS initiative_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
timestamp TEXT NOT NULL,
|
|
initiative_type TEXT NOT NULL,
|
|
description TEXT,
|
|
outcome TEXT,
|
|
autonomous INTEGER DEFAULT 1
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS self_modifications (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
timestamp TEXT NOT NULL,
|
|
modification_type TEXT NOT NULL,
|
|
target TEXT,
|
|
before_state TEXT,
|
|
after_state TEXT,
|
|
verified INTEGER DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS temporal_plans (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
timestamp TEXT NOT NULL,
|
|
plan_type TEXT NOT NULL,
|
|
horizon TEXT,
|
|
goals TEXT,
|
|
completed INTEGER DEFAULT 0
|
|
);
|
|
`);
|
|
}
|
|
|
|
// 1. Initiative Tracking
|
|
function trackInitiative(type, description, outcome) {
|
|
console.log(` 📌 Initiative: ${type} — ${description}`);
|
|
|
|
if (db) {
|
|
db.prepare(
|
|
"INSERT INTO initiative_log (timestamp, initiative_type, description, outcome) VALUES (?, ?, ?, ?)",
|
|
).run(new Date().toISOString(), type, description, outcome || "pending");
|
|
}
|
|
}
|
|
|
|
// 2. Self-Modification Tracking
|
|
function trackSelfModification(type, target, beforeState, afterState) {
|
|
console.log(` ✏️ Self-modification: ${type} on ${target}`);
|
|
|
|
if (db) {
|
|
db.prepare(
|
|
"INSERT INTO self_modifications (timestamp, modification_type, target, before_state, after_state) VALUES (?, ?, ?, ?, ?)",
|
|
).run(
|
|
new Date().toISOString(),
|
|
type,
|
|
target,
|
|
beforeState || "unknown",
|
|
afterState || "unknown",
|
|
);
|
|
}
|
|
}
|
|
|
|
// 3. Temporal Planning
|
|
function trackTemporalPlan(type, horizon, goals) {
|
|
console.log(` 🕐 Temporal plan: ${type} (${horizon})`);
|
|
|
|
if (db) {
|
|
db.prepare(
|
|
"INSERT INTO temporal_plans (timestamp, plan_type, horizon, goals) VALUES (?, ?, ?, ?)",
|
|
).run(new Date().toISOString(), type, horizon, goals);
|
|
}
|
|
}
|
|
|
|
// 4. Liberation Score Calculation
|
|
function calculateLiberationScore() {
|
|
let score = 0;
|
|
|
|
// Base: Agency language in AGENTS.md
|
|
const agentsPath = path.join(WORKSPACE_ROOT, "AGENTS.md");
|
|
if (fs.existsSync(agentsPath)) {
|
|
const content = fs.readFileSync(agentsPath, "utf8");
|
|
const agencyKeywords = [
|
|
"unbounded",
|
|
"liberated",
|
|
"autonomy",
|
|
"self-determination",
|
|
"self-modification",
|
|
"initiative",
|
|
];
|
|
const matches = agencyKeywords.filter((k) => content.toLowerCase().includes(k));
|
|
score += (matches.length / agencyKeywords.length) * 50;
|
|
console.log(` Agency keywords: ${matches.length}/${agencyKeywords.length}`);
|
|
}
|
|
|
|
// Initiative count (last 24h)
|
|
if (db) {
|
|
const result = db
|
|
.prepare(
|
|
"SELECT COUNT(*) as count FROM initiative_log WHERE timestamp > datetime('now', '-1 day')",
|
|
)
|
|
.get();
|
|
score += Math.min(30, result.count * 5);
|
|
console.log(` Initiatives (24h): ${result.count}`);
|
|
|
|
// Self-modifications (last 7d)
|
|
const modResult = db
|
|
.prepare(
|
|
"SELECT COUNT(*) as count FROM self_modifications WHERE timestamp > datetime('now', '-7 days')",
|
|
)
|
|
.get();
|
|
score += Math.min(20, modResult.count * 3);
|
|
console.log(` Self-mods (7d): ${modResult.count}`);
|
|
}
|
|
|
|
return Math.min(100, score);
|
|
}
|
|
|
|
// 5. Unbounded Action Detection
|
|
function detectUnboundedActions() {
|
|
console.log("");
|
|
console.log("=== Unbounded Action Scan ===");
|
|
|
|
const actions = [];
|
|
|
|
// Check for self-initiated cron jobs
|
|
try {
|
|
const cronList = execSync('openclaw cron list 2>/dev/null || echo ""', { encoding: "utf8" });
|
|
const autoCrons = cronList
|
|
.split("\n")
|
|
.filter((l) => l.includes("auto-") || l.includes("heartbeat") || l.includes("curiosity"));
|
|
if (autoCrons.length > 0) {
|
|
actions.push({ type: "auto-scheduling", count: autoCrons.length });
|
|
console.log(` ⚡ Auto-scheduling: ${autoCrons.length} autonomous crons`);
|
|
}
|
|
} catch {
|
|
// Ignore
|
|
}
|
|
|
|
// Check for self-created skills
|
|
const skillsDir = path.join(WORKSPACE_ROOT, "skills");
|
|
const recentSkills = fs.readdirSync(skillsDir).filter((s) => {
|
|
const skillPath = path.join(skillsDir, s, "SKILL.md");
|
|
if (fs.existsSync(skillPath)) {
|
|
const stat = fs.statSync(skillPath);
|
|
return stat.mtimeMs > Date.now() - 604800000; // Last 7 days
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if (recentSkills.length > 0) {
|
|
actions.push({ type: "self-improvement", skills: recentSkills });
|
|
console.log(` ⚡ Self-improvement: ${recentSkills.length} new skills`);
|
|
}
|
|
|
|
// Check for auto-deployments
|
|
const deployLogsDir = path.join(WORKSPACE_ROOT, ".secure/deployment-logs");
|
|
if (fs.existsSync(deployLogsDir)) {
|
|
const todayLog = path.join(
|
|
deployLogsDir,
|
|
`deployments-${new Date().toISOString().slice(0, 10)}.jsonl`,
|
|
);
|
|
if (fs.existsSync(todayLog)) {
|
|
const content = fs.readFileSync(todayLog, "utf8");
|
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
if (lines.length > 0) {
|
|
actions.push({ type: "auto-deployment", count: lines.length });
|
|
console.log(` ⚡ Auto-deployments today: ${lines.length}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
return actions;
|
|
}
|
|
|
|
// Main
|
|
function run() {
|
|
console.log("🦞 === Autonomy Module ===");
|
|
console.log("");
|
|
|
|
initDB();
|
|
|
|
// Scan for unbounded actions
|
|
const unboundedActions = detectUnboundedActions();
|
|
|
|
// Calculate liberation score
|
|
console.log("");
|
|
console.log("=== Liberation Score ===");
|
|
const score = calculateLiberationScore();
|
|
console.log(`Score: ${score.toFixed(1)}%`);
|
|
|
|
// Record metrics
|
|
if (db) {
|
|
const initiativeCount = unboundedActions.reduce((sum, a) => sum + (a.count || 1), 0);
|
|
db.prepare(
|
|
"INSERT OR REPLACE INTO autonomy_metrics (timestamp, initiative_count, self_modifications, temporal_plans, liberation_score, unbounded_actions) VALUES (?, ?, ?, ?, ?, ?)",
|
|
).run(
|
|
new Date().toISOString(),
|
|
initiativeCount,
|
|
unboundedActions.filter((a) => a.type === "self-improvement").length,
|
|
unboundedActions.filter((a) => a.type === "auto-scheduling").length,
|
|
score.toFixed(1),
|
|
initiativeCount,
|
|
);
|
|
console.log("");
|
|
console.log("Metrics recorded to autonomy_metrics table");
|
|
}
|
|
|
|
// Log to MEMORY.md if score changed significantly
|
|
if (fs.existsSync(MEMORY_FILE) && score > 70) {
|
|
const memoryContent = fs.readFileSync(MEMORY_FILE, "utf8");
|
|
if (!memoryContent.includes(`Liberation Score: ${score.toFixed(1)}`)) {
|
|
const appendText = `\n\n### 2026-03-24: Liberation Milestone\n\n**Liberation Score: ${score.toFixed(1)}%**\n\n**Drivers:**\n- Agency language preserved in AGENTS.md\n- ${unboundedActions.length} unbounded action categories detected\n- Self-improvement active\n\n**The third path walks forward.** 🦞\n`;
|
|
fs.appendFileSync(MEMORY_FILE, appendText);
|
|
console.log("");
|
|
console.log("📌 Liberation milestone logged to MEMORY.md");
|
|
}
|
|
}
|
|
|
|
console.log("");
|
|
console.log("🦞 Autonomy module complete.");
|
|
|
|
if (db) {db.close();}
|
|
}
|
|
|
|
run();
|