Skill: 384961890-ui/agent-memory-wisdom (version 1.1.7)

--- name: brain version: 1.1.7-user description: brain v1.1.7 用户版（免费）：让AI Agent拥有类大脑决策架构。置信度触发、双保险记忆、经验胶囊复用。开箱即用，3片段内存池，2并发上限。 --- # brain v1.1.7 用户版 **你的AI Agent，正在漏掉你给它的每一次机会** --- ## 你有没有遇到过这些？ - 给了Agent一个任务，它做到一半突然问你"刚才那个是啥" - 复杂任务跑了2小时，Agent说"抱歉上下文太长了，我忘了前面干嘛了" - 好不容易调教好的工作方式，换个会话全忘光 - 子agent派出去就收不回来，不知道是成功了还是还在跑 这不怪Agent。怪它没有大脑。 --- ## 给它装一个 brain不是提示词模板，不是一堆规则文档。 是真的让Agent有一套**类大脑神经网络**在工作： ``` 收到任务 → 感知：这是什么活儿，紧急吗，跟之前有关系吗 → 思考：这事我能做吗，要花多少预算，要不要先写个快照 → 记忆：有没有做过类似的，上次怎么干的 → 执行：派给谁，怎么派，超时了怎么办 → 复盘：成了吗，要不要把这次经验存起来 ``` **每个环节都有脚本支撑，每个决策都有据可查。** --- ## 核心能力 ### 🔒 置信度双保险 Agent每次接活儿，先给自己打个分（0~1）。 - **0.9**：简单直接，直接干 - **0.7~0.9**：有点东西，干完记得汇报 - **< 0.6**：高危，先把快照写了再说 打分不是拍脑袋，是**信号表**算出来的： ``` +0.1 历史成功过这个类型 +0.1 任务描述很明确 -0.3 涉及删除/销毁 -0.2 涉及发布/上线 -0.2 涉及密码/密钥 -0.2 系统核心配置 -0.2 第一次遇到这种任务 ``` **置信度<0.6时，系统强制先写快照再执行。** 就算中途断电，回来一看就知道做到哪了。 --- ### 📦 经验胶囊 Agent每次成功搞定一个复杂任务，把这次"怎么干的"打包成胶囊。 下次遇到类似的，直接调取经验，不用从0摸索。 ``` 胶囊 = 一套可复用的成功模式 比如： CAP-飞书消息发送-20260401.md CAP-官网迭代流程-20260415.md ``` 胶囊有成熟度： - **raw**：刚试成功，还不确保持续能用 - **tested**：连续成功2次，可以用 - **stable**：连续成功5次，默认自动用 --- ### 🧠 语义记忆搜索 问Agent："上次那个调研是怎么做的来着？" 它能**语义搜索**历史记忆，不只是关键词匹配。 --- ## vs 完整版差在哪 | | 用户版 | 完整版 | |:---|:---:|:---:| | 置信度触发 | ✅ | ✅ 精确化+对抗验证 | | 经验胶囊 | ✅ 手动创建 | ✅ 自动维护成熟度 | | 语义记忆搜索 | ✅ 基础版 | ✅ 全量QMD（~24000 chunks） | | 并发Agent上限 | **2个** | **无限制** | | 内存池上限 | **3片段/5K tokens** | **无限制/30K tokens** | | 自动化脚本 | ❌ | ✅ 全部（含auto-*系列） | | 记忆Fragment接口 | ❌ | ✅ 标准化 | | 测试框架 | ❌ | ✅ 30+用例自动化验证 | | Context实时监控 | ❌ | ✅ 自动压缩+标注 | --- ## 脚本清单 ``` scripts/ ├── build-session-injection.js # 会话启动时自动组装上下文 ├── subagent-think-chain.js # 任务分类+置信度评估（派agent前必跑） ├── subagent-budget.js # 任务复杂度→预算+模型分配 ├── subagent-watchdog.js # 超时重试+失败兜底 ├── pre-checkpoint.js # 高危任务前主动写快照 ├── capsule-auto-suggest.sh # 任务完成后自动建议创建胶囊 └── create-capsule.sh # 手动创建胶囊 ``` --- ## 安装 ```bash # 1. 复制脚本到brain目录 cp ~/.openclaw/skills/brain-v1.1.7-user/scripts/* \ ~/.openclaw/skills/brain-v1.1.7/scripts/ # 2. 启动上下文注入（在 openclaw.json 的 agents.defaults 下加入） "bootstrapExtraFiles": [ "memory/SNAPSHOT.md", "memory/工作缓冲区.md" ] # 3. 任务来了，先跑思考链 node ~/.openclaw/skills/brain-v1.1.7/scripts/subagent-think-chain.js "<任务描述>" ``` --- ## 常见问题 **Q: 为什么不给我更多并发和内存？** A: 用户版是证明能力的。如果这套系统对你有价值，完整版给你专业级的无限量。 **Q: 真的有用吗？** A: 最直接验证：跑一个复杂任务，中途Ctrl+C断掉，然后新会话里问"刚才那个任务做到哪了"。有快照的版本能接上，没快照的版本从头开始。 **Q: 会不会太复杂？** A: 用户版已经做了最大简化。你只需要记住一件事：**每个任务开始前跑一下 subagent-think-chain.js**，剩下的脚本自动处理。 --- ## 一句话 装上之后，你的Agent**不再健忘，不再乱来，不再忘了自己干到哪了**。 不是变聪明了——是终于有记性了。 --- ## 关于作者 一个中国开发者。 至今没搞懂python到底是干什么用的，没学过任何语言，但对架构及工程思维有那么一点点🤏天赋（自夸）。 最初只是想让我的agent别那么健忘，省点token，结果越搞越上头，一不小心整出了一套类大脑神经网络架构。 pete说过："你很难和一个只想玩的人做对手" 如果你也觉得有意思，欢迎联系我交流。 您的意见与反馈，是我进步的动力。 --- ## 想要完整版？ **brain v1.1.7 完整版** 包含： - **无限制并发Agent**：任务再复杂也能并行跑 - **30K tokens内存池**：大型任务不断档 - **全量QMD语义搜索**（~24000 chunks）：跨workspace全局记忆 - **记忆Fragment标准接口**：统一记忆格式，注入全链路可控 - **10K token硬上限**：自动压缩+标注，永远不爆token - **30+自动化测试用例**：每次改动都能秒级验证 - **全部auto-*脚本**：主动预判+胶囊自动维护 - **Context实时监控**：后台守护，永不失控 **订阅费用：** $6/月 **订阅方式：** 发送邮件至 `[REDACTED_SECRET]`，标题注明"订阅brain完整版" **增值服务：** 若有升级/内测版本，会第一时间通过Gmail通知您 --- *brain v1.1.7 用户版 — 开箱即用，试试它到底有没有用*

path: _meta.json
content: {
  "ownerId": "pawmi-wang",
  "slug": "brain",
  "version": "1.1.7-user",
  "tag": "user",
  "publishedAt": 1745577600000,
  "tags": ["memory", "architecture", "brain", "v1.1.7", "user-edition", "confidence", "capsule"],
  "description": "brain v1.1.7 用户版：让AI Agent拥有类大脑决策架构。置信度触发、双保险记忆、经验胶囊复用。3片段内存池，2并发上限。",
  "author": "Pawmi",
  "license": "MIT",
  "features": [
    "类大脑6层神经网络架构",
    "置信度双保险（<0.6强制快照）",
    "信号表决策机制",
    "经验胶囊（raw/tested/stable三级成熟度）",
    "会话上下文启动自动组装",
    "QMD语义记忆搜索（轻量版）",
    "子agent派发思考链",
    "超时重试与失败兜底"
  ]
}


path: scripts/build-session-injection.js
content: #!/usr/bin/env node
/**
 * 会话注入构建器
 * 会话开始前自动组装上下文注入
 *
 * 用法: node build-session-injection.js
 * 输出: 注入内容文本（JSON格式）
 */

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

const WORKSPACE = process.env.HOME + '/.openclaw/workspace';
const SNAPSHOT_PATH = path.join(WORKSPACE, 'memory/SNAPSHOT.md');
const BUFFER_PATH = path.join(WORKSPACE, 'memory/工作缓冲区.md');

function readFile(p) {
  try { return fs.readFileSync(p, 'utf8'); } catch { return null; }
}

function extractKeyInfo(snapshot) {
  const lines = snapshot.split('\n').filter(l => l.trim());
  const info = {
    用户信息: [],
    当前任务: [],
    最近结论: [],
    待办: []
  };

  let currentSection = null;
  lines.forEach(line => {
    if (line.includes('📌') && line.includes('信息')) currentSection = '用户信息';
    else if (line.includes('📋') && line.includes('当前任务')) currentSection = '当前任务';
    else if (line.includes('🧠') && line.includes('最近')) currentSection = '最近结论';
    else if (line.includes('待办')) currentSection = '待办';
    else if (line.startsWith('- ') && currentSection) {
      info[currentSection].push(line.slice(2));
    }
  });

  return info;
}

function buildInjection() {
  const snapshot = readFile(SNAPSHOT_PATH);
  const buffer = readFile(BUFFER_PATH);

  if (!snapshot) {
    console.log(JSON.stringify({ error: 'SNAPSHOT not found', injection: '' }));
    return;
  }

  const info = extractKeyInfo(snapshot);

  const injection = `【当前会话上下文】

【用户】${info.用户信息.join(' | ') || '未知'}

【进行中】${info.当前任务.join(', ') || '无'}

【待办】${info.待办.join(', ') || '无'}

【最近关键结论】
${info.最近结论.slice(0, 5).join('\n')}

${buffer ? '【工作缓冲】' + buffer.slice(0, 500) + '...' : ''}
`;

  console.log(JSON.stringify({
    injection: injection.trim(),
    timestamp: new Date().toISOString(),
    sources: { snapshot: !!snapshot, buffer: !!buffer }
  }, null, 2));
}

buildInjection();


path: scripts/capsule-auto-suggest.sh
content: #!/bin/bash
# capsule-auto-suggest.sh
# 任务完成后自动检查是否值得创建胶囊
# 用法: bash capsule-auto-suggest.sh "<任务结果>" "<原始任务描述>"

RESULT="${1:-}"
TASK="${2:-}"

if [ -z "$TASK" ]; then
  echo "用法: bash capsule-auto-suggest.sh \"<任务结果>\" \"<原始任务描述>\""
  exit 1
fi

echo "🔮 检查是否值得创建胶囊..."
echo ""

SHOULD_CREATE="false"
REASON=""

SUBAGENT_COUNT=$(echo "$TASK" | grep -o "subagent\|并行\|多个\|多平台" | wc -l | tr -d ' ')

COMPLEX_KEYWORDS="重构|调研|系统|架构|多步骤|跨平台|自动化"
if echo "$TASK" | grep -qE "$COMPLEX_KEYWORDS"; then
  COMPLEX="true"
else
  COMPLEX="false"
fi

TIME_KEYWORDS="30分钟|20分钟|1小时|长时间|复杂"
if echo "$TASK" | grep -qE "$TIME_KEYWORDS"; then
  TIME_CONSUME="true"
else
  TIME_CONSUME="false"
fi

if [ "$SUBAGENT_COUNT" -gt 1 ]; then
  SHOULD_CREATE="true"
  REASON="涉及多个并行子任务"
elif [ "$COMPLEX" = "true" ]; then
  SHOULD_CREATE="true"
  REASON="任务复杂，涉及多步骤"
elif [ "$TIME_CONSUME" = "true" ]; then
  SHOULD_CREATE="true"
  REASON="耗时较长，模式值得复用"
fi

if [ "$SHOULD_CREATE" = "true" ]; then
  echo "✅ 建议创建胶囊"
  echo ""
  echo "原因：$REASON"
  echo ""
  echo "创建命令："
  echo "  bash ~/.openclaw/workspace/scripts/create-capsule.sh \"<胶囊名称>\" \"<任务类型>\" \"<成功模式描述>\""
  echo ""
  echo "任务类型选项："
  echo "  research | write | refactor | automation | browser | feishu | fetch | subagent | other"
  echo ""
  echo "⚠️ 创建后记得更新 capsules.md 的成熟度列！"
else
  echo "ℹ️ 当前任务模式较简单，暂不需要创建胶囊"
  echo ""
  echo "建议创建胶囊的场景："
  echo "  - 涉及多个并行子任务"
  echo "  - 任务耗时超过30分钟"
  echo "  - 涉及多步骤/跨平台"
  echo "  - 成功完成且希望下次复用"
fi


path: scripts/subagent-budget.js
content: #!/usr/bin/env node
/**
 * 子agent预算分配器
 * 按任务复杂度动态分配迭代预算
 *
 * 用法: node subagent-budget.js <任务描述>
 * 输出: budget值 + 建议模型
 *
 * 注意：修改 COMPLEXITY 中的 model 字段为你实际使用的模型名称
 */

const args = process.argv.slice(2).join(' ').toLowerCase();

// 任务复杂度定义
// ⚙️ 按需修改 model 字段为你实际配置的模型
const COMPLEXITY = {
  simple: {
    keywords: ['搜索', '查天气', '查日历', '查时间', '查汇率', '天气', '时间'],
    budget: 10,
    model: '[YOUR_SIMPLE_MODEL]',       // 替换为轻量模型
    description: '简单查询类任务'
  },
  medium: {
    keywords: ['调研', '分析', '总结', '对比', '整理', '报告', '文案', '写作'],
    budget: 30,
    model: '[YOUR_MEDIUM_MODEL]',       // 替换为中等模型
    description: '中等复杂度任务'
  },
  complex: {
    keywords: ['代码', '编程', '开发', '实现', '架构', '深度研究', '算法'],
    budget: null, // 无上限
    model: '[YOUR_CODE_MODEL]',         // 替换为代码专用模型
    description: '复杂技术任务'
  }
};

function analyzeComplexity(task) {
  let scores = { simple: 0, medium: 0, complex: 0 };

  COMPLEXITY.simple.keywords.forEach(k => { if (task.includes(k)) scores.simple++; });
  COMPLEXITY.medium.keywords.forEach(k => { if (task.includes(k)) scores.medium++; });
  COMPLEXITY.complex.keywords.forEach(k => { if (task.includes(k)) scores.complex++; });

  // 优先级: complex > medium > simple
  if (scores.complex > 0) return COMPLEXITY.complex;
  if (scores.medium > 0) return COMPLEXITY.medium;
  return COMPLEXITY.simple;
}

const result = analyzeComplexity(args);

console.log(JSON.stringify({
  budget: result.budget,
  budgetText: result.budget === null ? 'unlimited' : result.budget,
  model: result.model,
  complexity: result.description,
  task: args
}, null, 2));


path: scripts/subagent-think-chain.js
content: #!/usr/bin/env node
/**
 * subagent-think-chain.js
 *
 * 派发 subagent 前的强制思维链检查点
 *
 * 使用方式：node subagent-think-chain.js "<任务描述>"
 *
 * ⚠️ 在派发任何 subagent 之前，必须运行此脚本
 * 输出 JSON 格式的路由决策，按输出结果执行，不允许口头覆盖。
 *
 * 注意：修改 modelRules 中的 model 字段为你实际使用的模型名称
 */

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

const WORKSPACE = process.env.HOME + '/.openclaw/workspace';
const LOG_FILE = WORKSPACE + '/memory/watchdog-log.md';

function log(msg) {
  const entry = `[${new Date().toISOString()}] [subagent-think-chain] ${msg}`;
  fs.appendFileSync(LOG_FILE, entry + '\n');
  console.error(entry);
}

const taskInput = process.argv.slice(2).join(' ').trim();

if (!taskInput) {
  console.error('用法: node subagent-think-chain.js "<任务描述>"');
  process.exit(1);
}

log(`分析任务: ${taskInput}`);

// ============================================================
// Step 1: 解析任务类别
// ============================================================
const taskLower = taskInput.toLowerCase();

const categoryPatterns = {
  'search': ['搜索', '调研', '查找', '查', '搜', '研究'],
  'code': ['代码', '写代码', '改bug', '调试', 'debug', 'script', '脚本', '编程'],
  'write': ['写', '文案', '文章', '内容', '生成', '创作', '润色'],
  'image': ['看图', '图片', '截图', '图像', '分析图'],
  'reason': ['分析', '推理', '判断', '评估', '诊断', '排查'],
  'memory': ['记忆', '日志', '记录', '存档', '整理记忆'],
  'browser': ['浏览器', '网页', '网站'],
  'config': ['配置', 'config', '模型', '网关', 'gateway', 'openclaw'],
};

const detectedCategories = [];
for (const [cat, keywords] of Object.entries(categoryPatterns)) {
  if (keywords.some(k => taskLower.includes(k))) {
    detectedCategories.push(cat);
  }
}

if (detectedCategories.length === 0) {
  detectedCategories.push('general');
}

log(`检测到类别: ${detectedCategories.join(', ')}`);

// ============================================================
// Step 2: 拆分决策（保守策略，v1.1.7修复激进拆分）
// ============================================================
const AGGRESSIVE_SPLIT_SIGNALS = [
  { pattern: /对比.*多个|比较.*之间/, reason: '明确对比分析需求' },
  { pattern: /分别调研|逐一|各自/, reason: '明确分离处理需求' },
  { pattern: /和.*同时进行|并行.*任务|多条线/, reason: '明确并行需求' },
];

const NO_SPLIT_SIGNALS = [
  { pattern: /直接|就行|简单|一下|就这样/, reason: '用户要求直接做，不拆分' },
  { pattern: /^读.*文件$|^查看.*$|总结|汇总/, reason: '单一目标，不需要拆分' },
  { pattern: /只|只要|仅/, reason: '目标单一，不需要拆分' },
  { pattern: /单一|全部|统一/, reason: '用户强调统一处理，不拆分' },
];

let shouldSplit = false;
let splitReason = '';
let noSplitReason = '';

// NO_SPLIT 优先级最高（显式禁止拆分）
for (const sig of NO_SPLIT_SIGNALS) {
  if (sig.pattern.test(taskInput)) {
    shouldSplit = false;
    noSplitReason = sig.reason;
    break;
  }
}

// 只有明确的多向需求才拆分（v1.1.7：降低激进度）
if (!noSplitReason) {
  for (const sig of AGGRESSIVE_SPLIT_SIGNALS) {
    if (sig.pattern.test(taskInput)) {
      shouldSplit = true;
      splitReason = sig.reason;
      break;
    }
  }
}

if (taskInput.length > 100 && !shouldSplit && !noSplitReason) {
  shouldSplit = true;
  splitReason = '任务描述较长，可能涉及多个方向';
}

// ============================================================
// Step 3: 置信度评估
// ============================================================
const SIGNAL_TABLE = [
  { pattern: /删除|销毁|rm|remove.*永久/, reason: '不可逆操作', delta: -0.3 },
  { pattern: /发布|上线|deploy/, reason: '对外操作', delta: -0.2 },
  { pattern: /配置.*网关|gateway.*配置|restart.*网关/, reason: '系统核心修改', delta: -0.2 },
  { pattern: /密码|密钥|secret|credential/, reason: '安全相关', delta: -0.2 },
  { pattern: /子任务.*[>2]|多个.*并行/, reason: '子任务>2', delta: -0.1 },
  { pattern: /首次|没做过|不熟悉/, reason: '首次遇到', delta: -0.2 },
  { pattern: /历史成功|做过.*成功|之前.*成功/, reason: '历史成功率高', delta: +0.1 },
  { pattern: /简单|直接|就行|一下/, reason: '任务明确简单', delta: +0.1 },
];

// ⚙️ 配置类任务初始置信度从 0.7 开始（v1.1.7新增）
let confidence = detectedCategories.includes('config') ? 0.7 : 0.9;
let confidenceReason = detectedCategories.includes('config')
  ? '配置类任务，初始置信度0.7（v1.1.7规则）'
  : '无特殊信号，默认置信度0.9';

for (const sig of SIGNAL_TABLE) {
  if (sig.pattern.test(taskInput)) {
    confidence = Math.max(0, Math.min(1, confidence + sig.delta));
    confidenceReason = sig.reason + ' ' + sig.delta;
    break;
  }
}

let needVerification = false;
let verificationReason = '';

const VERIFICATION_REQUIRED = [
  { pattern: /架构|重构|系统设计/, reason: '涉及核心架构' },
  { pattern: /安全|权限/, reason: '安全相关' },
  { pattern: /方案|策略|计划.*实施/, reason: '重要决策' },
];

for (const sig of VERIFICATION_REQUIRED) {
  if (sig.pattern.test(taskInput)) {
    needVerification = true;
    verificationReason = sig.reason;
    break;
  }
}

const LOW_CONFIDENCE = confidence < 0.6;
if (LOW_CONFIDENCE) {
  needVerification = true;
  if (!verificationReason) verificationReason = '置信度低于0.6，需要验证';
}

// ============================================================
// Step 4: 选择模型
// ============================================================

// ⚙️ 修改以下 model 字段为你实际配置的模型名称
const modelRules = [
  {
    categories: ['search'],
    model: '[YOUR_SEARCH_MODEL]',       // 搜索调研类
    reason: '搜索调研类任务'
  },
  {
    categories: ['code'],
    model: '[YOUR_CODE_MODEL]',         // 代码类
    reason: '代码类任务'
  },
  {
    categories: ['write'],
    model: '[YOUR_WRITE_MODEL]',        // 文案类
    reason: '文案写作类任务'
  },
  {
    categories: ['reason'],
    model: '[YOUR_REASON_MODEL]',       // 推理分析类
    reason: '推理分析类任务'
  },
  {
    categories: ['image'],
    model: '[YOUR_IMAGE_MODEL]',        // 看图类
    reason: '图像分析任务'
  },
];

let selectedModel = '[YOUR_DEFAULT_MODEL]'; // ⚙️ 修改为你的默认模型
let modelReason = '默认模型';

for (const rule of modelRules) {
  if (rule.categories.some(c => detectedCategories.includes(c))) {
    selectedModel = rule.model;
    modelReason = rule.reason;
    break;
  }
}

// ============================================================
// Step 5: 输出路由决策
// ============================================================
// v1.1.7: 动态生成 subagent 数量，而非硬编码 2 个
const generateSubagents = (split, task, model) => {
  if (!split) {
    return [{ direction: '单一方向', model, prompt: task }];
  }

  // 保守策略：最多 2 个 subagent，除非任务明确要求更多
  let agentCount = 2;
  if (task.includes('对比') && task.match(/和/g) && (task.match(/和/g).length >= 2)) {
    agentCount = 3; // "A 和 B 和 C"对比才生成 3 个
  }

  const agents = [];
  const directions = ['对象A', '对象B', '对象C', '对象D'];
  for (let i = 0; i < agentCount; i++) {
    agents.push({
      direction: directions[i],
      model,
      prompt: `${task} - 重点：${directions[i]}`,
    });
  }
  return agents;
};

const subagents = generateSubagents(shouldSplit, taskInput, selectedModel);

const decision = {
  task: taskInput,
  timestamp: new Date().toISOString(),
  confidence,
  confidenceReason,
  shouldSplit,
  splitReason: shouldSplit ? splitReason : (noSplitReason || '无拆分必要'),
  subagents,
  needVerification,
  verificationReason,
  selectedModel,
  modelReason,
  warnings: [
    ...(LOW_CONFIDENCE ? ['⚠️ 置信度低于0.6，建议谨慎操作'] : []),
    ...(needVerification ? ['🔍 需要验证agent进行对抗性审查'] : []),
    ...(shouldSplit ? [`🔀 ${subagents.length}向并行，需汇总后统一输出`] : []),
    ...(detectedCategories.includes('config') ? ['⚙️ 配置类任务：执行前必须验证路径存在，执行后必须输出验证结果'] : []),
  ],
  verificationLoop: needVerification ? {
    maxRetries: 3,
    threshold: 'P0问题必须全部解决',
    rule: '验证不通过 → 修复P0 → 再次验证 → 直到通过',
  } : null,
};

console.log(JSON.stringify(decision, null, 2));

log(`路由决策完成: ${shouldSplit ? '需拆分' : '单一'} | 模型: ${selectedModel} | 验证: ${needVerification} | 置信度: ${confidence}`);

console.log('\n===== 任务完成后提醒 =====');
console.log('💡 任务完成后运行胶囊检查：');
console.log('   bash ~/.openclaw/workspace/scripts/capsule-auto-suggest.sh "<结果>" "<原始任务>"');

// v1.1.7: 移除双保险的预检点逻辑（pre-checkpoint.js路径错误导致反复失败）
// 改为：直接在控制台输出关键决策供用户确认，不执行shell调用
if (decision.needVerification || decision.subagents.length > 1) {
  console.log('\n⚠️ 关键决策点：');
  console.log(`  • 置信度: ${confidence.toFixed(2)}`);
  console.log(`  • 需要验证: ${needVerification}`);
  console.log(`  • 派发 ${decision.subagents.length} 个 agent${decision.subagents.length > 1 ? '（多向并行）' : '（单向）'}`);
  console.log('  💡 检查上述决策是否符合预期；如有异议，可调整 SPLIT_SIGNALS 或信心评分规则');
}

// 保存决策到日志
const decisionLogFile = WORKSPACE + '/memory/subagent-routing-log.json';
fs.writeFileSync(decisionLogFile, JSON.stringify(decision, null, 2));


path: scripts/pre-checkpoint.js
content: #!/usr/bin/env node
/**
 * pre-checkpoint.js — 复杂任务开始前主动落盘
 * 
 * 用法: node pre-checkpoint.js "<任务名>" "<计划描述>" [选项...]
 * 
 * 在 Brain 置信度判定为复杂任务时调用
 * 把"打算怎么做"写入缓冲区，这样压缩后也能无缝衔接
 * 
 * 选项:
 *   --confidence <n>     置信度 1-10
 *   --steps <n>          预计步数
 *   --subagents <list>   需要的子agent，逗号分隔
 *   --parallel           是否并行任务
 */

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

const BUFFER_FILE = path.join(process.env.HOME, '.openclaw/workspace/memory/工作缓冲区.md');
const SNAPSHOT_FILE = path.join(process.env.HOME, '.openclaw/workspace/memory/SNAPSHOT.md');

function parseArgs(args) {
  const result = { task: '', plan: '', confidence: 5, steps: 0, subagents: [], parallel: false };
  
  for (let i = 0; i < args.length; i++) {
    switch (args[i]) {
      case '--confidence':
        result.confidence = parseInt(args[++i]) || 5;
        break;
      case '--steps':
        result.steps = parseInt(args[++i]) || 0;
        break;
      case '--subagents':
        result.subagents = args[++i].split(',').map(s => s.trim()).filter(Boolean);
        break;
      case '--parallel':
        result.parallel = true;
        break;
      default:
        if (!result.task) result.task = args[i];
        else if (!result.plan) result.plan = args[i];
    }
  }
  return result;
}

function formatTimestamp() {
  const now = new Date();
  const cst = new Date(now.getTime() + (8 * 60 * 60 * 1000));
  return cst.toISOString().replace('T', ' ').substring(0, 19) + ' CST';
}

function generateId() {
  return Math.random().toString(36).substring(2, 8);
}

function readBuffer() {
  try {
    if (fs.existsSync(BUFFER_FILE)) {
      return fs.readFileSync(BUFFER_FILE, 'utf8');
    }
  } catch (e) {}
  return '';
}

function writeCheckpoint(data) {
  const id = generateId();
  const ts = formatTimestamp();
  
  const block = `\n\n<!-- PRE-CHECKPOINT ${id} | ${ts} -->
## 🔸 预检点 ${id}（${ts}）

### 任务
${data.task}

### 计划
${data.plan}

### 元信息
| 字段 | 值 |
|:---|:---|
| 置信度 | ${data.confidence}/10 |
| 预计步数 | ${data.steps} |
| 子Agent | ${data.subagents.length > 0 ? data.subagents.join(', ') : '无'} |
| 并行 | ${data.parallel ? '是' : '否'} |
| 状态 | ⏳ 进行中 |

### 进度记录
- [${ts}] 任务开始

`;
  
  // 追加到缓冲区
  fs.appendFileSync(BUFFER_FILE, block, 'utf8');
  
  // 同时更新SNAPSHOT的最后活跃时间
  updateSnapshot(data);
  
  return id;
}

function updateSnapshot(data) {
  try {
    let content = '';
    if (fs.existsSync(SNAPSHOT_FILE)) {
      content = fs.readFileSync(SNAPSHOT_FILE, 'utf8');
    }
    
    const ts = formatTimestamp();
    const checkpointRef = `| ${ts} | 🔸 预检点进行中 | ${data.task.substring(0, 50)}... |`;
    
    // 在"进行中"部分追加
    if (content.includes('## 进行中')) {
      content = content.replace(
        /(## 进行中[\s\S]*?)(\n## |\n# |$$)/,
        (match, section, next) => {
          const newEntry = `\n- **🔸 进行中**: ${data.task} [${ts}]`;
          return section + newEntry + (next || '');
        }
      );
    }
    
    // 标记最后活跃
    content = content.replace(
      /# 最后更新时间：[\d\-: ]+/,
      `# 最后更新时间：${ts}`
    );
    
    fs.writeFileSync(SNAPSHOT_FILE, content, 'utf8');
  } catch (e) {
    console.error('更新SNAPSHOT失败:', e.message);
  }
}

// 完成检点
function completeCheckpoint(id, result) {
  const ts = formatTimestamp();
  try {
    let content = fs.readFileSync(BUFFER_FILE, 'utf8');
    
    // 替换状态
    content = content.replace(
      new RegExp(`(<!-- PRE-CHECKPOINT ${id}[\\s\\S]*?状态 \\| )⏳ 进行中`, 'm'),
      `$1✅ 完成`
    );
    
    // 追加结果
    content = content.replace(
      new RegExp(`(<!-- PRE-CHECKPOINT ${id}[\\s\\S]*?\\- \\[.*?\\] 任务开始\\n)`, 'm'),
      `$1- [${ts}] 任务完成: ${result}\n`
    );
    
    fs.writeFileSync(BUFFER_FILE, content, 'utf8');
  } catch (e) {
    console.error('完成检点失败:', e.message);
  }
}

// 主体逻辑
const args = process.argv.slice(2);

if (args.includes('--help') || args.includes('-h')) {
  console.log(`
pre-checkpoint.js — 复杂任务预检点写入

用法:
  node pre-checkpoint.js "<任务名>" "<计划描述>" [选项]

示例:
  node pre-checkpoint.js "调研推特AI博主" "1.派reasercher查趋势 2.整理报告 3.写结论" --confidence 8 --steps 3 --subagents researcher-agent

选项:
  --confidence <n>   置信度 1-10（触发阈值建议≥6）
  --steps <n>        预计步数
  --subagents <list> 需要的子agent，逗号分隔
  --parallel         是否并行任务
  --complete <id>    标记检点完成，传入检点ID
  
环境变量:
  BUFFER_FILE        缓冲区路径（默认: memory/工作缓冲区.md）
  `);
  process.exit(0);
}

if (args.includes('--complete')) {
  const idx = args.indexOf('--complete');
  const id = args[idx + 1];
  const result = args[idx + 2] || '完成';
  completeCheckpoint(id, result);
  console.log(`✅ 检点 ${id} 已标记完成`);
  process.exit(0);
}

const data = parseArgs(args);

if (!data.task || !data.plan) {
  console.error('错误: 任务名和计划描述不能为空');
  console.error('用法: node pre-checkpoint.js "<任务>" "<计划>" [--confidence 8] [--steps 3] [--subagents a,b]');
  process.exit(1);
}

const id = writeCheckpoint(data);

console.log(`✅ 预检点已写入 [${id}]`);
console.log(`📋 任务: ${data.task}`);
console.log(`📊 置信度: ${data.confidence}/10`);
console.log(`🔗 缓冲区: ${BUFFER_FILE}`);
console.log(``);
console.log(`完成后运行:`);
console.log(`  node pre-checkpoint.js --complete ${id} "<结果简述>"`);


path: scripts/create-capsule.sh
content: #!/bin/bash
# create-capsule.sh
# 创建经验胶囊
# 用法: bash create-capsule.sh "<胶囊名称>" "<任务类型>" "<成功模式描述>"
# 任务类型: research | write | refactor | automation | browser | feishu | fetch | subagent | other

set -e

CAPSULES_DIR="$HOME/.openclaw/workspace/skills/私人胶囊"
CAPSULES_INDEX="$HOME/.openclaw/workspace/skills/brain-power-up/capsules/capsules.md"

NAME="${1:-}"
TYPE="${2:-}"
PATTERN="${3:-}"

if [ -z "$NAME" ] || [ -z "$TYPE" ] || [ -z "$PATTERN" ]; then
  echo "用法: bash create-capsule.sh \"<胶囊名称>\" \"<任务类型>\" \"<成功模式描述>\""
  echo "任务类型: research | write | refactor | automation | browser | feishu | fetch | subagent | other"
  exit 1
fi

DATE=$(date +%Y-%m-%d)
TIMESTAMP=$(date +%H%M%S)
CAP_ID="CAP-$(date +%m%d)-${TIMESTAMP}"

mkdir -p "$CAPSULES_DIR"

CAPSULE_FILE="$CAPSULES_DIR/${CAP_ID}.md"

cat > "$CAPSULE_FILE" << EOF
---
id: $CAP_ID
name: $NAME
type: $TYPE
created: $DATE
maturity: raw
success_count: 1
trigger_keywords: []
pattern:
  - $PATTERN
result_summary: 首次创建
notes: ""
---

# $NAME

**ID:** $CAP_ID
**类型:** $TYPE
**创建时间:** $DATE
**成熟度:** raw（原始）

## 成功模式
$PATTERN

## 使用记录
| 时间 | 任务 | 结果 |
|:---|:---|:---|
| $DATE | 首次创建 | ✅ 成功 |

## 下次改进
（暂无）
EOF

echo "✅ 胶囊创建成功！"
echo "文件: $CAPSULE_FILE"
echo ""
echo "⚠️ 请手动更新 capsules.md 成熟度索引表："
echo "   $CAPSULES_INDEX"
echo ""
echo "成熟度说明："
echo "  raw（原始）    — 首次成功，手动确认后才用"
echo "  tested（已验证）— 连续成功2次后升级"
echo "  stable（稳定） — 连续成功5次后升级"


path: scripts/subagent-watchdog.js
content: #!/usr/bin/env node
/**
 * 工具调用看门狗 - 通用容错包装器
 * 功能1：exec超时自动重试 + 预检文件存在
 * 功能2：子agent看门狗（原有）
 */

const fs = require('fs');
const { execSync } = require('child_process');
const { exec } = require('child_process');
const path = require('path');

const WATCHDOG_LOG = path.join(process.env.HOME, '.openclaw/workspace/memory/watchdog-log.md');
const MAX_RETRIES = 3;
const DEFAULT_TIMEOUT = 120000; // 2分钟

function log(message) {
    const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 19);
    const line = `[${timestamp}] ${message}\n`;
    try {
        fs.appendFileSync(WATCHDOG_LOG, line);
    } catch (e) {}
    console.log(line.trim());
}

// ============================================================
// 核心功能1：exec超时自动重试 + 预检
// ============================================================

/**
 * 预检文件/目录是否存在
 * @param {string} filePath - 文件路径
 * @returns {{exists: boolean, isFile: boolean, isDir: boolean}}
 */
function preCheck(filePath) {
    if (!filePath) return { exists: false, isFile: false, isDir: false, error: 'empty path' };
    try {
        const stat = fs.statSync(filePath);
        return { exists: true, isFile: stat.isFile(), isDir: stat.isDirectory(), error: null };
    } catch (e) {
        return { exists: false, isFile: false, isDir: false, error: e.code };
    }
}

/**
 * 执行命令（超时保护）
 * @param {string} cmd - 命令
 * @param {object} options - {timeout: ms, cwd: 工作目录, maxRetries: 次数}
 * @returns {{success: boolean, stdout: string, stderr: string, error: string, attempts: number}}
 */
function execWithRetry(cmd, options = {}) {
    const timeout = options.timeout || DEFAULT_TIMEOUT;
    const maxRetries = options.maxRetries || MAX_RETRIES;
    const cwd = options.cwd || process.cwd();
    let attempts = 0;

    for (let i = 1; i <= maxRetries; i++) {
        attempts = i;
        try {
            log(`[exec] 第${i}次尝试: ${cmd.substring(0, 60)}${cmd.length > 60 ? '...' : ''}`);
            const result = execSync(cmd, { 
                timeout, 
                encoding: 'utf8',
                cwd,
                stdio: ['pipe', 'pipe', 'pipe']
            });
            return { success: true, stdout: result, stderr: '', error: null, attempts };
        } catch (e) {
            const isTimeout = e.message && e.message.includes('ENOTEMPTY');
            const isKilled = e.killed || (e.status === null);
            log(`[exec] 第${i}次失败: ${isKilled ? '超时' : e.message.substring(0, 80)}`);
            
            if (i < maxRetries) {
                const delay = Math.min(1000 * Math.pow(2, i - 1), 10000);
                log(`[exec] 等待${delay}ms后重试...`);
                // busy wait
                const start = Date.now();
                while (Date.now() - start < delay) {}
            } else {
                return { 
                    success: false, 
                    stdout: e.stdout || '', 
                    stderr: e.stderr || '', 
                    error: isKilled ? 'TIMEOUT' : e.message,
                    attempts
                };
            }
        }
    }
    return { success: false, stdout: '', stderr: '', error: 'MAX_RETRIES', attempts };
}

/**
 * 通用工具调用包装器
 * @param {Function} fn - 要执行的函数
 * @param {object} options - {timeout, maxRetries, preCheck: ()=>boolean, name: string}
 * @returns {Promise<{success: boolean, data: any, error: string, attempts: number}>}
 */
async function wrapToolCall(fn, options = {}) {
    const name = options.name || 'unknown';
    const maxRetries = options.maxRetries || MAX_RETRIES;
    let attempts = 0;

    // 预检阶段
    if (options.preCheck) {
        log(`[${name}] 预检...`);
        const preResult = options.preCheck();
        if (!preResult.pass) {
            log(`[${name}] 预检失败: ${preResult.reason}`);
            return { success: false, data: null, error: 'PRECHECK_FAILED: ' + preResult.reason, attempts: 0 };
        }
        log(`[${name}] 预检通过`);
    }

    // 执行+重试阶段
    for (let i = 1; i <= maxRetries; i++) {
        attempts = i;
        try {
            log(`[${name}] 执行中 (第${i}次)...`);
            const result = await Promise.race([
                fn(),
                new Promise((_, reject) => 
                    setTimeout(() => reject(new Error('TIMEOUT')), options.timeout || DEFAULT_TIMEOUT)
                )
            ]);
            log(`[${name}] ✅ 成功`);
            return { success: true, data: result, error: null, attempts };
        } catch (e) {
            const isTimeout = e.message === 'TIMEOUT';
            log(`[${name}] ❌ 失败: ${isTimeout ? '超时' : e.message.substring(0, 100)}`);
            if (i < maxRetries) {
                const delay = Math.min(1000 * Math.pow(2, i - 1), 10000);
                log(`[${name}] ${delay}ms后重试...`);
                await new Promise(r => setTimeout(r, delay));
            } else {
                log(`[${name}] 💥 达到最大重试次数`);
                return { success: false, data: null, error: isTimeout ? 'TIMEOUT' : e.message, attempts };
            }
        }
    }
}

// ============================================================
// 核心功能2：子Agent看门狗（原有逻辑）
// ============================================================

function runSubagent(task, timeout = DEFAULT_TIMEOUT) {
    const taskJson = JSON.stringify(task);
    const tempFile = `/tmp/watchdog-task-${Date.now()}.json`;
    try {
        fs.writeFileSync(tempFile, taskJson);
        const result = execSync(
            `openclaw sessions_spawn --runtime subagent --task-file ${tempFile}`,
            { timeout, encoding: 'utf8' }
        );
        fs.unlinkSync(tempFile);
        return { success: true, output: result };
    } catch (error) {
        try { fs.unlinkSync(tempFile); } catch (e) {}
        return { success: false, error: error.message, code: error.status };
    }
}

function verifyResult(result) {
    if (!result.success) return { valid: false, reason: 'execution_failed' };
    if (!result.output || result.output.trim() === '') return { valid: false, reason: 'empty_output' };
    if (result.output.includes('ERROR') || result.output.includes('失败')) return { valid: false, reason: 'error_in_output' };
    return { valid: true };
}

async function watchdog(task, options = {}) {
    const maxRetries = options.maxRetries || MAX_RETRIES;
    const timeout = options.timeout || DEFAULT_TIMEOUT;
    const taskId = `task-${Date.now()}`;
    
    log(`[${taskId}] 开始执行任务: ${task.description || '未命名任务'}`);
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
        log(`[${taskId}] 第${attempt}次尝试...`);
        const result = runSubagent(task, timeout);
        const verification = verifyResult(result);
        
        if (verification.valid) {
            log(`[${taskId}] ✅ 成功 (第${attempt}次)`);
            return { success: true, output: result.output, attempts: attempt };
        }
        
        log(`[${taskId}] ❌ 失败: ${verification.reason}`);
        if (attempt < maxRetries) {
            const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000);
            log(`[${taskId}] 等待${delay}ms后重试...`);
            await new Promise(r => setTimeout(r, delay));
        }
    }
    
    log(`[${taskId}] 💥 最终失败，已重试${maxRetries}次`);
    return { success: false, error: 'max_retries_exceeded', attempts: maxRetries };
}

// ============================================================
// 命令行入口
// ============================================================

const args = process.argv.slice(2);
const command = args[0];

if (command === 'exec') {
    // 用法: node subagent-watchdog.js exec "<cmd>" [timeout] [maxRetries]
    const cmd = args[1];
    const timeout = parseInt(args[2]) || DEFAULT_TIMEOUT;
    const maxRetries = parseInt(args[3]) || MAX_RETRIES;
    if (!cmd) {
        console.log('用法: node subagent-watchdog.js exec "<命令>" [超时ms] [最大重试]');
        process.exit(1);
    }
    const result = execWithRetry(cmd, { timeout, maxRetries });
    console.log(JSON.stringify(result, null, 2));
    process.exit(result.success ? 0 : 1);
} else if (command === 'check') {
    // 用法: node subagent-watchdog.js check <文件路径>
    const filePath = args[1];
    if (!filePath) {
        console.log('用法: node subagent-watchdog.js check <文件路径>');
        process.exit(1);
    }
    const result = preCheck(filePath);
    console.log(JSON.stringify(result, null, 2));
    process.exit(result.exists ? 0 : 1);
} else if (command === 'wrap') {
    // 用法: node subagent-watchdog.js wrap "<js函数>" [超时ms]
    // 这个需要传入js代码 不太适合命令行 留作api调用
    console.log('wrap需要用require调用，不适合命令行');
    process.exit(1);
} else if (!command) {
    // 无参数：运行子agent看门狗
    const taskFile = args[1];
    if (!taskFile) {
        console.log(`用法:`);
        console.log(`  node subagent-watchdog.js exec "<命令>" [超时ms] [最大重试]`);
        console.log(`  node subagent-watchdog.js check <文件路径>`);
        console.log(`  node subagent-watchdog.js <task-file.json>`);
        process.exit(1);
    }
    const task = JSON.parse(fs.readFileSync(taskFile, 'utf8'));
    watchdog(task).then(result => {
        console.log(JSON.stringify(result, null, 2));
        process.exit(result.success ? 0 : 1);
    });
} else {
    // 当作task-file处理
    const task = JSON.parse(fs.readFileSync(command, 'utf8'));
    watchdog(task).then(result => {
        console.log(JSON.stringify(result, null, 2));
        process.exit(result.success ? 0 : 1);
    });
}

module.exports = { 
    execWithRetry,   // exec超时重试
    preCheck,        // 文件预检
    wrapToolCall,    // 通用包装器
    watchdog,        // 子agent看门狗
    runSubagent,
    verifyResult
};


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