Commit f49cad855662639d36c190006ac1e803f977acf7
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
Showing
9 changed files
with
315 additions
and
41 deletions
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 "Q1 ä¸šåŠ¡ç›®æ ‡" --desc "..." --owner <ä½ | @@ -59,9 +62,9 @@ node bin/lemon.js goal create --title "Q1 ä¸šåŠ¡ç›®æ ‡" --desc "..." --owner <ä½ | ||
| 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 <雿撌梧 techcompany:cto> --to < | @@ -58,11 +57,10 @@ node bin/lemon.js task dispatch --from <雿撌梧 techcompany:cto> --to < | ||
| 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
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('/create', (req, res) => { | @@ -28,7 +28,65 @@ router.post('/create', (req, res) => { | ||
| 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('/:companyId/hire', async (req, res) => { | @@ -415,16 +473,57 @@ router.post('/:companyId/hire', async (req, res) => { | ||
| 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 { |