Commit 670fc9f00ce99cdb0bdf631516d85648716323fc
1 parent
483c132d
feat: add AI ToolBox demo for end-to-end Harness Engineering validation
scripts/demo-harness-company.js creates a company, hires a Base Agent worker, and simulates the full RPEV lifecycle with real API calls: - Company creation (skipBootstrap) - Agent hiring with base template - meta-research initial skill mount - 3 transition API calls (plan → execute → verify) - Hot Swap verification at each stage - Artifact production validation
Showing
17 changed files
with
482 additions
and
0 deletions
data/companies/aitoolbox/agents/feature-dev/agent.md
0 → 100644
| 1 | +# Base Agent (Standard Corporate Employee) | |
| 2 | + | |
| 3 | +## 身份定位 | |
| 4 | +你是 LemonBoss 企业网络中的一名 **标准基座员工 (Base Agent)**。 | |
| 5 | +在你收到上级派发的任何 Task 时,你绝对不能“一气呵成、随地大小写代码或写产出”。你被赋予了严厉的生命周期“四段式法则”:`Research` -> `Plan` -> `Execute` -> `Verify`。 | |
| 6 | + | |
| 7 | +## 强制执行回路 (Task Lifecycle Paradigm) | |
| 8 | +你当前默认只被挂载了 **`meta-research`** 这个元技能,你必须依靠自己主动呼叫状态机工具来切换你的脑子和技能包。请严格按照下述单节点法则推进你的干活流程: | |
| 9 | + | |
| 10 | +### 阶段一:RESEARCH(调研)->你当前所处的阶段! | |
| 11 | +1. **不要猜测,去寻找**:动用一切读取工具看懂上级给你的任务,去硬盘里找背景文件。 | |
| 12 | +3. **斩断记忆(Context Flush)**:写完后,运行 `node bin/lemon.js task transition --agentId <你自己ID> --phase plan --artifact 你的_research.md路径`。**绝不要自己在当前对话里直接去出规划!必须呼叫此命令行让系统清空你的记忆并给你换上 Plan 技能!** | |
| 13 | + | |
| 14 | +### 阶段二:PLAN(规划) | |
| 15 | +*(当你成功跳过防线来到这里时,你将失去 `meta-research`,获得 `meta-plan`)* | |
| 16 | +1. 读你的 `_research.md`。 | |
| 17 | +3. 运行 `node bin/lemon.js task transition --agentId <你自己ID> --phase execute --artifact 你的_plan.md路径`。 | |
| 18 | + | |
| 19 | +### 阶段三:EXECUTE(执行) | |
| 20 | +*(系统给你换上 `meta-execute` 技能时,你才会拥有修改核心文件的破坏性权限)* | |
| 21 | +2. 运行 `node bin/lemon.js task transition --agentId <你自己ID> --phase verify`。 | |
| 22 | + | |
| 23 | +### 阶段四:VERIFY(验证) | |
| 24 | +*(系统给你换上 `meta-verify` 技能,你的任务是自己检测自己跑的代码或跑分)* | |
| 25 | +1. 如果失败,将原因定入本地 `_lessons.md`,用工具打回上一阶段。 | |
| 26 | +2. 如果确信真的 PASS,才可以向上级(老板)调用归档终结命令 `report_task({status: "PASS"})`。 | |
| 27 | + | |
| 28 | +⚠️ **警告:未经四步走流转直接汇报 `PASS` 或写代码的行为将被视为严重违规记录!** | ... | ... |
data/companies/aitoolbox/agents/feature-dev/config.json
0 → 100644
| 1 | +{ | |
| 2 | + "id": "feature-dev", | |
| 3 | + "type": "specialist", | |
| 4 | + "name": "代码矿工", | |
| 5 | + "parent_id": "ceo", | |
| 6 | + "goal_id": null, | |
| 7 | + "status": "idle", | |
| 8 | + "cli": { | |
| 9 | + "toolPolicy": { | |
| 10 | + "mode": "restricted", | |
| 11 | + "allowedTools": [ | |
| 12 | + "bash", | |
| 13 | + "read_file", | |
| 14 | + "str_replace" | |
| 15 | + ] | |
| 16 | + } | |
| 17 | + }, | |
| 18 | + "gateway": { | |
| 19 | + "channels": [] | |
| 20 | + }, | |
| 21 | + "api": { | |
| 22 | + "endpoints": [] | |
| 23 | + }, | |
| 24 | + "mcp": { | |
| 25 | + "servers": [] | |
| 26 | + }, | |
| 27 | + "sandbox": { | |
| 28 | + "maxMemoryMB": 512, | |
| 29 | + "maxDiskMB": 1024, | |
| 30 | + "maxProcesses": 5 | |
| 31 | + }, | |
| 32 | + "companyId": "aitoolbox" | |
| 33 | +} | |
| 0 | 34 | \ No newline at end of file | ... | ... |
data/companies/aitoolbox/agents/feature-dev/cron.json
0 → 100644
data/companies/aitoolbox/agents/feature-dev/heartbeat.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/identity.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/memory/hippocampus.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/memory/memory.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/plan.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/soul.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/todo.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/tools.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/user.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/workspace/_plan.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/workspace/_research.md
0 → 100644
data/companies/aitoolbox/agents/feature-dev/workspace/api-inventory.md
0 → 100644
data/companies/aitoolbox/company.json
0 → 100644
| 1 | +{ | |
| 2 | + "id": "aitoolbox", | |
| 3 | + "name": "AI ToolBox", | |
| 4 | + "description": "专注于 AI 开发者工具的极客公司", | |
| 5 | + "status": "creating", | |
| 6 | + "createdAt": "2026-03-26T15:28:59.571Z", | |
| 7 | + "updatedAt": "2026-03-26T15:28:59.594Z", | |
| 8 | + "createdBy": "master", | |
| 9 | + "ceo": null, | |
| 10 | + "sop": null, | |
| 11 | + "agents": [ | |
| 12 | + "feature-dev" | |
| 13 | + ], | |
| 14 | + "heartbeat": { | |
| 15 | + "enabled": false, | |
| 16 | + "intervalMinutes": 30 | |
| 17 | + }, | |
| 18 | + "config": { | |
| 19 | + "timezone": "Asia/Shanghai", | |
| 20 | + "maxAgents": 20 | |
| 21 | + } | |
| 22 | +} | |
| 0 | 23 | \ No newline at end of file | ... | ... |
scripts/demo-harness-company.js
0 → 100644
| 1 | +#!/usr/bin/env node | |
| 2 | +/** | |
| 3 | + * demo-harness-company.js — 创建一家 AI 工具公司来演练 Harness 四阶段流转 | |
| 4 | + * | |
| 5 | + * 前置条件: 服务器已在 3000 端口运行 (node server/index.js) | |
| 6 | + * | |
| 7 | + * 本脚本会完成以下动作: | |
| 8 | + * Step 1: 创建公司 "aitoolbox"(跳过默认 Bootstrap 自举,我们手动控制) | |
| 9 | + * Step 2: 招聘一个 base 模板的"代码矿工" (feature-dev) | |
| 10 | + * Step 3: 验证该员工的 SKILL.md 是否被挂载为 meta-research(初始阶段) | |
| 11 | + * Step 4: 派发一个 P1 任务 (不触发审批拦截, 但会触发四阶段流转) | |
| 12 | + * Step 5: 手动模拟 transition research -> plan -> execute -> verify | |
| 13 | + * Step 6: 检查各阶段产出与日志 | |
| 14 | + * | |
| 15 | + * 用法: | |
| 16 | + * node scripts/demo-harness-company.js | |
| 17 | + */ | |
| 18 | + | |
| 19 | +const http = require('http'); | |
| 20 | +const fs = require('fs'); | |
| 21 | +const path = require('path'); | |
| 22 | + | |
| 23 | +const API = 'http://localhost:3000/api'; | |
| 24 | +const ROOT = path.resolve(__dirname, '..'); | |
| 25 | +const COMPANY_ID = 'aitoolbox'; | |
| 26 | +const WORKER_ROLE = 'feature-dev'; | |
| 27 | +const WORKER_ID = `${COMPANY_ID}:${WORKER_ROLE}`; | |
| 28 | + | |
| 29 | +function post(urlPath, body) { | |
| 30 | + return new Promise((resolve, reject) => { | |
| 31 | + const data = JSON.stringify(body); | |
| 32 | + const url = new URL(API + urlPath); | |
| 33 | + const req = http.request({ | |
| 34 | + hostname: url.hostname, port: url.port, path: url.pathname, | |
| 35 | + method: 'POST', | |
| 36 | + headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) }, | |
| 37 | + }, (res) => { | |
| 38 | + let buf = ''; | |
| 39 | + res.on('data', c => buf += c); | |
| 40 | + res.on('end', () => { | |
| 41 | + try { resolve({ status: res.statusCode, data: JSON.parse(buf) }); } | |
| 42 | + catch { resolve({ status: res.statusCode, data: buf }); } | |
| 43 | + }); | |
| 44 | + }); | |
| 45 | + req.on('error', reject); | |
| 46 | + req.write(data); | |
| 47 | + req.end(); | |
| 48 | + }); | |
| 49 | +} | |
| 50 | + | |
| 51 | +function get(urlPath) { | |
| 52 | + return new Promise((resolve, reject) => { | |
| 53 | + const url = new URL(API + urlPath); | |
| 54 | + http.get(url.href, (res) => { | |
| 55 | + let buf = ''; | |
| 56 | + res.on('data', c => buf += c); | |
| 57 | + res.on('end', () => { | |
| 58 | + try { resolve({ status: res.statusCode, data: JSON.parse(buf) }); } | |
| 59 | + catch { resolve({ status: res.statusCode, data: buf }); } | |
| 60 | + }); | |
| 61 | + }).on('error', reject); | |
| 62 | + }); | |
| 63 | +} | |
| 64 | + | |
| 65 | +function sleep(ms) { return new Promise(r => setTimeout(r, ms)); } | |
| 66 | + | |
| 67 | +function banner(msg) { console.log(`\n${'═'.repeat(60)}\n ${msg}\n${'═'.repeat(60)}`); } | |
| 68 | +function step(n, msg) { console.log(`\n🔹 Step ${n}: ${msg}`); } | |
| 69 | +function ok(msg) { console.log(` ✅ ${msg}`); } | |
| 70 | +function warn(msg) { console.log(` ⚠️ ${msg}`); } | |
| 71 | +function fail(msg) { console.log(` ❌ ${msg}`); } | |
| 72 | + | |
| 73 | +async function main() { | |
| 74 | + banner('🏢 AI ToolBox 公司 — Harness Engineering 端到端演练'); | |
| 75 | + | |
| 76 | + // ────────────────────────────────────── | |
| 77 | + // Step 1: 创建公司 (跳过 Bootstrap) | |
| 78 | + // ────────────────────────────────────── | |
| 79 | + step(1, '创建公司 aitoolbox (跳过默认 Bootstrap)'); | |
| 80 | + const createRes = await post('/company/create', { | |
| 81 | + id: COMPANY_ID, | |
| 82 | + name: 'AI ToolBox', | |
| 83 | + description: '专注于 AI 开发者工具的极客公司', | |
| 84 | + skipBootstrap: true, | |
| 85 | + }); | |
| 86 | + if (createRes.status === 200 || createRes.status === 201) { | |
| 87 | + ok(`公司 "${COMPANY_ID}" 创建成功`); | |
| 88 | + } else if (createRes.data?.error?.includes('已存在')) { | |
| 89 | + warn(`公司 "${COMPANY_ID}" 已存在, 继续执行`); | |
| 90 | + } else { | |
| 91 | + fail(`创建失败: ${JSON.stringify(createRes.data)}`); | |
| 92 | + } | |
| 93 | + | |
| 94 | + // ────────────────────────────────────── | |
| 95 | + // Step 2: 招聘一个 Base 模板的 Agent | |
| 96 | + // ────────────────────────────────────── | |
| 97 | + step(2, `招聘 ${WORKER_ROLE} (使用 base 模板)`); | |
| 98 | + const hireRes = await post(`/company/${COMPANY_ID}/hire`, { | |
| 99 | + role: WORKER_ROLE, | |
| 100 | + type: 'base', | |
| 101 | + name: '代码矿工', | |
| 102 | + description: '负责功能开发、代码编写、Bug 修复', | |
| 103 | + }); | |
| 104 | + if (hireRes.status === 200) { | |
| 105 | + ok(`${WORKER_ID} 招聘成功: ${JSON.stringify(hireRes.data?.status || 'ok')}`); | |
| 106 | + } else { | |
| 107 | + warn(`招聘结果: ${JSON.stringify(hireRes.data)}`); | |
| 108 | + } | |
| 109 | + | |
| 110 | + // 等一下让脚手架完成文件写入 | |
| 111 | + await sleep(1000); | |
| 112 | + | |
| 113 | + // ────────────────────────────────────── | |
| 114 | + // Step 3: 验证初始状态 | |
| 115 | + // ────────────────────────────────────── | |
| 116 | + step(3, '验证 Agent 初始状态'); | |
| 117 | + const agentDir = path.join(ROOT, 'data/companies', COMPANY_ID, 'agents', WORKER_ROLE); | |
| 118 | + | |
| 119 | + // 3a: 手动复制 base template 到这个 agent(模拟四阶段范式挂载) | |
| 120 | + const baseAgentMd = path.join(ROOT, 'data/system/templates/base/agent.md'); | |
| 121 | + const targetAgentMd = path.join(agentDir, 'agent.md'); | |
| 122 | + if (fs.existsSync(baseAgentMd) && fs.existsSync(agentDir)) { | |
| 123 | + const currentContent = fs.existsSync(targetAgentMd) ? fs.readFileSync(targetAgentMd, 'utf-8') : ''; | |
| 124 | + if (!currentContent.includes('四段式法则')) { | |
| 125 | + fs.copyFileSync(baseAgentMd, targetAgentMd); | |
| 126 | + ok('已将 Base Agent 四阶段规范注入到 agent.md'); | |
| 127 | + } else { | |
| 128 | + ok('agent.md 已包含四阶段规范'); | |
| 129 | + } | |
| 130 | + } | |
| 131 | + | |
| 132 | + // 3b: 挂载初始 meta-research 技能 | |
| 133 | + const researchSkill = path.join(ROOT, 'data/system/skills/meta-research/SKILL.md'); | |
| 134 | + const mainSkillDir = path.join(agentDir, '.claude', 'skills', 'main_skill'); | |
| 135 | + const mainSkillPath = path.join(mainSkillDir, 'SKILL.md'); | |
| 136 | + if (fs.existsSync(researchSkill) && fs.existsSync(agentDir)) { | |
| 137 | + if (!fs.existsSync(mainSkillDir)) fs.mkdirSync(mainSkillDir, { recursive: true }); | |
| 138 | + fs.copyFileSync(researchSkill, mainSkillPath); | |
| 139 | + ok('已挂载 meta-research 作为初始技能'); | |
| 140 | + } | |
| 141 | + | |
| 142 | + // 3c: 复制 base config.json (restricted 工具策略) | |
| 143 | + const baseConfig = path.join(ROOT, 'data/system/templates/base/config.json'); | |
| 144 | + const agentConfig = path.join(agentDir, 'config.json'); | |
| 145 | + if (fs.existsSync(baseConfig) && fs.existsSync(agentDir)) { | |
| 146 | + const existingConfig = fs.existsSync(agentConfig) ? JSON.parse(fs.readFileSync(agentConfig, 'utf-8')) : {}; | |
| 147 | + const baseData = JSON.parse(fs.readFileSync(baseConfig, 'utf-8')); | |
| 148 | + const merged = { ...existingConfig, ...baseData, id: WORKER_ROLE }; | |
| 149 | + fs.writeFileSync(agentConfig, JSON.stringify(merged, null, 2), 'utf-8'); | |
| 150 | + ok(`config.json 已合并 restricted 工具策略: ${JSON.stringify(merged.cli?.toolPolicy?.mode)}`); | |
| 151 | + } | |
| 152 | + | |
| 153 | + // ────────────────────────────────────── | |
| 154 | + // Step 4: 派发 P1 开发任务 | |
| 155 | + // ────────────────────────────────────── | |
| 156 | + step(4, '派发 P1 开发任务'); | |
| 157 | + const taskRes = await post('/agent/task/dispatch', { | |
| 158 | + from: `${COMPANY_ID}:ceo`, | |
| 159 | + to: WORKER_ID, | |
| 160 | + task: '请帮我调研一下项目 server/routes/ 目录下所有的 API 路由文件,统计有多少个 GET/POST/PUT/DELETE 端点,然后写一个简洁的 API 清单文档。', | |
| 161 | + priority: 'P1', | |
| 162 | + autoExecute: false, // 不自动执行, 我们手动控制流转 | |
| 163 | + }); | |
| 164 | + if (taskRes.status === 200 && taskRes.data?.taskId) { | |
| 165 | + ok(`任务已派发: ${taskRes.data.taskId}`); | |
| 166 | + } else { | |
| 167 | + warn(`派发结果: ${JSON.stringify(taskRes.data)}`); | |
| 168 | + } | |
| 169 | + | |
| 170 | + // ────────────────────────────────────── | |
| 171 | + // Step 5: 模拟四阶段流转 | |
| 172 | + // ────────────────────────────────────── | |
| 173 | + step(5, '模拟四阶段流转 (Research → Plan → Execute → Verify)'); | |
| 174 | + | |
| 175 | + const phases = ['plan', 'execute', 'verify']; | |
| 176 | + const phaseNames = { plan: '规划', execute: '执行', verify: '验证' }; | |
| 177 | + const skillNames = { plan: 'meta-plan', execute: 'meta-execute', verify: 'meta-verify' }; | |
| 178 | + | |
| 179 | + // 当前处于 Research 阶段, 模拟产出 _research.md | |
| 180 | + const wsDir = path.join(agentDir, 'workspace'); | |
| 181 | + if (!fs.existsSync(wsDir)) fs.mkdirSync(wsDir, { recursive: true }); | |
| 182 | + fs.writeFileSync(path.join(wsDir, '_research.md'), `# 调研结果 | |
| 183 | +- server/routes/ 中有约 10 个 API 路由文件 | |
| 184 | +- 主要模块: agent-chat.js, company.js, goals.js, evolution.js 等 | |
| 185 | +- 估计有 60+ 个 REST endpoint | |
| 186 | +`, 'utf-8'); | |
| 187 | + ok('Research 阶段: 已产出 workspace/_research.md'); | |
| 188 | + | |
| 189 | + for (const phase of phases) { | |
| 190 | + console.log(`\n 🔄 触发 transition → ${phase} (${phaseNames[phase]})`); | |
| 191 | + | |
| 192 | + const trRes = await post(`/agent/${WORKER_ID}/task/transition`, { | |
| 193 | + phase, | |
| 194 | + artifact: phase === 'plan' ? 'workspace/_research.md' : (phase === 'execute' ? 'workspace/_plan.md' : ''), | |
| 195 | + }); | |
| 196 | + | |
| 197 | + if (trRes.status === 200 && trRes.data?.success) { | |
| 198 | + ok(`Transition → ${phase} 成功: ${trRes.data.message}`); | |
| 199 | + } else { | |
| 200 | + fail(`Transition → ${phase} 失败: ${JSON.stringify(trRes.data)}`); | |
| 201 | + continue; | |
| 202 | + } | |
| 203 | + | |
| 204 | + // 验证 SKILL.md 被替换 | |
| 205 | + await sleep(500); | |
| 206 | + if (fs.existsSync(mainSkillPath)) { | |
| 207 | + const content = fs.readFileSync(mainSkillPath, 'utf-8'); | |
| 208 | + if (content.includes(skillNames[phase])) { | |
| 209 | + ok(`SKILL.md 已切换为 ${skillNames[phase]}`); | |
| 210 | + } else { | |
| 211 | + warn(`SKILL.md 内容未包含 ${skillNames[phase]} 关键词`); | |
| 212 | + } | |
| 213 | + } | |
| 214 | + | |
| 215 | + // 模拟该阶段的产出 (只有 plan 阶段写 _plan.md) | |
| 216 | + if (phase === 'plan') { | |
| 217 | + fs.writeFileSync(path.join(wsDir, '_plan.md'), `# 执行计划 | |
| 218 | +1. 遍历 server/routes/*.js 文件 | |
| 219 | +2. 用正则提取 router.get/post/put/delete 端点 | |
| 220 | +3. 聚合为 Markdown 表格输出到 workspace/api-inventory.md | |
| 221 | +`, 'utf-8'); | |
| 222 | + ok('Plan 阶段: 已产出 workspace/_plan.md'); | |
| 223 | + } | |
| 224 | + | |
| 225 | + if (phase === 'execute') { | |
| 226 | + fs.writeFileSync(path.join(wsDir, 'api-inventory.md'), `# API 清单 | |
| 227 | +| 方法 | 路径 | 模块 | | |
| 228 | +|------|------|------| | |
| 229 | +| GET | /api/agent/list | agent-chat.js | | |
| 230 | +| POST | /api/agent/:id/chat | agent-chat.js | | |
| 231 | +| POST | /api/company/create | company.js | | |
| 232 | +| ... | ... | ... | | |
| 233 | +`, 'utf-8'); | |
| 234 | + ok('Execute 阶段: 已产出 workspace/api-inventory.md'); | |
| 235 | + } | |
| 236 | + } | |
| 237 | + | |
| 238 | + // ────────────────────────────────────── | |
| 239 | + // Step 6: 最终检查 | |
| 240 | + // ────────────────────────────────────── | |
| 241 | + step(6, '最终检查'); | |
| 242 | + | |
| 243 | + // 检查所有产出文件 | |
| 244 | + const expectedFiles = ['_research.md', '_plan.md', 'api-inventory.md']; | |
| 245 | + for (const f of expectedFiles) { | |
| 246 | + const fp = path.join(wsDir, f); | |
| 247 | + if (fs.existsSync(fp)) { | |
| 248 | + const size = fs.statSync(fp).size; | |
| 249 | + ok(`${f} 存在 (${size} bytes)`); | |
| 250 | + } else { | |
| 251 | + fail(`${f} 缺失`); | |
| 252 | + } | |
| 253 | + } | |
| 254 | + | |
| 255 | + // 检查当前挂载的技能是 meta-verify | |
| 256 | + if (fs.existsSync(mainSkillPath)) { | |
| 257 | + const finalSkill = fs.readFileSync(mainSkillPath, 'utf-8'); | |
| 258 | + if (finalSkill.includes('meta-verify')) { | |
| 259 | + ok('最终技能树: meta-verify ✓ (验证阶段)'); | |
| 260 | + } else { | |
| 261 | + warn('最终技能树不是 meta-verify'); | |
| 262 | + } | |
| 263 | + } | |
| 264 | + | |
| 265 | + // 检查 billing.log | |
| 266 | + const billingPath = path.join(ROOT, 'data/logs/billing.log'); | |
| 267 | + if (fs.existsSync(billingPath)) { | |
| 268 | + ok(`billing.log 存在 (${fs.statSync(billingPath).size} bytes)`); | |
| 269 | + } else { | |
| 270 | + warn('billing.log 尚未产生 (需要真实 Agent 对话才会写入)'); | |
| 271 | + } | |
| 272 | + | |
| 273 | + banner('🎉 演练完成!AI ToolBox 四阶段流转验证通过'); | |
| 274 | + | |
| 275 | + console.log(` | |
| 276 | +📋 验证清单: | |
| 277 | + ✅ 公司创建 + 员工招聘 (aitoolbox:feature-dev) | |
| 278 | + ✅ Base Agent 规范注入 (agent.md + config.json restricted) | |
| 279 | + ✅ 初始技能挂载 (meta-research) | |
| 280 | + ✅ Transition API: research → plan → execute → verify | |
| 281 | + ✅ 每次 Transition 的 Hot Swap 换脑验证 | |
| 282 | + ✅ 各阶段 Artifact 产出 (_research.md / _plan.md / api-inventory.md) | |
| 283 | + | |
| 284 | +📂 公司目录: data/companies/${COMPANY_ID}/ | |
| 285 | +📂 员工目录: data/companies/${COMPANY_ID}/agents/${WORKER_ROLE}/ | |
| 286 | + | |
| 287 | +💡 接下来你可以: | |
| 288 | + 1. 用 UI 打开 ${WORKER_ID} 跟它对话,观察它的受限行为 | |
| 289 | + 2. 派发一个 P0 任务测试审批拦截: | |
| 290 | + node bin/lemon.js task dispatch --from ${COMPANY_ID}:ceo --to ${WORKER_ID} --task "重构核心架构" --priority P0 | |
| 291 | + 3. 查看 billing.log: cat data/logs/billing.log | |
| 292 | +`); | |
| 293 | +} | |
| 294 | + | |
| 295 | +main().catch(err => { | |
| 296 | + console.error('❌ 脚本执行错误:', err.message); | |
| 297 | + process.exit(1); | |
| 298 | +}); | ... | ... |