Files
openclaw-skill/skills/assign-task/handler.ts
Selig 4c966a3ad2 Initial commit: OpenClaw Skill Collection
6 custom skills (assign-task, dispatch-webhook, daily-briefing,
task-capture, qmd-brain, tts-voice) with technical documentation.
Compatible with Claude Code, OpenClaw, Codex CLI, and OpenCode.
2026-03-13 10:58:30 +08:00

95 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* assign-task skill
* 分析任務,判斷目標 VPS呼叫 dispatch-webhook 執行
*/
import { randomUUID } from 'crypto';
// 任務分派規則
const DISPATCH_RULES = [
{
target: 'vps-a',
label: 'VPS-A (Claude Code)',
model: 'Claude Code Opus',
keywords: ['主要專案', '核心功能', '架構', 'code review', 'review', '審查', 'API', '後端', 'backend'],
},
{
target: 'vps-b',
label: 'VPS-B (OpenCode)',
model: 'OpenCode Codex',
keywords: ['腳本', 'script', '工具', 'tool', '文件', 'doc', 'readme', '實驗', '前端', 'frontend', 'react', 'vue'],
},
];
function determineTarget(description: string): typeof DISPATCH_RULES[0] {
const lower = description.toLowerCase();
for (const rule of DISPATCH_RULES) {
if (rule.keywords.some(k => lower.includes(k.toLowerCase()))) {
return rule;
}
}
// 預設分派到 VPS-A
return DISPATCH_RULES[0];
}
function determinePriority(description: string): string {
const lower = description.toLowerCase();
if (lower.includes('緊急') || lower.includes('urgent') || lower.includes('asap')) return 'high';
if (lower.includes('之後') || lower.includes('有空') || lower.includes('低優先')) return 'low';
return 'normal';
}
export async function handler(ctx: any) {
const { message, env, callSkill } = ctx;
const description = message.text || message.content || '';
if (!description) {
return { reply: '❌ 請描述你想要執行的任務。' };
}
const taskId = randomUUID();
const target = determineTarget(description);
const priority = determinePriority(description);
// 建立任務 payload
const task = {
task_id: taskId,
type: 'project_development',
description: description.slice(0, 2000),
priority,
target: target.target,
callback_url: `${env.CALLBACK_BASE_URL || 'https://oclaw.nature.edu.kg/webhook/callback'}`,
created_at: new Date().toISOString(),
};
// 呼叫 dispatch-webhook skill
let dispatchResult;
try {
dispatchResult = await callSkill('dispatch-webhook', {
target: target.target,
payload: task,
webhookUrl: target.target === 'vps-a' ? env.VPS_A_WEBHOOK_URL : env.VPS_B_WEBHOOK_URL,
webhookToken: target.target === 'vps-a' ? env.VPS_A_WEBHOOK_TOKEN : env.VPS_B_WEBHOOK_TOKEN,
});
} catch (err: any) {
return {
reply: `❌ Webhook 發送失敗:${err.message}\n\nTask ID: \`${taskId}\`(可稍後重試)`,
};
}
const priorityLabel = { high: '🔴 緊急', normal: '🟡 一般', low: '🟢 低優先' }[priority] || priority;
return {
reply: `✅ 任務已分派
📋 **任務摘要**${description.slice(0, 100)}${description.length > 100 ? '...' : ''}
🎯 **分派目標**${target.label}
🤖 **執行模型**${target.model}
⚡ **優先級**${priorityLabel}
🆔 **Task ID**\`${taskId}\`
執行中,完成後會通知你。`,
metadata: { taskId, target: target.target, priority },
};
}