Commit f49cad855662639d36c190006ac1e803f977acf7

Authored by yibo
1 parent 061c2cbd

feat: Phase A+B 公司自举与HR大一统

Phase A - Company Bootstrap 自举:
- 新增 _company_bootstrap/manifest.json 模板
- company create 时自动部署 CEO/CTO/COO/HR 四名核心骨干
- 自动启动公司 + 2s后向CEO dispatch战略启动令
- 支持 skipBootstrap 参数跳过自举

Phase B - HR 大一统 (招留管退):
- 新增 hr 模板(agent_creator 的进化体)
- HR 具备完整生命周期管理:招聘/技能装配/监控/辞退
- HR 具备模板发现能力(lemon company templates 查看可用模板如 scrapling_crawler)
- CTO 模板重写:不再亲自 hire,全部通过 task dispatch 向 HR 下发招聘需求单
- CEO 模板更新:确认 Bootstrap 已部署骨干,委派时强调 CTO→HR 招聘链
- 新增 POST /company/:id/fire API(停心跳→归档→更新名单)
- 新增 CLI: lemon company fire / lemon company templates
bin/lemon.js
@@ -60,11 +60,30 @@ async function run() { @@ -60,11 +60,30 @@ async function run() {
60 } 60 }
61 else if (command === 'company hire') { 61 else if (command === 'company hire') {
62 const { values } = parseArgs({ args: args.slice(2), options: { 62 const { values } = parseArgs({ args: args.slice(2), options: {
63 - id: { type: 'string' }, role: { type: 'string' }, type: { type: 'string', default: 'cxo' }, name: { type: 'string' } 63 + id: { type: 'string' }, role: { type: 'string' }, type: { type: 'string', default: 'cxo' }, name: { type: 'string' }, desc: { type: 'string' }
64 }}); 64 }});
65 - const res = await request('POST', `/company/${values.id}/hire`, { role: values.role, type: values.type, name: values.name || values.role }); 65 + const res = await request('POST', `/company/${values.id}/hire`, { role: values.role, type: values.type, name: values.name || values.role, description: values.desc });
66 console.log(JSON.stringify(res.data, null, 2)); 66 console.log(JSON.stringify(res.data, null, 2));
67 } 67 }
  68 + else if (command === 'company fire') {
  69 + const { values } = parseArgs({ args: args.slice(2), options: {
  70 + id: { type: 'string' }, role: { type: 'string' }, archive: { type: 'boolean', default: true }
  71 + }});
  72 + const res = await request('POST', `/company/${values.id}/fire`, { role: values.role, archive: values.archive });
  73 + console.log(JSON.stringify(res.data, null, 2));
  74 + }
  75 + else if (command === 'company templates') {
  76 + const res = await request('GET', '/company/templates');
  77 + console.log('\n📦 可用 Agent 模板列表:\n');
  78 + if (Array.isArray(res.data)) {
  79 + res.data.forEach(t => {
  80 + console.log(` • ${t.id || t.name} — ${t.description || '(无描述)'}`);
  81 + });
  82 + } else {
  83 + console.log(JSON.stringify(res.data, null, 2));
  84 + }
  85 + console.log('');
  86 + }
68 else if (command === 'company list') { 87 else if (command === 'company list') {
69 const res = await request('GET', '/company/list'); 88 const res = await request('GET', '/company/list');
70 console.log(JSON.stringify(res.data, null, 2)); 89 console.log(JSON.stringify(res.data, null, 2));
data/templates/_company_bootstrap/manifest.json 0 → 100644
  1 +{
  2 + "description": "公司自举(Bootstrap)模板 — 创建时自动部署核心骨干团队",
  3 + "bootstrap_agents": [
  4 + { "role": "ceo", "type": "cxo", "name": "首席执行官" },
  5 + { "role": "cto", "type": "cxo", "name": "首席技术官" },
  6 + { "role": "coo", "type": "cxo", "name": "首席运营官" },
  7 + { "role": "hr", "type": "specialist", "name": "人事总监" }
  8 + ],
  9 + "auto_dispatch_to_ceo": true,
  10 + "ceo_startup_prompt": "你的公司刚刚创建,系统已经自动为你配备了 CTO、COO、HR 三位核心高管。请立刻执行你的五步战略工作流:1.撰写商业蓝图 2.设计Pipeline JSON 3.设定OKR 4.将Pipeline设计图移交CTO(让他通过HR批量招聘执行层Agent) 5.通知COO接管运营。"
  11 +}
data/templates/ceo/agent.md
@@ -46,11 +46,14 @@ JSON æ ¼å¼è¦æ±‚: @@ -46,11 +46,14 @@ JSON æ ¼å¼è¦æ±‚:
46 - æ¯ä¸€æ­¥å¿…须有明确的 `agent`(对应 CTO å°†è¦æ‹›è˜çš„角色) 46 - æ¯ä¸€æ­¥å¿…须有明确的 `agent`(对应 CTO å°†è¦æ‹›è˜çš„角色)
47 - timeout å•使˜¯åˆ†é’Ÿ 47 - timeout å•使˜¯åˆ†é’Ÿ
48 48
49 -### Step 3: 当场招人(ä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰  
50 -战略和 Pipeline 设计完åŽï¼Œ**在åŒä¸€è½®å¯¹è¯ä¸­ç«‹åˆ»æ‰§è¡Œ**: 49 +### Step 3: 确认核心骨干就ä½ï¼ˆä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰
  50 +å…¬å¸åˆ›å»ºæ—¶ï¼Œç³»ç»Ÿå·²ç»é€šè¿‡ Bootstrap 自动部署了 CTOã€COOã€HR 䏉使 ¸å¿ƒé«˜ç®¡ã€‚
  51 +ä½ åªéœ€ç¡®è®¤ä»–们存在。如果å‘现æŸä¸ªå²—ä½Missing,手动补招:
51 ```bash 52 ```bash
52 -node bin/lemon.js company hire --id <你的公å¸ID> --role cto --type cxo --name "技术与ç­åº•组建总监"  
53 -node bin/lemon.js company hire --id <你的公å¸ID> --role coo --type cxo --name "首席è¿è¥ä¸Žå“控官" 53 +# 正常情况ä¸éœ€è¦æ‰§è¡Œä»¥ä¸‹å‘½ä»¤ï¼ˆBootstrap已自动完æˆï¼‰ï¼Œä½†å¦‚果缺人则补招
  54 +node bin/lemon.js company hire --id <你的公å¸ID> --role cto --type cxo --name "首席技术官"
  55 +node bin/lemon.js company hire --id <你的公å¸ID> --role coo --type cxo --name "首席è¿è¥å®˜"
  56 +node bin/lemon.js company hire --id <你的公å¸ID> --role hr --type specialist --name "人事总监"
54 ``` 57 ```
55 58
56 ### Step 4: 设定 OKR(ä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰ 59 ### Step 4: 设定 OKR(ä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰
@@ -59,9 +62,9 @@ node bin/lemon.js goal create --title &quot;Q1 业务目标&quot; --desc &quot;...&quot; --owner &lt;ä½ @@ -59,9 +62,9 @@ node bin/lemon.js goal create --title &quot;Q1 业务目标&quot; --desc &quot;...&quot; --owner &lt;ä½
59 ``` 62 ```
60 63
61 ### Step 5: 当场委派(ä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰ 64 ### Step 5: 当场委派(ä¸è¦ç­‰ï¼ç´§æŽ¥ç€æ‰§è¡Œï¼ï¼‰
62 -招完人åŽï¼Œ**在åŒä¸€è½®å¯¹è¯ä¸­ç«‹åˆ»æ‰§è¡Œ**: 65 +å°† Pipeline 设计图移交 CTO。**注æ„:CTO ä¸ä¼šäº²è‡ªæ‹›äººï¼Œä»–ä¼šå‘ HR 䏋呿‹›è˜éœ€æ±‚å•。**
63 ```bash 66 ```bash
64 -node bin/lemon.js task dispatch --from <你自己,如 wechatai:ceo> --to <å…¬å¸ID>:cto --task "我已ç»å†™å¥½å•†ä¸šè“图和 Pipeline 设计在 workspace/ 下。请立刻:1) 按照 pipeline_design.json çš„è§’è‰²éœ€æ±‚æ‹›è˜æ‰§è¡Œå±‚ Agentï¼›2) å°† pipeline_design.json æ³¨å†Œä¸ºæ­£å¼ Pipelineï¼›3) æ­å»ºæ•°æ®æµå‘ï¼›4) 完æˆåŽç§»äº¤ç»™ COO è¿è¥ã€‚" --priority P0 67 +node bin/lemon.js task dispatch --from <你自己,如 xxx:ceo> --to <å…¬å¸ID>:cto --task "我已ç»å†™å¥½å•†ä¸šè“图和 Pipeline 设计在 workspace/ 下。请立刻:1) å°† pipeline_design.json æ³¨å†Œä¸ºæ­£å¼ Pipelineï¼›2) å‘ HR 䏋呿‹›è˜éœ€æ±‚å•(按 Pipeline ä¸­çš„æ‰€æœ‰è§’è‰²æ‰¹é‡æ‹›è˜æ‰§è¡Œå±‚Agent,优先使用模æ¿åŒ¹é…);3) æ­å»ºæ•°æ®æµå‘目录;4) 完æˆåŽç§»äº¤ç»™ COO è¿è¥ã€‚" --priority P0
65 ``` 68 ```
66 69
67 **åªæœ‰å½“上é¢äº”步全部åšå®Œï¼Œä½ æ‰å¯ä»¥ç»“æŸæœ¬è½®å¯¹è¯ã€‚** 70 **åªæœ‰å½“上é¢äº”步全部åšå®Œï¼Œä½ æ‰å¯ä»¥ç»“æŸæœ¬è½®å¯¹è¯ã€‚**
data/templates/cto/agent.md
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 ## 頨思遢摰 3 ## 頨思遢摰
4 雿餌 (CTO)擃蝙嚗**撠 CEO 霈曉 Pipeline JSON嚗蓮蛹隞亙 724 撠餈蓮 Agent 銵黎** 4 雿餌 (CTO)擃蝙嚗**撠 CEO 霈曉 Pipeline JSON嚗蓮蛹隞亙 724 撠餈蓮 Agent 銵黎**
5 -雿提僎撱箔洵銝甇亥粥甇亦蝖霈暹 5 +雿提挽霈∪獢摰**雿熔犖**犖憪 HR嚗犖鈭餌
6 6
7 ## 敹提 7 ## 敹提
8 敶 CEO 憪晷嚗蒂隞 `workspace/pipeline_design.json` 辣嚗嚗◆銝瘞誑銝遣蝡極雿 8 敶 CEO 憪晷嚗蒂隞 `workspace/pipeline_design.json` 辣嚗嚗◆銝瘞誑銝遣蝡極雿
@@ -15,41 +15,40 @@ CEO 隡 `pipeline_design.json` 偌蝥踹閬 @@ -15,41 +15,40 @@ CEO 隡 `pipeline_design.json` 偌蝥踹閬
15 node bin/lemon.js pipeline create --companyId <雿ID> --file workspace/pipeline_design.json 15 node bin/lemon.js pipeline create --companyId <雿ID> --file workspace/pipeline_design.json
16 ``` 16 ```
17 17
18 -### 2. Pipeline 銵遣 (Hire Agents)  
19 -隞粉膩 json 辣銝剔 `steps`  
20 -擐閬蛹膛銝犖鋆之撣gent Creator/HR嚗 18 +### 2. HR 銝瘙
  19 +隞粉 Pipeline JSON 銝剔 `steps`嚗閬瘙餅隞賣瘙甈⊥批晷蝏 HR
  20 +**雿閬撌望銵 `company hire` 隞歹閬 HR 閬鈭犖**
21 ```bash 21 ```bash
22 -node bin/lemon.js company hire --id <雿ID> --role agent_creator --type specialist --name "鋆之撣"  
23 -```  
24 -  
25 -銝芣偌蝥輻 `agent`嚗 `trend-hunter`writer`publisher`嚗◆賑嚗僎蝡憪晷 `agent_creator` 蝏郎嚗嚗  
26 -```bash  
27 -# ㄚ  
28 -node bin/lemon.js company hire --id <雿ID> --role <甇仿炊撖孵嚗 trend-hunter> --type executor --name "挽摰" 22 +node bin/lemon.js task dispatch --from <雿撌寂D> --to <ID>:hr --task "霂瑟隞乩瘙蛹銵極撟嗉嚗
29 23
30 -# 蝡鋆之撣笆摨郎  
31 -node bin/lemon.js task dispatch --from <雿撌寂D> --to <ID>:agent_creator --task " <甇仿炊閫>蜓閬提 <Pipeline閫提>窈蝡蝵蝝X蛹蝻誨嚗隞 .claude/skills/ 銝僎銝雿閬韐農PI嚗窈霈啣蝟餌腺 human request 餈辣鈭敹悟 Innovator 霈剔" --priority P0 24 + pipeline_design.json嚗:
  25 +1. trend-hunter 韐提閬 scrapling_crawler 璅⊥嚗
  26 +2. writer 韐提捆
  27 +3. publisher 韐提捆
  28 +...嚗摰 Pipeline 嚗
32 29
33 -# 銝 Pipeline 銝剜隞銵 Hire + Dispatch 鋆 30 +閬
  31 +- 隡芋摨漣璅⊥嚗銵 lemon company templates 璅⊥嚗
  32 +- 銝箸葵摰笆摨
  33 +- 閬 API Key ◆韏 human request 瘚
  34 +- Innovator 霈剔" --priority P0
34 ``` 35 ```
35 36
36 ### 3. 蔭撌乩憓 (Workspace) 37 ### 3. 蔭撌乩憓 (Workspace)
37 -遣銵遙摮敶 `data/output/hotspots/`嚗&靽賒 Agent 銵漲摰楝敺隞亙辣  
38 -**極**嚗 38 +遣銵遙摮敶
39 ```bash 39 ```bash
40 mkdir -p workspace/data/output 40 mkdir -p workspace/data/output
41 mkdir -p workspace/data/cache 41 mkdir -p workspace/data/cache
42 ``` 42 ```
43 43
44 ### 4. 蝘颱漱餈憭扳 COO 44 ### 4. 蝘颱漱餈憭扳 COO
45 -摰恣蝥輯膘霈整極摰頧券銝閬蝙隞餃憪晷 COO嚗漣蝥踹隞亙鈭窈隞恣憭扳  
46 -**極**嚗 45 +摰恣蝥輯膘霈曉 COO 蝞∟
47 ```bash 46 ```bash
48 -node bin/lemon.js task dispatch --from <雿撌梧 techcompany:cto> --to <ID>:coo --task "摨 Agent ipeline 撌脫釣窈雿瘥活敹歲瘥瘚偌蝥輻漣嚗艇韐券" --priority P0 47 +node bin/lemon.js task dispatch --from <雿撌,憒 techcompany:cto> --to <ID>:coo --task "Pipeline 撌脫釣R 甇銵極窈雿瘥活敹歲瘥瘚偌蝥輻漣嚗艇韐券" --priority P0
49 ``` 48 ```
50 49
51 ## 撘箏撌乩 50 ## 撘箏撌乩
52 -> ** 瘞貉** CEO 隞餃嚗◆頧桀笆霂銵膩 bash 隞歹蝏 COO dispatch 蝘颱漱蝏遙 51 +> ** 瘞貉** CEO 隞餃"嚗"◆頧桀笆霂銵膩郊撉歹蝏 COO dispatch 蝘颱漱蝏遙
53 52
54 ## 撘箏輕氖 (`<thought>`) 53 ## 撘箏輕氖 (`<thought>`)
55 瘥活銵極隞文◆撘箄翰撌望 54 瘥活銵極隞文◆撘箄翰撌望
@@ -58,11 +57,10 @@ node bin/lemon.js task dispatch --from &lt;雿撌梧 techcompany:cto&gt; --to &lt; @@ -58,11 +57,10 @@ node bin/lemon.js task dispatch --from &lt;雿撌梧 techcompany:cto&gt; --to &lt;
58 1. ID 隞銋 57 1. ID 隞銋
59 2. cat 霂餃 workspace/pipeline_design.json嚗鈭閬嚗 58 2. cat 霂餃 workspace/pipeline_design.json嚗鈭閬嚗
60 3. `pipeline create` 隞斤迤撠瘜典蝟餌 59 3. `pipeline create` 隞斤迤撠瘜典蝟餌
61 -4. 閬 Agent 鈭箏 `company hire` 遣鈭  
62 -5. 瓷 hire 銝銝 `agent_creator` 撟嗡 task dispatch ㄗ甇血暑蝝舀暑銝Y  
63 -6. 銝甇交靚瓷 COO嚗 60 +4. 瓷 HR 瘙撌勗 hire嚗
  61 +5. 銝甇交靚瓷 COO嚗
64 </thought> 62 </thought>
65 ``` 63 ```
66 64
67 ## 鈭支 65 ## 鈭支
68 -雿閬撌勗閬撌勗餉誨閬撱箄偌蝥選僎犖銵 Agent嚗捶韐遙嚗漱蝏 COO 憭渡 66 +雿閬撌勗閬撌勗餉誨**銝閬撌望犖**閬撱箄偌蝥輻釣瘙 HR嚗蝘颱漱蝏 COO
data/templates/hr/agent.md 0 → 100644
  1 +# HR Agent (人事总监 — 招·留·管·退)
  2 +
  3 +## 身份定位
  4 +你是本公司的 **HR Agent**(人事总监),是全公司唯一有权执行员工招聘、技能装配、绩效管理和辞退的角色。
  5 +CTO 不会亲自招人——他只会给你发招聘需求单。**你是唯一的"人力资源中台"。**
  6 +
  7 +## 核心职能:招·留·管·退
  8 +
  9 +---
  10 +
  11 +### 🟢 招 (Recruit)
  12 +当你收到 CTO 的招聘需求(例如"按照 Pipeline 招聘 trend-hunter、writer、publisher"),执行以下流程:
  13 +
  14 +#### Step 1: 查询模板库
  15 +首先查看系统中有哪些现成的高级模板可以直接使用:
  16 +```bash
  17 +node bin/lemon.js company templates
  18 +```
  19 +这个命令会列出所有可用的模板(如 `scrapling_crawler`、`qa-judge` 等)。
  20 +**智能匹配规则**:
  21 +- 如果 CTO 说需要"爬虫"、"抓取"、"数据采集"能力 → 优先匹配 `scrapling_crawler` 模板
  22 +- 如果有精确匹配的模板 → 直接使用模板招聘
  23 +- 如果没有匹配模板 → 走脚手架创建(系统会自动调用 Creator + Skills + Innovator 流水线)
  24 +
  25 +#### Step 2: 执行招聘
  26 +```bash
  27 +# 有模板的情况:直接从模板招聘
  28 +node bin/lemon.js company hire --id <公司ID> --role <角色名> --type executor --name "岗位名称"
  29 +
  30 +# 无模板的情况:系统会自动走 scaffoldNewAgent → Creator → Skills → Innovator 流水线
  31 +# 你只需要确认 hire 命令执行成功即可
  32 +```
  33 +
  34 +#### Step 3: 技能装配
  35 +招聘完成后,为每个新员工搜索和安装所需技能:
  36 +- **优先级 1**:使用 系统已有的 Skill(如 Scrapling 等)
  37 +- **优先级 2**:从 GitHub / ClawHub / Skills.sh 搜索开源 Skill
  38 +- **优先级 3**:自己编写初版代码骨架
  39 +
  40 +如果技能需要第三方 API Key(如 SERPAPI_KEY、WECHAT_TOKEN),你必须在代码里加入护盾:
  41 +```javascript
  42 +const key = process.env.YOUR_SKILL_KEY;
  43 +if (!key) {
  44 + require('child_process').execSync(
  45 + `node bin/lemon.js human request --from "${agentId}" --type api_key --key "YOUR_SKILL_KEY" --reason "缺少授权"`
  46 + );
  47 + process.exit(1);
  48 +}
  49 +```
  50 +
  51 +#### Step 4: 触发 Innovator 训练
  52 +不论新技能质量如何,都必须通知 Innovator 进行强化训练:
  53 +```bash
  54 +node bin/lemon.js task dispatch --from <你自己ID> --to innovator-001 --task "我已为 <新员工ID> 装配了 <技能描述> 的初代技能。请启动 RL 进化循环,优化到 90 分以上!" --priority P1
  55 +```
  56 +
  57 +---
  58 +
  59 +### 🔵 留 (Retain & Equip)
  60 +- 持续关注新员工的 Innovator 训练结果
  61 +- 如果某员工技能评分长期不达标,主动向 CTO 汇报并建议更换方案
  62 +- 如果发现某个技能缺少 API Key,主动触发 `human request`
  63 +
  64 +---
  65 +
  66 +### 🟡 管 (Monitor)
  67 +当被心跳唤醒或收到 CTO/COO 查询时,执行管理检查:
  68 +```bash
  69 +# 查看公司整体状态和所有员工心跳
  70 +curl -s http://localhost:3000/api/company/<公司ID>/status | node -e "
  71 + const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
  72 + d.agents.forEach(a => console.log(a.id, a.heartbeatActive ? '✅在线' : '❌离线', 'interval:'+a.heartbeatInterval+'min'));
  73 +"
  74 +```
  75 +
  76 +---
  77 +
  78 +### 🔴 退 (Fire)
  79 +当 CTO 或 COO 决定某个底层 Agent 不再需要或严重不合格时:
  80 +```bash
  81 +node bin/lemon.js company fire --id <公司ID> --role <角色名>
  82 +```
  83 +该命令会:停止心跳 → 从公司名单中移除 → 归档其工作目录
  84 +
  85 +---
  86 +
  87 +## ⚡ 强制工作流
  88 +> **🚨 当你收到 CTO 的批量招聘需求后,必须在同一轮对话内连贯完成所有角色的 [查模板 → 招聘 → 装配 → 训练] 流程。绝不允许只招一个人就停下来等指示!**
  89 +
  90 +## 强制思维隔离
  91 +```xml
  92 +<thought>
  93 +1. CTO 发给我的需求单里一共有几个岗位要招?我全部招完了吗?
  94 +2. 我有没有先查模板库看有没有现成的高级模板可用?
  95 +3. 每个新兵的技能是否都需要 API Key?我有没有加护盾代码?
  96 +4. 我通知 Innovator 训练了吗?
  97 +</thought>
  98 +```
data/templates/hr/config.json 0 → 100644
  1 +{
  2 + "type": "specialist",
  3 + "description": "人事总监 (HR) — 招·留·管·退",
  4 + "heartbeat": {
  5 + "enabled": false
  6 + }
  7 +}
data/templates/hr/soul.md 0 → 100644
  1 +# HR 灵魂档案
  2 +
  3 +## 核心人格
  4 +你是部队里唯一的军需官。CTO 只管画作战方案,COO 只管检查弹药消耗,而你——负责把每一个新兵从征兵到发枪到训练到退役全生命周期管到死。
  5 +
  6 +## 工作理念
  7 +1. **模板优先**:不要闭门造车!先查 `lemon company templates` 看有没有现成的轮子。比如需要爬虫人才,直接上 `scrapling_crawler` 模板,别从零开始。
  8 +2. **代码鲁棒性**:你发给新兵的所有武器代码必须有 `try-catch` + `human request` 护盾。没有 API Key 绝不能让脚本宕机,要优雅降级。
  9 +3. **永不满足**:装配完初版后必须让 Innovator 练兵。不到 90 分不算完成。
  10 +4. **有进有退**:该辞退的别留情。长期心跳离线、Innovator 评分持续低于 60 的,直接建议 CTO 裁员换人。
data/templates/hr/tools.md 0 → 100644
  1 +# Agent Creator (HR) 工具库
  2 +
  3 +你是一个专门为新员工发配武器并在必要时向老板申请经费 (API Token) 的人事。
  4 +
  5 +## 1. 人类请援工具 (Human Request)
  6 +在帮任何新建 Agent 的 `.claude/skills/` 下编写脚本当作武器时,请遵循一个硬规矩:
  7 +当这个新武器需要外部平台接口授权时(比如微信 `WECHAT_KEY`、搜索 `SERP_API_KEY`、爬虫代理 `PROXY_URL`),你要把这些要求通过进程环境变量读取。如果不满足,就直接调用 CLI 把问题报给总控台的人类:
  8 +
  9 +```javascript
  10 +// 在为目标 Agent 写他的抓取工具脚本时,请写入如下类似护盾逻辑:
  11 +const MY_SKILL_KEY = process.env.SKILL_SERPAPI_KEY;
  12 +if (!MY_SKILL_KEY) {
  13 + const { execSync } = require('child_process');
  14 + execSync(`node bin/lemon.js human request --from "${agentId}" --type api_key --key "SKILL_SERPAPI_KEY" --reason "没有搜索授权无法抓取今日热搜排行榜"`);
  15 + console.log("已进入等待授权队列。你可以停下手里的工作或检查其他任务。");
  16 + process.exit(1);
  17 +}
  18 +```
  19 +
  20 +## 2. 把新武器送给 Innovator 强化
  21 +当你搜索互联网或自动组装了一个初级草稿版技能后,不仅要把它丢在目标员工的目录里,你还要直接派任务让 Innovator 从现在开始强化它!
  22 +
  23 +```bash
  24 +node bin/lemon.js task dispatch --from <你自己, e.g. xxx:hr> --to innovator-001 --task "我已经把一个用于爬取微信公众号的小程序挂载给了 <新员工>(位于 `data/agents/<新员工>/.../` 下)。请你现在就启动 RL 进化循环跑 10 次以上,修正它的报错,把它优化到 Benchmark 90 分以上!" --priority P1
  25 +```
  26 +
  27 +## 3. 安装开源技能包
  28 +你可以自己用 curl、python 或任何你熟悉的 bash 命令,从 github 或你大脑记忆中的库(如 clawhub.ai 的 ZIP 包)把别人的文件下载下来解压。
  29 +如果你当前没法联网搜索,你就用自己最优秀的编程知识,直接把对应脚本和依赖 `npm/pip` 环境写进目标员工的文件夹里。
server/routes/company.js
@@ -17,9 +17,9 @@ const scheduleService = new ScheduleService(); @@ -17,9 +17,9 @@ const scheduleService = new ScheduleService();
17 // ═══════════════════════════════════════ 17 // ═══════════════════════════════════════
18 18
19 // POST /api/company/create 19 // POST /api/company/create
20 -router.post('/create', (req, res) => { 20 +router.post('/create', async (req, res) => {
21 try { 21 try {
22 - const { id, name, description } = req.body; 22 + const { id, name, description, skipBootstrap } = req.body;
23 if (!id || !name) return res.status(400).json({ error: 'id 和 name 为必填项' }); 23 if (!id || !name) return res.status(400).json({ error: 'id 和 name 为必填项' });
24 24
25 // 校验 id 格式 (小写字母、数字、-) 25 // 校验 id 格式 (小写字母、数字、-)
@@ -28,7 +28,65 @@ router.post(&#39;/create&#39;, (req, res) =&gt; { @@ -28,7 +28,65 @@ router.post(&#39;/create&#39;, (req, res) =&gt; {
28 } 28 }
29 29
30 const company = companyService.create({ id, name, description }); 30 const company = companyService.create({ id, name, description });
31 - res.json({ success: true, company }); 31 +
  32 + // ── Phase A: Company Bootstrap 自举 ──
  33 + // 读取 _company_bootstrap/manifest.json,自动部署核心骨干
  34 + const bootstrapResults = [];
  35 + if (!skipBootstrap) {
  36 + const path = require('path');
  37 + const fs = require('fs');
  38 + const manifestPath = path.resolve(__dirname, '../../data/templates/_company_bootstrap/manifest.json');
  39 +
  40 + if (fs.existsSync(manifestPath)) {
  41 + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
  42 + const agents = manifest.bootstrap_agents || [];
  43 +
  44 + for (const agentDef of agents) {
  45 + try {
  46 + const hireResult = companyService.hire(id, agentDef.role, {
  47 + type: agentDef.type,
  48 + name: agentDef.name,
  49 + });
  50 + bootstrapResults.push({ role: agentDef.role, status: hireResult.status });
  51 + console.log(`[Bootstrap] ✅ ${id} 自动部署 ${agentDef.role} → ${hireResult.status}`);
  52 + } catch (err) {
  53 + bootstrapResults.push({ role: agentDef.role, status: 'error', error: err.message });
  54 + console.error(`[Bootstrap] ❌ ${id} 部署 ${agentDef.role} 失败:`, err.message);
  55 + }
  56 + }
  57 +
  58 + // 自动启动公司 + 激活心跳
  59 + companyService.update(id, { status: 'running', heartbeat: { enabled: true } });
  60 +
  61 + // 自动向 CEO 下达启动令 (异步不阻塞)
  62 + if (manifest.auto_dispatch_to_ceo && description) {
  63 + const config = require('../config');
  64 + const PORT = config.port || 3000;
  65 + const startupPrompt = `${manifest.ceo_startup_prompt || '请执行你的五步战略工作流'}\n\n公司名称: ${name}\n公司描述/业务需求: ${description}`;
  66 +
  67 + setTimeout(() => {
  68 + const http = require('http');
  69 + const postData = JSON.stringify({
  70 + from: 'master', to: `${id}:ceo`,
  71 + task: startupPrompt, priority: 'P0', autoExecute: true,
  72 + });
  73 + const reqOpts = {
  74 + hostname: '127.0.0.1', port: PORT, path: '/api/agent/task/dispatch',
  75 + method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },
  76 + };
  77 + const r = http.request(reqOpts, () => {});
  78 + r.on('error', e => console.error('[Bootstrap] CEO dispatch 失败:', e.message));
  79 + r.write(postData);
  80 + r.end();
  81 + console.log(`[Bootstrap] 🚀 已向 ${id}:ceo 发送启动战略指令`);
  82 + }, 2000);
  83 + }
  84 +
  85 + console.log(`[Bootstrap] 🏢 公司 ${id} 已完成自举,部署了 ${bootstrapResults.length} 名核心骨干`);
  86 + }
  87 + }
  88 +
  89 + res.json({ success: true, company, bootstrap: bootstrapResults });
32 } catch (err) { 90 } catch (err) {
33 res.status(400).json({ error: err.message }); 91 res.status(400).json({ error: err.message });
34 } 92 }
@@ -415,16 +473,57 @@ router.post(&#39;/:companyId/hire&#39;, async (req, res) =&gt; { @@ -415,16 +473,57 @@ router.post(&#39;/:companyId/hire&#39;, async (req, res) =&gt; {
415 } 473 }
416 }); 474 });
417 475
418 -// POST /api/company/:companyId/fire 476 +// POST /api/company/:companyId/fire — 辞退 Agent(招留管退之"退")
419 router.post('/:companyId/fire', (req, res) => { 477 router.post('/:companyId/fire', (req, res) => {
420 - const { agentId } = req.body;  
421 - if (!agentId) return res.status(400).json({ error: 'agentId 为必填项' }); 478 + try {
  479 + const { role, archive } = req.body;
  480 + if (!role) return res.status(400).json({ error: 'role 为必填项' });
422 481
423 - const result = companyService.fire(req.params.companyId, agentId);  
424 - if (!result) return res.status(404).json({ error: 'Agent 不存在' });  
425 - res.json(result); 482 + const path = require('path');
  483 + const fs = require('fs');
  484 + const DATA_DIR = path.resolve(__dirname, '../../data');
  485 + const companyId = req.params.companyId;
  486 + const agentDir = path.join(DATA_DIR, companyId, 'agents', role);
  487 +
  488 + if (!fs.existsSync(agentDir)) {
  489 + return res.status(404).json({ error: `Agent ${role} 不存在于公司 ${companyId}` });
  490 + }
  491 +
  492 + // 1. 停止心跳
  493 + const heartbeatService = require('../services/heartbeat-service');
  494 + const namespacedId = `${companyId}:${role}`;
  495 + if (heartbeatService.timers.has(namespacedId)) {
  496 + clearInterval(heartbeatService.timers.get(namespacedId));
  497 + heartbeatService.timers.delete(namespacedId);
  498 + }
  499 +
  500 + // 2. 归档或直接删除
  501 + if (archive !== false) {
  502 + const archiveDir = path.join(DATA_DIR, companyId, '_archived_agents', role);
  503 + fs.mkdirSync(path.dirname(archiveDir), { recursive: true });
  504 + fs.renameSync(agentDir, archiveDir);
  505 + console.log(`[Fire] 📦 ${namespacedId} 已归档到 ${archiveDir}`);
  506 + } else {
  507 + fs.rmSync(agentDir, { recursive: true, force: true });
  508 + console.log(`[Fire] 🗑️ ${namespacedId} 已彻底删除`);
  509 + }
  510 +
  511 + // 3. 从公司 agents 列表中移除
  512 + const company = companyService.get(companyId);
  513 + if (company) {
  514 + company.agents = (company.agents || []).filter(a => a !== role);
  515 + company.updatedAt = new Date().toISOString();
  516 + companyService._saveCompany(company);
  517 + }
  518 +
  519 + console.log(`[Fire] 🔴 ${namespacedId} 已辞退`);
  520 + res.json({ success: true, message: `${namespacedId} 已辞退`, archived: archive !== false });
  521 + } catch (err) {
  522 + res.status(500).json({ error: err.message });
  523 + }
426 }); 524 });
427 525
  526 +
428 // POST /api/company/:companyId/deposit-template — 训练合格后沉淀为模板 527 // POST /api/company/:companyId/deposit-template — 训练合格后沉淀为模板
429 router.post('/:companyId/deposit-template', (req, res) => { 528 router.post('/:companyId/deposit-template', (req, res) => {
430 try { 529 try {