148 lines
4.8 KiB
JavaScript
148 lines
4.8 KiB
JavaScript
|
|
// scripts/neural/convert-workorder-to-command.js
|
|||
|
|
// 🧬 工单→下行指令 转化器
|
|||
|
|
// Notion Agent 调用此脚本,将工单转化为铸渊可执行的下行指令
|
|||
|
|
// 输入:工单 JSON 文件路径
|
|||
|
|
// 输出:下行指令 JSON(写入 deploy-queue/pending/)
|
|||
|
|
|
|||
|
|
const fs = require('fs');
|
|||
|
|
const path = require('path');
|
|||
|
|
const crypto = require('crypto');
|
|||
|
|
|
|||
|
|
const DEPLOY_QUEUE = 'data/deploy-queue/pending';
|
|||
|
|
const NEURAL_MAP_PATH = 'skyeye/neural-map.json';
|
|||
|
|
|
|||
|
|
function loadJSON(p) {
|
|||
|
|
try { return JSON.parse(fs.readFileSync(p, 'utf8')); }
|
|||
|
|
catch (e) { return null; }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function generateCommandId() {
|
|||
|
|
var now = new Date();
|
|||
|
|
var cst = new Date(now.getTime() + 8 * 60 * 60 * 1000);
|
|||
|
|
var date = cst.toISOString().split('T')[0].replace(/-/g, '');
|
|||
|
|
var seq = crypto.randomBytes(2).toString('hex').toUpperCase();
|
|||
|
|
return 'CMD-' + date + '-' + seq;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function convertWorkOrderToCommand(workOrder) {
|
|||
|
|
var neuralMap = loadJSON(NEURAL_MAP_PATH);
|
|||
|
|
if (!neuralMap) throw new Error('neural-map.json 不存在');
|
|||
|
|
|
|||
|
|
var commandId = generateCommandId();
|
|||
|
|
var now = new Date().toISOString();
|
|||
|
|
|
|||
|
|
// 确定目标 Workflow
|
|||
|
|
var targetWorkflowId = (workOrder.affected && workOrder.affected.workflows)
|
|||
|
|
? workOrder.affected.workflows[0] : null;
|
|||
|
|
var targetWorkflow = targetWorkflowId
|
|||
|
|
? neuralMap.github_workflows[targetWorkflowId] : null;
|
|||
|
|
|
|||
|
|
// 确定指令类型
|
|||
|
|
var instructionType = 'trigger_workflow';
|
|||
|
|
var instructionParams = {};
|
|||
|
|
|
|||
|
|
var action = (workOrder.source && workOrder.source.rule_triggered) || '';
|
|||
|
|
if (action.indexOf('cleanup') !== -1 || action.indexOf('clean') !== -1) {
|
|||
|
|
instructionType = 'run_script';
|
|||
|
|
instructionParams = {
|
|||
|
|
script: 'scripts/neural/cleanup-old-reports.js',
|
|||
|
|
args: { max_age_days: 7 }
|
|||
|
|
};
|
|||
|
|
} else if (action.indexOf('guard_restart') !== -1 || action.indexOf('quota') !== -1) {
|
|||
|
|
instructionType = 'modify_config';
|
|||
|
|
instructionParams = {
|
|||
|
|
target_file: (workOrder.affected && workOrder.affected.guards && workOrder.affected.guards[0])
|
|||
|
|
? 'skyeye/guards/' + workOrder.affected.guards[0] + '.json'
|
|||
|
|
: null,
|
|||
|
|
modifications: { status: 'active', mode: 'normal' }
|
|||
|
|
};
|
|||
|
|
} else {
|
|||
|
|
instructionType = 'trigger_workflow';
|
|||
|
|
instructionParams = {
|
|||
|
|
event: 'workflow_dispatch',
|
|||
|
|
inputs: {
|
|||
|
|
reason: '工单 ' + workOrder.work_order_id + ' 自动触发',
|
|||
|
|
source_work_order: workOrder.work_order_id
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var assignedTo = (workOrder.assignment && workOrder.assignment.assigned_to) || 'AG-TY-01';
|
|||
|
|
var assignedToName = (workOrder.assignment && workOrder.assignment.assigned_to_name) || '天眼 Notion 大脑';
|
|||
|
|
|
|||
|
|
var command = {
|
|||
|
|
_protocol: 'neural-bridge-v3.0',
|
|||
|
|
_type: 'downstream_command',
|
|||
|
|
command_id: commandId,
|
|||
|
|
parent_work_order: workOrder.work_order_id,
|
|||
|
|
source: {
|
|||
|
|
agent_id: assignedTo,
|
|||
|
|
agent_name: assignedToName,
|
|||
|
|
issued_at: now,
|
|||
|
|
issued_reason: workOrder.title
|
|||
|
|
},
|
|||
|
|
target: {
|
|||
|
|
workflow_id: targetWorkflowId || 'unknown',
|
|||
|
|
workflow_file: targetWorkflow ? targetWorkflow.file : 'unknown',
|
|||
|
|
brain: targetWorkflow ? targetWorkflow.brain : assignedTo
|
|||
|
|
},
|
|||
|
|
instruction: {
|
|||
|
|
type: instructionType,
|
|||
|
|
params: instructionParams
|
|||
|
|
},
|
|||
|
|
constraints: {
|
|||
|
|
priority: workOrder.severity,
|
|||
|
|
timeout_hours: (workOrder.constraints && workOrder.constraints.timeout_hours) || 24,
|
|||
|
|
max_retries: (workOrder.constraints && workOrder.constraints.max_retries) || 2,
|
|||
|
|
requires_human_approval: workOrder.severity === 'P0',
|
|||
|
|
execution_window: {
|
|||
|
|
start: '06:00 CST',
|
|||
|
|
end: '23:00 CST'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
expected_outcome: {
|
|||
|
|
description: '解决工单 ' + workOrder.work_order_id + ': ' + workOrder.title,
|
|||
|
|
verification: {
|
|||
|
|
type: 'check_workflow_status',
|
|||
|
|
workflow: targetWorkflowId,
|
|||
|
|
expected_conclusion: 'success'
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
security: {
|
|||
|
|
sfp: '⌜SFP::' + assignedTo + '::NeuralBridge::' + commandId + '::' + now + '⌝',
|
|||
|
|
signature_chain: [assignedTo, '铸渊桥接层']
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 写入 deploy-queue
|
|||
|
|
fs.mkdirSync(DEPLOY_QUEUE, { recursive: true });
|
|||
|
|
fs.writeFileSync(
|
|||
|
|
path.join(DEPLOY_QUEUE, commandId + '.json'),
|
|||
|
|
JSON.stringify(command, null, 2)
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
console.log('✅ 工单 ' + workOrder.work_order_id + ' → 指令 ' + commandId);
|
|||
|
|
console.log(' 类型: ' + instructionType);
|
|||
|
|
console.log(' 目标: ' + (targetWorkflowId || '(待确定)'));
|
|||
|
|
console.log(' 优先级: ' + workOrder.severity);
|
|||
|
|
|
|||
|
|
return command;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// CLI 入口
|
|||
|
|
if (require.main === module) {
|
|||
|
|
var woPath = process.argv[2];
|
|||
|
|
if (!woPath) {
|
|||
|
|
console.error('用法: node convert-workorder-to-command.js <work-order.json>');
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
var wo = loadJSON(woPath);
|
|||
|
|
if (!wo) {
|
|||
|
|
console.error('❌ 无法读取工单文件: ' + woPath);
|
|||
|
|
process.exit(1);
|
|||
|
|
}
|
|||
|
|
convertWorkOrderToCommand(wo);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
module.exports = { convertWorkOrderToCommand };
|