worktree-bay 2.2.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/add.js +4 -2
- package/dist/engine.js +8 -3
- package/dist/util/progress.js +25 -0
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -41,6 +41,8 @@ export async function addCommand(cfg, feature, service, branch, base) {
|
|
|
41
41
|
}
|
|
42
42
|
// up: 一条命令为功能批量起多个服务(claim 自动 + 各服务默认分支)
|
|
43
43
|
export async function upCommand(cfg, feature, services, base) {
|
|
44
|
-
for (
|
|
45
|
-
|
|
44
|
+
for (let i = 0; i < services.length; i++) {
|
|
45
|
+
log(t(`▶ [${i + 1}/${services.length}] 起 ${services[i]} …`, `▶ [${i + 1}/${services.length}] bringing up ${services[i]} …`));
|
|
46
|
+
await addCommand(cfg, feature, services[i], undefined, base);
|
|
47
|
+
}
|
|
46
48
|
}
|
package/dist/engine.js
CHANGED
|
@@ -6,6 +6,7 @@ import { scanOccupancy } from './slots.js';
|
|
|
6
6
|
import { addWorktree } from './git.js';
|
|
7
7
|
import { runShell, run, spliceArgv, isTTY } from './util/exec.js';
|
|
8
8
|
import { warn, log } from './util/log.js';
|
|
9
|
+
import { withProgress } from './util/progress.js';
|
|
9
10
|
import { t } from './i18n.js';
|
|
10
11
|
export function mergeEnvText(text, kv) {
|
|
11
12
|
const lines = text.split('\n');
|
|
@@ -41,10 +42,12 @@ export async function bringUp(ctx, base, branch) {
|
|
|
41
42
|
const { sp, dir, repo, vars } = ctx;
|
|
42
43
|
if (!(await isPortFree(Number(vars.port))))
|
|
43
44
|
throw new Error(t(`端口 ${vars.port} 已被占用。先停掉占用它的进程,或用 \`worktree-bay gc\`/\`worktree-bay down <功能>\` 释放其它槽后重试。`, `port ${vars.port} is already in use. Stop whatever is using it, or free a slot with \`worktree-bay gc\`/\`worktree-bay down <feature>\`, then retry.`));
|
|
45
|
+
log(t(` → 创建 worktree(分支 ${branch})…`, ` → creating worktree (branch ${branch})…`));
|
|
44
46
|
addWorktree(repo, dir, branch, base);
|
|
45
47
|
for (const rel of sp.copy ?? []) {
|
|
46
|
-
// dereference: vendor/node_modules 含符号链接,Windows
|
|
47
|
-
|
|
48
|
+
// dereference: vendor/node_modules 含符号链接,Windows 下原样复制符号链接会失败,跟随并拷目标内容。
|
|
49
|
+
// 用异步 cp + spinner,让大目录(如 vendor ~238MB)拷贝时不像卡死。
|
|
50
|
+
await withProgress(t(`从主 checkout 拷贝 ${rel}(首次较慢)`, `copying ${rel} from main checkout (first time is slow)`), () => fs.promises.cp(path.join(repo, rel), path.join(dir, rel), { recursive: true, dereference: true }));
|
|
48
51
|
for (const lock of ['composer.lock', 'pnpm-lock.yaml', 'package-lock.json']) {
|
|
49
52
|
const a = path.join(repo, lock), b = path.join(dir, lock);
|
|
50
53
|
if (fs.existsSync(a) && fs.existsSync(b) && fs.readFileSync(a, 'utf8') !== fs.readFileSync(b, 'utf8'))
|
|
@@ -60,7 +63,9 @@ export async function bringUp(ctx, base, branch) {
|
|
|
60
63
|
fs.writeFileSync(fp, mergeEnvText(cur, rendered));
|
|
61
64
|
}
|
|
62
65
|
if (sp.setup) {
|
|
63
|
-
const
|
|
66
|
+
const cmd = renderTemplate(sp.setup, vars);
|
|
67
|
+
log(t(` → 执行 setup:${cmd}`, ` → running setup: ${cmd}`));
|
|
68
|
+
const r = runShell(cmd, { cwd: dir });
|
|
64
69
|
if (r.code !== 0)
|
|
65
70
|
throw new Error(t(`setup 命令失败(退出码 ${r.code})。查看上面的输出排查;修好后可重跑 add(已建的 worktree 会被复用,不会重复创建)。`, `setup command failed (exit code ${r.code}). Check the output above; after fixing, re-run add (the existing worktree is reused, not recreated).`));
|
|
66
71
|
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { log } from './log.js';
|
|
2
|
+
const FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
3
|
+
// 给长耗时异步步骤一个「在干活」的反馈:TTY 下转圈 + 秒数(写 stderr,用 \r 原地刷新),
|
|
4
|
+
// 非 TTY(管道 / CI / MCP)下退化为「开始…」「✓ 完成(Ns)」两行,避免刷屏。
|
|
5
|
+
export async function withProgress(label, fn) {
|
|
6
|
+
const t0 = Date.now();
|
|
7
|
+
const secs = () => ((Date.now() - t0) / 1000).toFixed(1);
|
|
8
|
+
if (!process.stderr.isTTY) {
|
|
9
|
+
log(` → ${label} …`);
|
|
10
|
+
const r = await fn();
|
|
11
|
+
log(` ✓ ${label}(${secs()}s)`);
|
|
12
|
+
return r;
|
|
13
|
+
}
|
|
14
|
+
let i = 0;
|
|
15
|
+
const timer = setInterval(() => { process.stderr.write(`\r ${FRAMES[i++ % FRAMES.length]} ${label} ${secs()}s `); }, 120);
|
|
16
|
+
if (typeof timer.unref === 'function')
|
|
17
|
+
timer.unref();
|
|
18
|
+
try {
|
|
19
|
+
return await fn();
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
clearInterval(timer);
|
|
23
|
+
process.stderr.write(`\r ✓ ${label}(${secs()}s) \n`);
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "worktree-bay",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Per-feature git worktree + port slots for parallel multi-service development: auto deps, env wiring, frontend-to-backend, merge-aware reclaim, plus an MCP server for AI agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|