Files
Sisyphus (主代理) 02762400fb chore: 项目基线提交 - 拼豆图纸生成器 V1.0 核心代码
- 前端: React+Vite 首页/AI专区, 算法库(MARD色板/量化/背景去除), API对接
- 后端: Express+SQLite, 兑换码/订单/支付/chibi生成, 风控+云端同步
- CI/CD: GitHub Actions + Docker + nginx 配置
- 文档: PRD/DESIGN/LAUNCH/ROADMAP/E2E/竞品对照等 15 份
- 工程: 任务看板(taskboard) + 健康巡检(agent-health) + Git流程(gitflow)
2026-08-13 21:40:27 +08:00

124 lines
5.1 KiB
JavaScript

#!/usr/bin/env node
/**
* PERLER LAB · Git 集成脚本
* 状态机 → Git 提交工作流:
* node gitflow.js daily "提交说明" # 日常提交所有改动
* node gitflow.js approve T-001 # 任务验收通过 → 自动 commit + 建议 push
* node gitflow.js push # 推送当前分支到远端
* node gitflow.js status # 查看任务/代码状态
*/
'use strict';
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const ROOT = path.resolve(__dirname);
const TASKS_FILE = path.join(__dirname, 'taskboard', 'tasks.json');
function run(cmd, silent = false) {
try {
const out = execSync(cmd, { cwd: ROOT, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
if (!silent && out.trim()) console.log(out.trim().split('\n').map(l => ' ' + l).join('\n'));
return { ok: true, out: out.trim() };
} catch (e) {
const msg = (e.stderr || e.stdout || e.message || '').trim();
if (!silent && msg) console.log(' ' + msg.split('\n').map(l => ' ' + l).join('\n'));
return { ok: false, out: msg };
}
}
function loadTasks() {
return JSON.parse(fs.readFileSync(TASKS_FILE, 'utf8'));
}
function ensureGitUser() {
const name = run('git config user.name', true).out;
const email = run('git config user.email', true).out;
if (!name || !email) {
console.log('[Git] 未配置提交身份,使用默认(可用 git config --global 覆盖)');
if (!name) run('git config user.name "Sisyphus"', true);
if (!email) run('git config user.email "sisyphus@perler-lab.local"', true);
}
}
function gitStatus() {
const { out } = run('git status --porcelain', true);
const files = out ? out.split('\n').filter(Boolean) : [];
const staged = files.filter(f => /^[MARD]/.test(f));
const unstaged = files.filter(f => /^.[MAD?]/.test(f));
return { all: files, staged, unstaged };
}
/* ---------- 命令 ---------- */
function cmdDaily(args) {
ensureGitUser();
const msg = args._.join(' ') || '日常提交';
const st = gitStatus();
if (!st.all.length) { console.log('[Git] 无任何改动,无需提交'); return; }
run('git add -A');
run(`git commit -m "${msg}"`);
console.log(`[Git] 日常提交完成: "${msg}" (${st.all.length} 个文件)`);
console.log('[Git] 提示: 运行 node gitflow.js push 推送到远端');
}
function cmdApprove(args) {
ensureGitUser();
const taskId = args._[0];
if (!taskId) { console.error('[错误] 用法: node gitflow.js approve <任务ID>'); process.exit(1); }
const db = loadTasks();
const task = db.tasks.find(t => t.id.toUpperCase() === String(taskId).toUpperCase());
if (!task) { console.error(`[错误] 任务 ${taskId} 不存在`); process.exit(1); }
if (task.status !== 'approved') {
console.error(`[错误] 任务 ${taskId} 当前状态为「${task.status}」,只有「验收通过」的任务才可上传`);
process.exit(1);
}
const st = gitStatus();
if (!st.all.length) { console.log(`[Git] 任务 ${taskId} 已验收通过,且代码无未提交改动`); return; }
run('git add -A');
const msg = `[验收通过] ${task.id} ${task.title}`;
const r = run(`git commit -m "${msg}"`);
if (!r.ok) { console.error('[Git] 提交失败'); process.exit(1); }
console.log(`[Git] 任务 ${taskId} 验收通过 → 已自动提交: "${msg}"`);
const remote = run('git remote get-url origin', true).out;
if (remote) {
const push = run('git push');
console.log(push.ok ? '[Git] 已推送到远端' : '[Git] 推送失败,请检查远端配置');
} else {
console.log('[Git] 未配置远端 (origin),跳过推送。配置: git remote add origin <仓库URL>');
}
}
function cmdPush() {
const remote = run('git remote get-url origin', true).out;
if (!remote) { console.error('[Git] 未配置远端,先执行: git remote add origin https://github.com/<用户>/<仓库>.git'); process.exit(1); }
const branch = run('git branch --show-current', true).out || 'main';
const r = run(`git push -u origin ${branch}`);
console.log(r.ok ? `[Git] 已推送 ${branch} 到 ${remote}` : '[Git] 推送失败');
}
function cmdStatus() {
const st = gitStatus();
console.log('=== Git 状态 ===');
if (!st.all.length) { console.log(' (工作区干净)'); }
st.all.forEach(f => console.log(' ' + f));
const remote = run('git remote get-url origin', true).out || '(未配置)';
const branch = run('git branch --show-current', true).out || '(无提交)';
console.log(`分支: ${branch} | 远端: ${remote}`);
const db = loadTasks();
const approved = db.tasks.filter(t => t.status === 'approved');
const pending = db.tasks.filter(t => ['in_progress', 'review'].includes(t.status));
console.log(`任务: 验收通过 ${approved.length} | 开发/待验收 ${pending.length}`);
}
/* ---------- 入口 ---------- */
const argv = process.argv.slice(2);
const cmd = argv[0];
const args = { _: argv.slice(1) };
const CMDS = { daily: cmdDaily, approve: cmdApprove, push: cmdPush, status: cmdStatus };
if (!CMDS[cmd]) {
console.log('用法: node gitflow.js <daily|approve|push|status> [参数]');
process.exit(1);
}
CMDS[cmd](args);