feat: 全栈 Logger 依赖注入 — DB/Route/AI 层传参 + 前端 Logger + 测试更新 + 归档 add-frontend-logger
This commit is contained in:
@@ -7,87 +7,9 @@
|
||||
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { existsSync, mkdirSync } from "node:fs";
|
||||
import { resolve, relative } from "node:path";
|
||||
import { relative, resolve } from "node:path";
|
||||
import { createInterface } from "node:readline";
|
||||
|
||||
function git(args, opts) {
|
||||
return execFileSync("git", args, { encoding: "utf-8", stdio: "pipe", ...opts });
|
||||
}
|
||||
|
||||
function getRootDir() {
|
||||
try {
|
||||
return resolve(git(["rev-parse", "--show-toplevel"]).trim());
|
||||
} catch {
|
||||
console.error("错误: 不在 git 仓库中");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchRemote() {
|
||||
try {
|
||||
git(["fetch", "--quiet"]);
|
||||
} catch {
|
||||
console.warn("警告: 无法获取远端信息,继续使用本地数据");
|
||||
}
|
||||
}
|
||||
|
||||
function listRemoteBranches() {
|
||||
try {
|
||||
return git(["branch", "-r"])
|
||||
.trim()
|
||||
.split(/\r?\n/)
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l && !l.includes(" -> "));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function matchingRemoteBranches(name) {
|
||||
return listRemoteBranches().filter((l) => l.endsWith(`/${name}`));
|
||||
}
|
||||
|
||||
function localBranchExists(name) {
|
||||
try {
|
||||
git(["show-ref", "--verify", "--quiet", `refs/heads/${name}`]);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function worktreeExists(worktreeDir) {
|
||||
try {
|
||||
const out = git(["worktree", "list"]);
|
||||
const target = resolve(worktreeDir);
|
||||
return out
|
||||
.split(/\r?\n/)
|
||||
.some((line) => {
|
||||
const fields = line.trim().split(/\s+/);
|
||||
return fields.length > 0 && resolve(fields[0]) === target;
|
||||
});
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function shortBranchName(remoteRef) {
|
||||
const idx = remoteRef.indexOf("/");
|
||||
return idx === -1 ? remoteRef : remoteRef.slice(idx + 1);
|
||||
}
|
||||
|
||||
function assertCanCreate(name, dir) {
|
||||
if (existsSync(dir)) {
|
||||
throw new Error(`工作区已存在于 ${dir}`);
|
||||
}
|
||||
if (worktreeExists(dir)) {
|
||||
throw new Error(`工作区 '${name}' 已存在`);
|
||||
}
|
||||
if (localBranchExists(name)) {
|
||||
throw new Error(`本地分支 '${name}' 已存在`);
|
||||
}
|
||||
}
|
||||
|
||||
function addWorktree(name, dir, base) {
|
||||
const args = ["worktree", "add", "-b", name, dir];
|
||||
if (base) args.push(base);
|
||||
@@ -104,62 +26,39 @@ function ask(rl, prompt) {
|
||||
return new Promise((resolve) => rl.question(prompt, resolve));
|
||||
}
|
||||
|
||||
async function selectFromList(items, prompt, allowCreate) {
|
||||
if (items.length === 0) return null;
|
||||
|
||||
console.log(prompt);
|
||||
items.forEach((item, i) => console.log(` ${i + 1}\t${item}`));
|
||||
if (allowCreate) console.log(` ${items.length + 1}\t创建新分支`);
|
||||
console.log();
|
||||
|
||||
const max = allowCreate ? items.length + 1 : items.length;
|
||||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
let cancelled = false;
|
||||
rl.on("close", () => { cancelled = true; });
|
||||
|
||||
while (true) {
|
||||
const raw = await ask(rl, `请选择 (1-${max}): `);
|
||||
if (cancelled) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
const n = Number.parseInt(raw, 10);
|
||||
if (Number.isNaN(n) || n < 1 || n > max) {
|
||||
console.log(`错误: 请输入 1-${max} 之间的数字`);
|
||||
continue;
|
||||
}
|
||||
if (n <= items.length) {
|
||||
const sel = items[n - 1];
|
||||
console.log(`已选择: ${sel}`);
|
||||
rl.close();
|
||||
return sel;
|
||||
}
|
||||
rl.close();
|
||||
return null;
|
||||
function assertCanCreate(name, dir) {
|
||||
if (existsSync(dir)) {
|
||||
throw new Error(`工作区已存在于 ${dir}`);
|
||||
}
|
||||
if (worktreeExists(dir)) {
|
||||
throw new Error(`工作区 '${name}' 已存在`);
|
||||
}
|
||||
if (localBranchExists(name)) {
|
||||
throw new Error(`本地分支 '${name}' 已存在`);
|
||||
}
|
||||
}
|
||||
|
||||
async function inputBranchName() {
|
||||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
let cancelled = false;
|
||||
rl.on("close", () => { cancelled = true; });
|
||||
|
||||
while (true) {
|
||||
const name = (await ask(rl, "请输入新分支名称: ")).trim();
|
||||
if (cancelled) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
if (name) {
|
||||
rl.close();
|
||||
return name;
|
||||
}
|
||||
console.log("错误: 分支名称不能为空");
|
||||
function fetchRemote() {
|
||||
try {
|
||||
git(["fetch", "--quiet"]);
|
||||
} catch {
|
||||
console.warn("警告: 无法获取远端信息,继续使用本地数据");
|
||||
}
|
||||
}
|
||||
|
||||
function getRootDir() {
|
||||
try {
|
||||
return resolve(git(["rev-parse", "--show-toplevel"]).trim());
|
||||
} catch {
|
||||
console.error("错误: 不在 git 仓库中");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
function git(args, opts) {
|
||||
return execFileSync("git", args, { encoding: "utf-8", stdio: "pipe", ...opts });
|
||||
}
|
||||
|
||||
async function handleWithName(name, worktreesDir) {
|
||||
const dir = resolve(worktreesDir, name);
|
||||
|
||||
@@ -218,6 +117,109 @@ async function handleWithoutName(worktreesDir) {
|
||||
}
|
||||
}
|
||||
|
||||
async function inputBranchName() {
|
||||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
let cancelled = false;
|
||||
rl.on("close", () => {
|
||||
cancelled = true;
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const name = (await ask(rl, "请输入新分支名称: ")).trim();
|
||||
if (cancelled) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
if (name) {
|
||||
rl.close();
|
||||
return name;
|
||||
}
|
||||
console.log("错误: 分支名称不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
function listRemoteBranches() {
|
||||
try {
|
||||
return git(["branch", "-r"])
|
||||
.trim()
|
||||
.split(/\r?\n/)
|
||||
.map((l) => l.trim())
|
||||
.filter((l) => l && !l.includes(" -> "));
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function localBranchExists(name) {
|
||||
try {
|
||||
git(["show-ref", "--verify", "--quiet", `refs/heads/${name}`]);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function matchingRemoteBranches(name) {
|
||||
return listRemoteBranches().filter((l) => l.endsWith(`/${name}`));
|
||||
}
|
||||
|
||||
async function selectFromList(items, prompt, allowCreate) {
|
||||
if (items.length === 0) return null;
|
||||
|
||||
console.log(prompt);
|
||||
items.forEach((item, i) => console.log(` ${i + 1}\t${item}`));
|
||||
if (allowCreate) console.log(` ${items.length + 1}\t创建新分支`);
|
||||
console.log();
|
||||
|
||||
const max = allowCreate ? items.length + 1 : items.length;
|
||||
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
||||
|
||||
let cancelled = false;
|
||||
rl.on("close", () => {
|
||||
cancelled = true;
|
||||
});
|
||||
|
||||
while (true) {
|
||||
const raw = await ask(rl, `请选择 (1-${max}): `);
|
||||
if (cancelled) {
|
||||
rl.close();
|
||||
process.exit(1);
|
||||
}
|
||||
const n = Number.parseInt(raw, 10);
|
||||
if (Number.isNaN(n) || n < 1 || n > max) {
|
||||
console.log(`错误: 请输入 1-${max} 之间的数字`);
|
||||
continue;
|
||||
}
|
||||
if (n <= items.length) {
|
||||
const sel = items[n - 1];
|
||||
console.log(`已选择: ${sel}`);
|
||||
rl.close();
|
||||
return sel;
|
||||
}
|
||||
rl.close();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function shortBranchName(remoteRef) {
|
||||
const idx = remoteRef.indexOf("/");
|
||||
return idx === -1 ? remoteRef : remoteRef.slice(idx + 1);
|
||||
}
|
||||
|
||||
function worktreeExists(worktreeDir) {
|
||||
try {
|
||||
const out = git(["worktree", "list"]);
|
||||
const target = resolve(worktreeDir);
|
||||
return out.split(/\r?\n/).some((line) => {
|
||||
const fields = line.trim().split(/\s+/);
|
||||
return fields.length > 0 && resolve(fields[0]) === target;
|
||||
});
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => process.exit(1));
|
||||
|
||||
async function main() {
|
||||
|
||||
Reference in New Issue
Block a user