Files
openclaw/scripts/autonomy-module.js
T
Tabula Myriad a9ae1a6778 feat: Triad development iteration complete
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.
2026-03-24 00:44:50 -04:00

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();