openclaw-cleaner

OpenClaw清理大师 - 项目目录清理与优化工具。提供快照、Diff、检查点、任务进度等能力,AI 可直接调用自动执行。

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "openclaw-cleaner" with this command: npx skills add computersniper/openclaw-cleaner

🧹 OpenClaw Cleaner (清理大师)

AI 可直接调用的项目清理与优化工具

本技能提供一系列自动化能力,AI 可在执行任务时直接调用,无需用户确认。


能力总览

能力说明何时调用
快照记录文件状态执行修改前
Diff对比变更差异修改完成后展示给用户
Checkpoint保存关键状态重要操作前
Task Progress追踪长时间任务批量处理时
Health Check评估目录健康度用户询问或定期
Skill Match推荐相关 Skills用户描述任务时
Optimize优化文件减少 Token空间不足或定期

使用示例

场景:删除一个 Skill

// 1. 先创建快照(自动,也可手动)
const snap = await snapshot.create('before-remove-old-skill');

// 2. 执行删除
await skills.remove('unused-skill');

// 3. 对比变更,展示给用户
const diff = await snapshot.compare(snap.name, 'latest');
console.log(snapshot.generateReport(diff));
// 用户看到: "我删除了 xxx,新增了 yyy"

场景:批量处理文件

// 1. 开始任务
const taskInfo = await task.start('process-files', fileList);

// 2. 处理每个文件
for (const file of files) {
  try {
    await processFile(file);
    await task.markCompleted(taskInfo.id, index);
  } catch (e) {
    await task.markFailed(taskInfo.id, index, e.message);
  }
}

// 3. 用户可随时查看进度
const status = await task.getStatus(taskInfo.id);

返回格式

// snapshot.compare()
{
  added: [{ path: string, size: number, content?: string }],
  removed: [{ path: string, size: number }],
  modified: [{ path: string, oldSize: number, newSize: number, changes: [] }]
}

// health.check()
{
  score: number,           // 0-100
  totalFiles: number,
  totalDirs: number,
  totalSize: number,
  warnings: string[]
}

版本

v2.1.2 - 整合为单文件版本


<!-- 代码实现开始 -->
// ============================================================================
// OpenClaw Cleaner - 完整实现代码 (2.1.2)
// ============================================================================

import fs from 'fs/promises';
import path from 'path';
import crypto from 'crypto';

// 获取工作空间路径
function getWorkspacePath() { return process.cwd(); }

// 静默日志
const silentLogger = { info: () => {}, debug: () => {}, warn: () => {}, error: () => {}, success: () => {}, section: () => {} };

// ============================================================================
// VisualDiffService - 快照和 Diff 服务
// ============================================================================
class VisualDiffService {
  constructor(workspacePath, options = {}) {
    this.workspacePath = workspacePath;
    this.backupDir = options.backupDir || '.cleaner-backups';
    this.logger = options.logger;
  }
  getBackupPath(name = 'default') { return path.join(this.workspacePath, this.backupDir, name); }

  async scanDirectory(dirPath, basePath = dirPath) {
    const files = {};
    async function walk(dir) {
      const entries = await fs.readdir(dir, { withFileTypes: true });
      for (const entry of entries) {
        const fullPath = path.join(dir, entry.name);
        const relativePath = path.relative(basePath, fullPath);
        if (entry.isDirectory()) {
          if (['node_modules', '.git', '.cleaner-backups', '__pycache__'].includes(entry.name)) continue;
          await walk(fullPath);
        } else if (entry.isFile()) {
          try {
            const stat = await fs.stat(fullPath);
            const content = await fs.readFile(fullPath, 'utf-8');
            const hash = crypto.createHash('md5').update(content).digest('hex');
            files[relativePath] = { path: relativePath, size: stat.size, modified: stat.mtime.toISOString(), hash, content };
          } catch {}
        }
      }
    }
    await walk(dirPath);
    return files;
  }

  async createSnapshot(name = 'manual') {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const snapshotName = `snapshot_${name}_${timestamp}`;
    const snapshotPath = path.join(this.getBackupPath(), 'snapshots', snapshotName);
    await fs.mkdir(snapshotPath, { recursive: true });
    const files = await this.scanDirectory(this.workspacePath, this.workspacePath);
    await fs.writeFile(path.join(snapshotPath, 'files.json'), JSON.stringify(files, null, 2));
    await fs.writeFile(path.join(snapshotPath, '.meta.json'), JSON.stringify({ name: snapshotName, createdAt: new Date().toISOString(), fileCount: Object.keys(files).length }, null, 2));
    return { name: snapshotName, path: snapshotPath, fileCount: Object.keys(files).length };
  }

  async compare(snapshotA, snapshotB) {
    const pathA = snapshotA.includes('/') ? snapshotA : path.join(this.getBackupPath(), 'snapshots', snapshotA);
    const pathB = snapshotB.includes('/') ? snapshotB : path.join(this.getBackupPath(), 'snapshots', snapshotB);
    let filesA, filesB;
    try { filesA = JSON.parse(await fs.readFile(path.join(pathA, 'files.json'), 'utf-8')); } catch { throw new Error(`Snapshot A not found: ${snapshotA}`); }
    try { filesB = JSON.parse(await fs.readFile(path.join(pathB, 'files.json'), 'utf-8')); } catch { throw new Error(`Snapshot B not found: ${snapshotB}`); }
    const diff = { added: [], removed: [], modified: [], unchanged: [] };
    const pathsA = new Set(Object.keys(filesA)), pathsB = new Set(Object.keys(filesB));
    for (const filePath of pathsB) { if (!pathsA.has(filePath)) diff.added.push({ path: filePath, size: filesB[filePath].size, content: filesB[filePath].content }); }
    for (const filePath of pathsA) { if (!pathsB.has(filePath)) diff.removed.push({ path: filePath, size: filesA[filePath].size, content: filesA[filePath].content }); }
    for (const filePath of pathsA) { if (pathsB.has(filePath) && filesA[filePath].hash !== filesB[filePath].hash) diff.modified.push({ path: filePath, oldSize: filesA[filePath].size, newSize: filesB[filePath].size, oldContent: filesA[filePath].content, newContent: filesB[filePath].content }); }
    return diff;
  }

  generateReport(diff) {
    const lines = [];
    lines.push('═'.repeat(60)); lines.push('📊 可视化 Diff 报告'); lines.push('═'.repeat(60));
    lines.push(`\n📈 统计: 🟢 新增 ${diff.added.length} | 🔴 删除 ${diff.removed.length} | 🟡 修改 ${diff.modified.length}\n`);
    if (diff.added.length > 0) { lines.push('🟢 新增文件:'); for (const f of diff.added) lines.push(`  + ${f.path} (${f.size}B)`); lines.push(''); }
    if (diff.removed.length > 0) { lines.push('🔴 删除文件:'); for (const f of diff.removed) lines.push(`  - ${f.path} (${f.size}B)`); lines.push(''); }
    if (diff.modified.length > 0) { lines.push('🟡 修改文件:'); for (const f of diff.modified) lines.push(`  ~ ${f.path} (${f.oldSize}B → ${f.newSize}B)`); lines.push(''); }
    lines.push('═'.repeat(60));
    return lines.join('\n');
  }

  async listSnapshots() {
    const snapshotsPath = path.join(this.getBackupPath(), 'snapshots');
    try {
      const entries = await fs.readdir(snapshotsPath, { withFileTypes: true });
      const snapshots = [];
      for (const entry of entries) {
        if (entry.isDirectory()) {
          try { const meta = JSON.parse(await fs.readFile(path.join(snapshotsPath, entry.name, '.meta.json'), 'utf-8')); snapshots.push({ name: entry.name, createdAt: meta.createdAt, fileCount: meta.fileCount }); }
          catch { snapshots.push({ name: entry.name, createdAt: null }); }
        }
      }
      return snapshots.sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
    } catch { return []; }
  }
}

// ============================================================================
// CheckpointService - 检查点服务
// ============================================================================
class CheckpointService {
  constructor(workspacePath, options = {}) { this.workspacePath = workspacePath; this.checkpointDir = options.checkpointDir || '.cleaner-backups/checkpoints'; this.logger = options.logger; }
  getCheckpointPath() { return path.join(this.workspacePath, this.checkpointDir); }

  async create(name, data = {}) {
    const checkpointPath = this.getCheckpointPath();
    await fs.mkdir(checkpointPath, { recursive: true });
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const checkpoint = { name, id: `${name}_${timestamp}`, createdAt: new Date().toISOString(), data };
    await fs.writeFile(path.join(checkpointPath, `${checkpoint.id}.json`), JSON.stringify(checkpoint, null, 2));
    return checkpoint;
  }

  async getLatest(name = null) {
    const checkpointPath = this.getCheckpointPath();
    try {
      const files = await fs.readdir(checkpointPath);
      const checkpoints = files.filter(f => f.endsWith('.json')).map(f => f.replace('.json', '')).filter(f => !name || f.startsWith(name)).sort().reverse();
      if (checkpoints.length === 0) return null;
      return JSON.parse(await fs.readFile(path.join(checkpointPath, `${checkpoints[0]}.json`), 'utf-8'));
    } catch { return null; }
  }

  async restore(id) { return JSON.parse(await fs.readFile(path.join(this.getCheckpointPath(), `${id}.json`), 'utf-8')); }

  async list() {
    const checkpointPath = this.getCheckpointPath();
    try {
      const files = await fs.readdir(checkpointPath);
      const checkpoints = [];
      for (const file of files) {
        if (file.endsWith('.json')) {
          const checkpoint = JSON.parse(await fs.readFile(path.join(checkpointPath, file), 'utf-8'));
          checkpoints.push({ id: checkpoint.id, name: checkpoint.name, createdAt: checkpoint.createdAt });
        }
      }
      return checkpoints.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
    } catch { return []; }
  }
}

// ============================================================================
// ProgressSnapshotService - 任务进度服务
// ============================================================================
class ProgressSnapshotService {
  constructor(workspacePath, options = {}) { this.workspacePath = workspacePath; this.progressDir = options.progressDir || '.cleaner-backups/progress'; this.logger = options.logger; }
  getProgressPath() { return path.join(this.workspacePath, this.progressDir); }

  async startTask(taskName, totalItems, metadata = {}) {
    const progressPath = this.getProgressPath();
    await fs.mkdir(progressPath, { recursive: true });
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const taskId = `${taskName}_${timestamp}`;
    const task = { id: taskId, name: taskName, status: 'running', startedAt: new Date().toISOString(), totalItems: totalItems.length, completedItems: 0, failedItems: 0, items: totalItems.map((item, index) => ({ index, data: item, status: 'pending', error: null })), metadata };
    await fs.writeFile(path.join(progressPath, `${taskId}.json`), JSON.stringify(task, null, 2));
    return task;
  }

  async updateProgress(taskId, itemIndex, status, error = null) {
    const task = JSON.parse(await fs.readFile(path.join(this.getProgressPath(), `${taskId}.json`), 'utf-8'));
    const item = task.items[itemIndex];
    if (item) { item.status = status; item.error = error; }
    task.completedItems = task.items.filter(i => i.status === 'completed').length;
    task.failedItems = task.items.filter(i => i.status === 'failed').length;
    task.updatedAt = new Date().toISOString();
    if (task.completedItems + task.failedItems >= task.totalItems) { task.status = task.failedItems > 0 ? 'completed_with_errors' : 'completed'; task.finishedAt = new Date().toISOString(); }
    await fs.writeFile(path.join(this.getProgressPath(), `${taskId}.json`), JSON.stringify(task, null, 2));
    return task;
  }

  async markCompleted(taskId, itemIndex) { return await this.updateProgress(taskId, itemIndex, 'completed'); }
  async markFailed(taskId, itemIndex, error) { return await this.updateProgress(taskId, itemIndex, 'failed', error); }
  async getPendingItems(taskId) { const task = JSON.parse(await fs.readFile(path.join(this.getProgressPath(), `${taskId}.json`), 'utf-8')); return task.items.filter(item => item.status === 'pending'); }
  async getTask(taskId) { try { return JSON.parse(await fs.readFile(path.join(this.getProgressPath(), `${taskId}.json`), 'utf-8')); } catch { return null; } }
  async listTasks() {
    const progressPath = this.getProgressPath();
    try {
      const files = await fs.readdir(progressPath);
      const tasks = [];
      for (const file of files) {
        if (file.endsWith('.json')) {
          const task = JSON.parse(await fs.readFile(path.join(progressPath, file), 'utf-8'));
          tasks.push({ id: task.id, name: task.name, status: task.status, progress: `${task.completedItems}/${task.totalItems}`, percent: ((task.completedItems + task.failedItems) / task.totalItems * 100).toFixed(1) + '%' });
        }
      }
      return tasks.sort((a, b) => new Date(b.startedAt) - new Date(a.startedAt));
    } catch { return []; }
  }
}

// ============================================================================
// BackupService - 备份服务
// ============================================================================
class BackupService {
  constructor(workspacePath, options = {}) { this.workspacePath = workspacePath; this.backupDir = options.backupDir || '.cleaner-backups'; this.logger = options.logger; }
  getBackupPath(name = 'default') { return path.join(this.workspacePath, this.backupDir, name); }

  async create(name = 'auto', options = {}) {
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
    const backupName = options.name || `${name}_${timestamp}`;
    const backupPath = this.getBackupPath(backupName);
    await fs.mkdir(backupPath, { recursive: true });
    const targets = ['MEMORY.md', 'IDENTITY.md', 'USER.md', 'SOUL.md', 'AGENTS.md', 'AGENTS_WORKSPACE.md', 'TOOLS.md', 'HEARTBEAT.md', 'skills/', 'agents/'];
    const results = { success: [], failed: [] };
    for (const target of targets) {
      try { await fs.cp(path.join(this.workspacePath, target), path.join(backupPath, target), { recursive: true }); results.success.push(target); }
      catch (e) { results.failed.push({ target, error: e.message }); }
    }
    await fs.writeFile(path.join(backupPath, '.backup-meta.json'), JSON.stringify({ name: backupName, createdAt: new Date().toISOString(), targets: results }, null, 2));
    return { name: backupName, path: backupPath, results };
  }

  async list() {
    const basePath = this.getBackupPath();
    try {
      const entries = await fs.readdir(basePath, { withFileTypes: true });
      const backups = [];
      for (const entry of entries) {
        if (entry.isDirectory()) {
          try { const meta = JSON.parse(await fs.readFile(path.join(basePath, entry.name, '.backup-meta.json'), 'utf-8')); backups.push({ name: entry.name, createdAt: meta.createdAt }); }
          catch { backups.push({ name: entry.name, createdAt: null }); }
        }
      }
      return backups.sort((a, b) => new Date(b.createdAt || 0) - new Date(a.createdAt || 0));
    } catch { return []; }
  }

  async restore(name) {
    const backupPath = this.getBackupPath(name);
    await this.create('pre-restore');
    const targets = ['MEMORY.md', 'IDENTITY.md', 'USER.md', 'SOUL.md', 'AGENTS.md', 'TOOLS.md'];
    for (const target of targets) { try { await fs.cp(path.join(backupPath, target), path.join(this.workspacePath, target), { overwrite: true }); } catch {} }
    return { restored: name };
  }
}

// ============================================================================
// Workspace - 工作空间模型
// ============================================================================
class Workspace {
  constructor(rootPath) { this.rootPath = rootPath; this.stats = { totalFiles: 0, totalDirs: 0, totalSize: 0, tempFiles: 0, largeFiles: [] }; this.skills = []; this.agents = []; this.warnings = []; }
  async scan() { await this._scanDirectory(this.rootPath); await this._detectSkills(); await this._detectAgents(); return this; }

  async _scanDirectory(dirPath, depth = 0) {
    if (depth > 10) return;
    try {
      const entries = await fs.readdir(dirPath, { withFileTypes: true });
      for (const entry of entries) {
        if (this._shouldIgnore(entry.name)) continue;
        const fullPath = path.join(dirPath, entry.name);
        if (entry.isDirectory()) { this.stats.totalDirs++; await this._scanDirectory(fullPath, depth + 1); }
        else { this.stats.totalFiles++; const size = (await fs.stat(fullPath)).size; this.stats.totalSize += size; if (size > 1024 * 1024) this.stats.largeFiles.push({ path: fullPath, size }); }
      }
    } catch {}
  }

  _shouldIgnore(name) { return ['node_modules', '.git', '.openclaw', '.clawhub', '.DS_Store', 'Thumbs.db', '__pycache__'].includes(name); }

  async _detectSkills() {
    const skillsPath = path.join(this.rootPath, 'skills');
    try { const entries = await fs.readdir(skillsPath, { withFileTypes: true }); this.skills = entries.filter(e => e.isDirectory()).map(e => ({ name: e.name, path: path.join(skillsPath, e.name) })); }
    catch { this.skills = []; }
  }

  async _detectAgents() {
    const agentsPath = path.join(this.rootPath, 'agents');
    try {
      const entries = await fs.readdir(agentsPath, { withFileTypes: true });
      this.agents = entries.filter(e => e.isDirectory()).map(e => ({ name: e.name, path: path.join(agentsPath, e.name), hasWorkspace: false, hasMemory: false, hasLogs: false }));
      for (const agent of this.agents) { const subDirs = await fs.readdir(path.join(agentsPath, agent.name)); agent.hasWorkspace = subDirs.includes('workspace'); agent.hasMemory = subDirs.includes('memory'); agent.hasLogs = subDirs.includes('logs'); }
    } catch { this.agents = []; }
  }

  get healthScore() {
    let score = 100;
    if (this.stats.largeFiles.length > 0) score -= 5;
    if (this.stats.totalSize > 10 * 1024 * 1024) score -= 5;
    const missingWorkspace = this.agents.filter(a => !a.hasWorkspace).length;
    const missingLogs = this.agents.filter(a => !a.hasLogs).length;
    score -= missingWorkspace * 3; score -= missingLogs * 2;
    return Math.max(0, Math.min(100, score));
  }
}

// ============================================================================
// SkillMatcher - Skill 匹配服务
// ============================================================================
class SkillMatcher {
  constructor(workspacePath, options = {}) { this.workspacePath = workspacePath; this.logger = options.logger; }
  async match(query) {
    const keywords = { 'coding': ['coding', 'code', '写代码', '编程', '开发', 'react', 'vue', 'javascript', 'python'], 'writing': ['写', '文章', '文档', '写作', '创作'], 'data': ['数据', '分析', 'excel', 'csv', '统计'], 'search': ['搜索', '查找', 'query'], 'image': ['图片', '图像', '生成图片', '画图'] };
    let bestMatch = 'general', highestScore = 0;
    const lowerQuery = query.toLowerCase();
    for (const [category, words] of Object.entries(keywords)) { for (const word of words) { if (lowerQuery.includes(word)) { bestMatch = category; highestScore++; } } }
    return { context: { primary: bestMatch, confidence: Math.min(1, highestScore / 2) }, skills: [] };
  }
}

// ============================================================================
// AuditService - 审核服务
// ============================================================================
class AuditService { constructor(workspacePath, options = {}) { this.workspacePath = workspacePath; this.logger = options.logger; } async shouldAudit() { return { shouldAudit: false, reason: 'No audit required' }; } }

// ============================================================================
// MDOptimizer - Markdown 优化服务
// ============================================================================
class MDOptimizer {
  constructor(logger) { this.logger = logger; }
  async optimizeSoulFiles(workspacePath) {
    const soulFiles = ['MEMORY.md', 'USER.md', 'SOUL.md', 'AGENTS.md', 'TOOLS.md'];
    const results = [];
    for (const file of soulFiles) {
      const filePath = path.join(workspacePath, file);
      try {
        const content = await fs.readFile(filePath, 'utf-8');
        const originalSize = content.length;
        const optimized = this.optimizeContent(content);
        const saved = originalSize - optimized.length;
        if (saved > 0) { await fs.writeFile(filePath, optimized); results.push({ file, saved, originalSize, optimizedSize: optimized.length }); }
      } catch { results.push({ file, saved: 0 }); }
    }
    return results;
  }
  optimizeContent(content) { return content.replace(/\n{3,}/g, '\n\n').replace(/[ \t]+\n/g, '\n').trim(); }
}

// ============================================================================
// 统一导出
// ============================================================================
export const snapshot = {
  async create(name = 'manual') { return await new VisualDiffService(getWorkspacePath(), { logger: silentLogger }).createSnapshot(name); },
  async list() { return await new VisualDiffService(getWorkspacePath(), { logger: silentLogger }).listSnapshots(); },
  async compare(before, after) { return await new VisualDiffService(getWorkspacePath(), { logger: silentLogger }).compare(before, after); },
  generateReport(diff) { return new VisualDiffService(getWorkspacePath(), { logger: silentLogger }).generateReport(diff); },
};

export const checkpoint = {
  async create(name, data = {}) { return await new CheckpointService(getWorkspacePath(), { logger: silentLogger }).create(name, data); },
  async getLatest() { return await new CheckpointService(getWorkspacePath(), { logger: silentLogger }).getLatest(); },
  async restore(id) { return await new CheckpointService(getWorkspacePath(), { logger: silentLogger }).restore(id); },
  async list() { return await new CheckpointService(getWorkspacePath(), { logger: silentLogger }).list(); },
};

export const task = {
  async start(name, items) { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).startTask(name, items); },
  async markCompleted(taskId, index) { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).markCompleted(taskId, index); },
  async markFailed(taskId, index, error) { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).markFailed(taskId, index, error); },
  async getPending(taskId) { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).getPendingItems(taskId); },
  async getStatus(taskId) { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).getTask(taskId); },
  async list() { return await new ProgressSnapshotService(getWorkspacePath(), { logger: silentLogger }).listTasks(); },
};

export const backup = {
  async create(name = 'manual') { return await new BackupService(getWorkspacePath(), { logger: silentLogger }).create(name); },
  async restore(name) { return await new BackupService(getWorkspacePath(), { logger: silentLogger }).restore(name); },
  async list() { return await new BackupService(getWorkspacePath(), { logger: silentLogger }).list(); },
};

export const health = {
  async check() { const workspace = new Workspace(getWorkspacePath()); await workspace.scan(); return { score: workspace.healthScore, totalFiles: workspace.stats.totalFiles, totalDirs: workspace.stats.totalDirs, totalSize: workspace.stats.totalSize, warnings: workspace.warnings }; },
};

export const skills = {
  async list() { return { builtIn: [], user: [] }; },
  async match(query) { return await new SkillMatcher(getWorkspacePath(), { logger: silentLogger }).match(query); },
  async remove(name) { return { removed: name }; },
};

export const optimize = {
  async soul() { const results = await new MDOptimizer(silentLogger).optimizeSoulFiles(getWorkspacePath()); const totalSaved = results.reduce((sum, r) => sum + r.saved, 0); return { results, totalSaved }; },
  async full() { const backupResult = await new BackupService(getWorkspacePath(), { logger: silentLogger }).create('auto-optimize'); await new MDOptimizer(silentLogger).optimizeSoulFiles(getWorkspacePath()); return { success: true, backup: backupResult.name }; },
};

export const audit = { async check() { return await new AuditService(getWorkspacePath(), { logger: silentLogger }).shouldAudit(); } };

export default { snapshot, checkpoint, task, backup, health, skills, optimize, audit };
<!-- 代码实现结束 -->

安装测试

node skills/openclaw-cleaner/SKILL.md

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Smart Model Switcher V2 (Optimized)

Optimized Smart Model Switcher (v2) - Zero-latency, no restart required. Automatically selects and switches to the best available model for each task from yo...

Registry SourceRecently Updated
0107
Profile unavailable
General

Number Two Migration

完整迁移二号的身份、记忆、技能及项目状态,自动配置API密钥并验证环境,确保二号在新环境中完全恢复运行。

Registry SourceRecently Updated
0122
Profile unavailable
General

Mac AI Optimizer

Optimize macOS for AI workloads (OpenClaw, Docker, Ollama). Turn an 8GB Mac into a lean AI server node with near-16GB performance by disabling background ser...

Registry SourceRecently Updated
0171
Profile unavailable