Skill: cjboy007/auto-revolution (version 2.0.2)

--- name: auto-revolution description: Safe publishing variant of Auto Revolution. Provides structured task templates, review prompts, safety scanning, task state updates, and logging for human supervised multi step workflows. Use when creating or reviewing task JSON files, applying review results, scanning instruction text for risky shell patterns, or managing queued task activation. This package avoids autonomous background execution and does not run arbitrary shell instruction strings. --- # Auto Revolution This is the ClawHub publishing variant. ## Use this skill for - creating structured task JSON files - activating queued tasks whose dependencies are complete - scanning proposed instruction text for risky shell patterns - applying review JSON back into a task file - logging workflow events in JSONL - generating a review prompt for manual or supervised review ## Do not use this package for - autonomous cron loops - unsupervised background execution - direct execution of arbitrary shell instruction strings - remote agent spawning from bundled scripts ## Files to use - `task-schema.json` for task structure reference - `config/models.json` for example role configuration - `scripts/create-task.js` to create a task interactively - `scripts/activate-queued-tasks.js` to move ready tasks from `queued` to `pending` - `scripts/security-scan.js` to scan instruction text or a task review block - `scripts/trigger-review.js` to generate a review prompt for supervised review - `scripts/apply-review.js` to write a review result back into a task JSON file - `scripts/log-event.js` to append JSONL audit events - `scripts/atomic-lock.sh`, `scripts/force-unlock.sh`, `scripts/unblock-task.sh` for task lock maintenance ## Minimal workflow 1. Create or edit a task JSON. 2. If the task depends on other tasks, run `scripts/activate-queued-tasks.js` when dependencies may be complete. 3. Generate a review prompt with `scripts/trigger-review.js`. 4. Obtain a supervised review result as JSON. 5. Apply that result with `scripts/apply-review.js`. 6. If you need to inspect instruction text, run `scripts/security-scan.js` before any manual execution. ## Safety rules - Keep a human in the loop for any real execution. - Treat generated instructions as untrusted until reviewed. - Prefer structured task updates over free form shell execution. - Do not add scripts that call `execSync` on model generated instruction strings in the publishing package. ## Notes This package is intentionally minimal for publication. Internal development documents, autonomous heartbeat runners, and direct execution engines belong in the private local version, not the published package.

path: README.md
content: # Auto Revolution

Safe publishing variant for ClawHub.

## What this package includes

- structured task creation
- dependency activation for queued tasks
- instruction safety scanning
- review prompt generation
- review result application
- JSONL event logging
- task lock maintenance helpers

## What this package excludes

- autonomous cron heartbeats
- direct execution of arbitrary shell instruction strings
- bundled remote review runners
- internal design and experiment documents

## Included scripts

- `node scripts/create-task.js`
- `node scripts/activate-queued-tasks.js`
- `node scripts/security-scan.js <task-file.json>`
- `node scripts/trigger-review.js <task-id>`
- `node scripts/apply-review.js <task-id> --file <review.json>`
- `node scripts/log-event.js <event> [key=value...]`

## Safety position

This publishing variant is for supervised workflows. Generated instructions should be reviewed before any real execution. The package does not include autonomous executors.


path: config/models.json
content: {
  "roles": {
    "reviewer": {
      "primary": "default-model/gemini-pro",
      "fallback": "advanced-model/gemini-pro",
      "description": "优先使用 Google 官方 Gemini，认证失败则 fallback 到 Aiberm"
    },
    "executor": "advanced-model/gpt",
    "auditor": {
      "primary": "default-model/gemini-pro",
      "fallback": "advanced-model/gemini-pro",
      "description": "优先使用 Google 官方 Gemini，认证失败则 fallback 到 Aiberm"
    },
    "coordinator": "default-model/qwen-plus"
  },
  "timeouts": {
    "reviewer": 300,
    "executor": 300,
    "auditor": 180,
    "description": "超时时间（秒）：Reviewer/Auditor 5 分钟，Executor 5 分钟"
  },
  "enforceAudit": true,
  "executorDefault": "advanced-model/gpt",
  "description": "Executor 统一使用 GPT-5.4（代码能力强），除非用户特殊要求",
  "lastUpdated": "2026-03-29T12:53:00+08:00"
}


path: scripts/README.md
content: # Auto Revolution Scripts

This publishing bundle keeps only supervised workflow helpers.

## Included

- `create-task.js`
- `activate-queued-tasks.js`
- `security-scan.js`
- `trigger-review.js`
- `apply-review.js`
- `log-event.js`
- `atomic-lock.sh`
- `force-unlock.sh`
- `unblock-task.sh`

## Excluded from publish bundle

- autonomous heartbeat coordinators
- direct execution engines
- remote review runner scripts
- internal test and experiment scripts

## Guidance

Use these scripts to manage task state and review data. Keep any real execution under explicit human supervision outside this publishing package.


path: scripts/activate-queued-tasks.js
content: #!/usr/bin/env node
/**
 * activate-queued-tasks.js - 依赖激活器
 * 检查所有 queued 状态的任务，激活依赖已完成的任务
 * 
 * 用法：node activate-queued-tasks.js
 */

const fs = require('fs');
const path = require('path');

const TASKS_DIR = path.join(__dirname, '..', 'tasks');
const LOGS_DIR = path.join(__dirname, '..', 'logs');
const EVENTS_LOG = path.join(LOGS_DIR, 'events.log');

// 确保日志目录存在
if (!fs.existsSync(LOGS_DIR)) {
  fs.mkdirSync(LOGS_DIR, { recursive: true });
}

/**
 * 写入事件日志
 */
function logEvent(event, data = {}) {
  const entry = {
    timestamp: new Date().toISOString(),
    event,
    ...data
  };
  fs.appendFileSync(EVENTS_LOG, JSON.stringify(entry) + '\n');
  return entry;
}

/**
 * 读取任务文件
 */
function readTask(taskId) {
  const taskFile = path.join(TASKS_DIR, `${taskId}.json`);
  if (!fs.existsSync(taskFile)) {
    return null;
  }
  return JSON.parse(fs.readFileSync(taskFile, 'utf8'));
}

/**
 * 写入任务文件
 */
function writeTask(task) {
  const taskFile = path.join(TASKS_DIR, `${task.task_id}.json`);
  fs.writeFileSync(taskFile, JSON.stringify(task, null, 2));
}

/**
 * 检查依赖是否全部完成
 */
function areDependenciesCompleted(dependsOn) {
  if (!dependsOn || dependsOn.length === 0) {
    return true;
  }
  
  return dependsOn.every(depId => {
    const depTask = readTask(depId);
    return depTask && (depTask.status === 'completed' || depTask.status === 'packaged');
  });
}

/**
 * 激活任务
 */
function activateTask(task) {
  const oldStatus = task.status;
  task.status = 'pending';
  task.activated_at = new Date().toISOString();
  task.history = task.history || [];
  task.history.push({
    timestamp: task.activated_at,
    action: 'activated',
    previous_status: oldStatus,
    note: `依赖已完成：${(task.depends_on || []).join(', ')}`,
    activated_by: 'auto-dependency-check'
  });
  
  writeTask(task);
  
  logEvent('task_activated', {
    task_id: task.task_id,
    dependencies: task.depends_on,
    previous_status: oldStatus
  });
  
  console.log(`✅ ${task.task_id} 已激活（依赖完成）`);
}

/**
 * 主程序
 */
function main() {
  console.log('🔍 检查 queued 任务...');
  
  // 列出所有任务文件
  const taskFiles = fs.readdirSync(TASKS_DIR)
    .filter(f => f.endsWith('.json'))
    .map(f => f.replace('.json', ''));
  
  let activatedCount = 0;
  
  for (const taskId of taskFiles) {
    const task = readTask(taskId);
    if (!task) continue;
    
    // 只处理 queued 状态的任务
    if (task.status !== 'queued') {
      continue;
    }
    
    // 检查依赖
    const dependsOn = task.depends_on || [];
    if (dependsOn.length === 0) {
      // 没有依赖，直接激活
      activateTask(task);
      activatedCount++;
      continue;
    }
    
    // 检查所有依赖是否完成
    if (areDependenciesCompleted(dependsOn)) {
      activateTask(task);
      activatedCount++;
    } else {
      const pendingDeps = dependsOn.filter(depId => {
        const depTask = readTask(depId);
        return !depTask || (depTask.status !== 'completed' && depTask.status !== 'packaged');
      });
      console.log(`⏳ ${task.task_id} 等待依赖：${pendingDeps.join(', ')}`);
    }
  }
  
  console.log('');
  console.log(`📊 检查完成：${activatedCount} 个任务已激活`);
  
  if (activatedCount === 0) {
    console.log('✅ 没有需要激活的任务');
  }
}

main();


path: scripts/apply-review.js
content: #!/usr/bin/env node
/**
 * apply-review.js - 应用 Sonnet 审阅结果到任务文件
 * 
 * 用法：node apply-review.js <task-id> '<review-json>'
 * 
 * 或者从文件读取：node apply-review.js <task-id> --file <review.json>
 */

const fs = require('fs');
const path = require('path');

const TASKS_DIR = path.join(__dirname, '..', 'tasks');
const LOGS_DIR = path.join(__dirname, '..', 'logs');
const SCRIPTS_DIR = path.join(__dirname, '..');
const EVENTS_LOG = path.join(LOGS_DIR, 'events.log');

/**
 * 写入事件日志
 */
function logEvent(event, data = {}) {
  const entry = {
    timestamp: new Date().toISOString(),
    event,
    ...data
  };
  fs.appendFileSync(EVENTS_LOG, JSON.stringify(entry) + '\n');
  console.log(`📝 事件：${event}`, JSON.stringify(data));
  return entry;
}

/**
 * 读取任务文件
 */
function readTask(taskId) {
  const taskFile = path.join(TASKS_DIR, `${taskId}.json`);
  if (!fs.existsSync(taskFile)) {
    return null;
  }
  return JSON.parse(fs.readFileSync(taskFile, 'utf8'));
}

/**
 * 写入任务文件
 */
function writeTask(task) {
  const taskFile = path.join(TASKS_DIR, `${task.task_id}.json`);
  fs.writeFileSync(taskFile, JSON.stringify(task, null, 2));
}

// 主程序
const args = process.argv.slice(2);
const taskId = args[0];

if (!taskId) {
  console.log('用法：');
  console.log('  node apply-review.js <task-id> \'<review-json>\'');
  console.log('  node apply-review.js <task-id> --file <review.json>');
  console.log('  node apply-review.js <task-id> --stdin  # 从 stdin 读取 JSON');
  console.log('');
  console.log('示例：');
  console.log('  node apply-review.js task-010 --file review-result.json');
  console.log('  cat review-result.json | node apply-review.js task-010 --stdin');
  process.exit(0);
}

const task = readTask(taskId);

if (!task) {
  console.error(`❌ 任务不存在：${taskId}`);
  process.exit(1);
}

// 解析 review JSON
let review;

if (args.includes('--file')) {
  const fileIndex = args.indexOf('--file');
  const reviewFile = args[fileIndex + 1];
  
  if (!reviewFile) {
    console.error('❌ 缺少文件名');
    process.exit(1);
  }
  
  if (!fs.existsSync(reviewFile)) {
    console.error(`❌ 文件不存在：${reviewFile}`);
    process.exit(1);
  }
  
  try {
    review = JSON.parse(fs.readFileSync(reviewFile, 'utf8'));
  } catch (error) {
    console.error('❌ JSON 解析失败:', error.message);
    process.exit(1);
  }
} else if (args.includes('--stdin')) {
  // 从 stdin 读取 JSON（避免命令行引号转义问题）
  const input = fs.readFileSync(0, 'utf8');
  
  try {
    review = JSON.parse(input);
  } catch (error) {
    console.error('❌ JSON 解析失败:', error.message);
    process.exit(1);
  }
} else {
  // 从命令行参数读取 JSON
  const reviewJson = args.slice(1).join(' ');
  
  try {
    review = JSON.parse(reviewJson);
  } catch (error) {
    console.error('❌ JSON 解析失败:', error.message);
    console.error('提示：如果 JSON 包含引号，建议使用 --file 或 --stdin 方式');
    console.error('示例：node apply-review.js task-010 --file review.json');
    console.error('      cat review.json | node apply-review.js task-010 --stdin');
    process.exit(1);
  }
}

// 验证必要字段
if (!review.verdict) {
  console.error('❌ 缺少 verdict 字段');
  process.exit(1);
}

if (!['approve', 'revise', 'reject', 'complete'].includes(review.verdict)) {
  console.error(`❌ 无效的 verdict: ${review.verdict}`);
  process.exit(1);
}

console.log(`📝 应用审阅结果到 ${taskId}...`);
console.log(`Verdict: ${review.verdict}`);

// 更新任务
const oldStatus = task.status;
task.review = review;
task.updated_at = new Date().toISOString();

// 根据 verdict 更新状态
if (review.verdict === 'complete') {
  task.status = 'completed';
  task.completed_at = task.updated_at;
  console.log('✅ 任务完成！');
} else if (review.verdict === 'reject') {
  task.current_iteration = (task.current_iteration || 0) + 1;
  if (task.current_iteration >= task.max_iterations) {
    task.status = 'failed';
    console.log('❌ 达到最大迭代次数，任务失败');
  } else {
    task.status = 'pending';
    console.log('🔄 重新执行（iteration +1）');
  }
} else {
  // approve 或 revise → reviewed，等待 executor-agent 执行
  task.status = 'reviewed';
  console.log('⏳ 等待 executor-agent 执行');
}

// 记录到 history
task.history = task.history || [];
task.history.push({
  timestamp: task.updated_at,
  action: 'review_applied',
  verdict: review.verdict,
  confidence: review.confidence,
  feedback: review.feedback,
  model: 'advanced-model/sonnet'
});

writeTask(task);

logEvent('review_applied', {
  task_id: taskId,
  from: oldStatus,
  to: task.status,
  verdict: review.verdict,
  model: 'advanced-model/sonnet'
});

console.log('');
console.log('✅ 审阅结果已应用');
console.log(`   状态：${oldStatus} → ${task.status}`);
console.log(`   Feedback: ${review.feedback}`);

if (review.next_instructions) {
  console.log('');
  console.log('📋 Next Instructions:');
  console.log('-'.repeat(50));
  console.log(review.next_instructions);
  console.log('-'.repeat(50));
}

console.log('');
console.log('下一步：');
if (task.status === 'reviewed') {
  console.log('  运行 executor-agent 心跳执行指令：');
  console.log('  node scripts/iron-heartbeat.js');
} else if (task.status === 'pending') {
  console.log('  重新触发审阅：');
  console.log('  node scripts/trigger-review.js ' + taskId);
}


path: scripts/atomic-lock.sh
content: #!/bin/bash
# atomic-lock.sh - 原子锁管理脚本
# 使用 mkdir 原子操作，彻底消除 TOCTOU 竞态

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TASKS_DIR="$SCRIPT_DIR/../tasks"
LOCK_TIMEOUT_MINUTES=5

usage() {
  echo "用法：$0 <command> <task-id>"
  echo ""
  echo "命令:"
  echo "  acquire   获取锁（成功返回 0，失败返回 1）"
  echo "  release   释放锁"
  echo "  check     检查锁状态"
  echo "  timeout   检查锁是否超时（超时返回 0，未超时返回 1）"
  echo ""
  echo "示例:"
  echo "  $0 acquire task-001"
  echo "  $0 release task-001"
  exit 1
}

acquire_lock() {
  local task_id=$1
  local lock_dir="$TASKS_DIR/${task_id}.lock.d"
  
  # 原子操作：mkdir 成功=获得锁，失败=已有锁
  if mkdir "$lock_dir" 2>/dev/null; then
    # 写入 PID 和时间戳
    echo $$ > "$lock_dir/pid"
    date -Iseconds > "$lock_dir/timestamp"
    echo "✅ 已获取锁：$task_id"
    return 0
  else
    echo "⚠️ 锁已存在：$task_id"
    return 1
  fi
}

release_lock() {
  local task_id=$1
  local lock_dir="$TASKS_DIR/${task_id}.lock.d"
  
  if [ -d "$lock_dir" ]; then
    rm -rf "$lock_dir"
    echo "✅ 已释放锁：$task_id"
    return 0
  else
    echo "⚠️ 锁不存在：$task_id"
    return 0
  fi
}

check_lock() {
  local task_id=$1
  local lock_dir="$TASKS_DIR/${task_id}.lock.d"
  
  if [ -d "$lock_dir" ]; then
    echo "🔒 锁存在：$task_id"
    if [ -f "$lock_dir/pid" ]; then
      echo "   PID: $(cat "$lock_dir/pid")"
    fi
    if [ -f "$lock_dir/timestamp" ]; then
      echo "   创建时间：$(cat "$lock_dir/timestamp")"
    fi
    return 0
  else
    echo "🔓 锁不存在：$task_id"
    return 1
  fi
}

check_timeout() {
  local task_id=$1
  local lock_dir="$TASKS_DIR/${task_id}.lock.d"
  local timestamp_file="$lock_dir/timestamp"
  
  if [ ! -d "$lock_dir" ]; then
    echo "⚠️ 锁不存在，无法检查超时"
    return 1
  fi
  
  if [ ! -f "$timestamp_file" ]; then
    echo "⚠️ 时间戳文件不存在，视为超时"
    return 0
  fi
  
  local timestamp=$(cat "$timestamp_file")
  local lock_epoch=$(date -d "$timestamp" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%S" "$timestamp" +%s 2>/dev/null)
  local now_epoch=$(date +%s)
  local age_seconds=$((now_epoch - lock_epoch))
  local age_minutes=$((age_seconds / 60))
  
  echo "🕐 锁已存在 $age_minutes 分钟"
  
  if [ $age_minutes -ge $LOCK_TIMEOUT_MINUTES ]; then
    echo "⏰ 锁已超时（阈值：$LOCK_TIMEOUT_MINUTES 分钟）"
    return 0
  else
    echo "✅ 锁未超时"
    return 1
  fi
}

# 主程序
if [ $# -lt 2 ]; then
  usage
fi

command=$1
task_id=$2

case "$command" in
  acquire)
    acquire_lock "$task_id"
    ;;
  release)
    release_lock "$task_id"
    ;;
  check)
    check_lock "$task_id"
    ;;
  timeout)
    check_timeout "$task_id"
    ;;
  *)
    echo "❌ 未知命令：$command"
    usage
    ;;
esac


path: scripts/force-unlock.sh
content: #!/bin/bash
# force-unlock.sh - 强制解锁脚本（死锁恢复）
# 用于超时锁的清理和任务状态恢复

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TASKS_DIR="$SCRIPT_DIR/../tasks"
LOGS_DIR="$SCRIPT_DIR/../logs"

# 确保日志目录存在
mkdir -p "$LOGS_DIR"

usage() {
  echo "用法：$0 <task-id> [--note \"备注信息\"]"
  echo ""
  echo "选项:"
  echo "  --note   可选，记录解锁原因"
  echo ""
  echo "示例:"
  echo "  $0 task-001"
  echo "  $0 task-001 --note \"死锁超时恢复\""
  exit 1
}

log_event() {
  local event=$1
  local task_id=$2
  local extra=$3
  
  local json="{\"timestamp\":\"$(date -Iseconds)\",\"event\":\"$event\",\"task_id\":\"$task_id\"$extra}"
  echo "$json" >> "$LOGS_DIR/events.log"
}

# 解析参数
task_id=""
note=""

while [[ $# -gt 0 ]]; do
  case $1 in
    --note)
      note="$2"
      shift 2
      ;;
    *)
      if [ -z "$task_id" ]; then
        task_id=$1
      else
        echo "❌ 未知参数：$1"
        usage
      fi
      shift
      ;;
  esac
done

if [ -z "$task_id" ]; then
  usage
fi

task_file="$TASKS_DIR/${task_id}.json"
lock_dir="$TASKS_DIR/${task_id}.lock.d"

echo "🔓 强制解锁：$task_id"

# 检查任务文件
if [ ! -f "$task_file" ]; then
  echo "❌ 任务文件不存在：$task_file"
  exit 1
fi

# 检查锁是否存在
if [ ! -d "$lock_dir" ]; then
  echo "⚠️ 锁目录不存在，任务可能未锁定"
fi

# 删除锁目录
if [ -d "$lock_dir" ]; then
  rm -rf "$lock_dir"
  echo "✅ 已删除锁目录"
fi

# 更新任务状态
note_escaped=$(echo "$note" | sed 's/"/\\"/g')
node -e "
const fs = require('fs');
const task = JSON.parse(fs.readFileSync('$task_file', 'utf8'));

// 记录解锁前的状态
const oldStatus = task.status;

// 状态回写到 pending（如果是 blocked 或 reviewing）
if (['blocked', 'reviewing', 'executing'].includes(task.status)) {
  task.status = 'pending';
}

// 增加迭代次数
task.current_iteration = (task.current_iteration || 0) + 1;

// 记录到 history
task.history = task.history || [];
task.history.push({
  timestamp: new Date().toISOString(),
  action: 'force_unlocked',
  previous_status: '$oldStatus',
  note: '$note_escaped',
  resolved_by: 'manual-force-unlock'
});

// 更新 blocked 相关字段（如果有）
task.resolved_at = new Date().toISOString();
task.resolved_note = '$note_escaped';

fs.writeFileSync('$task_file', JSON.stringify(task, null, 2));
console.log('✅ 任务状态已更新：' + oldStatus + ' → pending');
"

# 记录事件日志
log_event "force_unlock" "$task_id" ",\"note\":\"$note_escaped\",\"previous_status\":\"reviewing\""}

echo ""
echo "✅ 强制解锁完成"
echo "   任务：$task_id"
echo "   状态：pending（等待审阅）"
if [ -n "$note" ]; then
  echo "   备注：$note"
fi
echo ""
echo "下一步：main-agent 心跳将自动检测到 pending 状态并进行审阅"


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)