worktree-bay 0.1.1 → 1.0.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/cli.js +19 -9
- package/dist/commands/add.js +2 -1
- package/dist/commands/ls.js +1 -1
- package/dist/commands/rm.js +6 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
4
|
import { loadConfig } from './config.js';
|
|
4
5
|
import { claimCommand } from './commands/claim.js';
|
|
@@ -9,42 +10,51 @@ import { rmCommand } from './commands/rm.js';
|
|
|
9
10
|
import { gcCommand } from './commands/gc.js';
|
|
10
11
|
import { complete, completionCommand } from './commands/completion.js';
|
|
11
12
|
import { die } from './util/log.js';
|
|
13
|
+
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
12
14
|
const program = new Command();
|
|
13
|
-
program.name('worktree-bay').description('worktree 槽位+端口编排器').version(
|
|
15
|
+
program.name('worktree-bay').description('worktree 槽位+端口编排器').version(pkg.version);
|
|
14
16
|
const sync = (fn) => { try {
|
|
15
17
|
fn(loadConfig(process.cwd()));
|
|
16
18
|
}
|
|
17
19
|
catch (e) {
|
|
18
20
|
die(e.message);
|
|
19
21
|
} };
|
|
20
|
-
program.command('claim <feature>').
|
|
22
|
+
program.command('claim <feature>').description('为功能占一个槽位(端口块)')
|
|
23
|
+
.action(async (f) => { try {
|
|
21
24
|
await claimCommand(loadConfig(process.cwd()), f);
|
|
22
25
|
}
|
|
23
26
|
catch (e) {
|
|
24
27
|
die(e.message);
|
|
25
28
|
} });
|
|
26
|
-
program.command('ls').
|
|
27
|
-
|
|
29
|
+
program.command('ls').description('列出所有槽位与占用状态')
|
|
30
|
+
.action(() => sync(lsCommand));
|
|
31
|
+
program.command('add <feature> <service> <branch> [base]').description('在某服务为功能开 worktree 并挂入其槽位')
|
|
32
|
+
.action(async (f, s, b, base) => { try {
|
|
28
33
|
await addCommand(loadConfig(process.cwd()), f, s, b, base);
|
|
29
34
|
}
|
|
30
35
|
catch (e) {
|
|
31
36
|
die(e.message);
|
|
32
37
|
} });
|
|
33
|
-
program.command('run <feature> <service> <name> [args...]').
|
|
34
|
-
|
|
35
|
-
program.command('
|
|
38
|
+
program.command('run <feature> <service> <name> [args...]').description('在服务运行体里跑 run.<name> 命令(透传 args)')
|
|
39
|
+
.action((f, s, n, args) => sync((c) => runCommand(c, f, s, n, args ?? [])));
|
|
40
|
+
program.command('sh <feature> <service>').description('进入服务运行体的 shell')
|
|
41
|
+
.action((f, s) => sync((c) => shCommand(c, f, s)));
|
|
42
|
+
program.command('rm <feature> [service]').description('拆除某服务或整槽的 worktree(默认查脏/未推保护)').option('-f, --force', '跳过脏/未推检查强制删除')
|
|
43
|
+
.action(async (f, s, o) => { try {
|
|
36
44
|
await rmCommand(loadConfig(process.cwd()), f, s, !!o.force);
|
|
37
45
|
}
|
|
38
46
|
catch (e) {
|
|
39
47
|
die(e.message);
|
|
40
48
|
} });
|
|
41
|
-
program.command('gc').option('--apply'
|
|
49
|
+
program.command('gc').description('合并感知回收(默认 dry-run)').option('--apply', '实际执行回收')
|
|
50
|
+
.action(async (o) => { try {
|
|
42
51
|
await gcCommand(loadConfig(process.cwd()), !!o.apply);
|
|
43
52
|
}
|
|
44
53
|
catch (e) {
|
|
45
54
|
die(e.message);
|
|
46
55
|
} });
|
|
47
|
-
program.command('completion <shell>').
|
|
56
|
+
program.command('completion <shell>').description('打印 shell 补全脚本(bash|zsh|fish)')
|
|
57
|
+
.action((sh) => { try {
|
|
48
58
|
completionCommand(sh);
|
|
49
59
|
}
|
|
50
60
|
catch (e) {
|
package/dist/commands/add.js
CHANGED
|
@@ -4,6 +4,7 @@ import { withLock } from '../lock.js';
|
|
|
4
4
|
import { claim } from '../slots.js';
|
|
5
5
|
import { slugify, worktreeDirName } from '../naming.js';
|
|
6
6
|
import { buildVars, bringUp } from '../engine.js';
|
|
7
|
+
import { mainBranch } from '../git.js';
|
|
7
8
|
import { log } from '../util/log.js';
|
|
8
9
|
export function resolveAdd(cfg, feature, service, branch) {
|
|
9
10
|
if (!cfg.services[service])
|
|
@@ -18,7 +19,7 @@ export async function addCommand(cfg, feature, service, branch, base) {
|
|
|
18
19
|
const sp = cfg.services[service];
|
|
19
20
|
const ctxBase = { cfg, service, sp, slot: p.slot, slug: p.slug, dir: p.dir, repo: p.repo };
|
|
20
21
|
const ctx = { ...ctxBase, vars: buildVars(cfg, ctxBase) };
|
|
21
|
-
await bringUp(ctx, base ??
|
|
22
|
+
await bringUp(ctx, base ?? `origin/${mainBranch(p.repo)}`, branch);
|
|
22
23
|
log(`✓ ${service} 挂入 "${feature}"(槽 ${p.slot},端口 ${ctx.vars.port})`);
|
|
23
24
|
});
|
|
24
25
|
}
|
package/dist/commands/ls.js
CHANGED
|
@@ -9,7 +9,7 @@ export function renderSlots(cfg) {
|
|
|
9
9
|
for (const n of [...slots].sort((a, b) => a - b)) {
|
|
10
10
|
const base = blockBase(cfg.portBase, cfg.slotSpan, n);
|
|
11
11
|
const svc = (occ.get(n) ?? []).map((o) => `${o.service}@${base + cfg.services[o.service].offset}`);
|
|
12
|
-
lines.push(`slot ${n} ${labels[String(n)] ?? '(unnamed)'}
|
|
12
|
+
lines.push(`slot ${n} ${labels[String(n)] ?? '(unnamed)'} block=${base} [${svc.join(', ') || 'no worktree'}]`);
|
|
13
13
|
}
|
|
14
14
|
return lines.join('\n') || '(no slots in use)';
|
|
15
15
|
}
|
package/dist/commands/rm.js
CHANGED
|
@@ -14,6 +14,7 @@ export function resolveRm(cfg, feature, service) {
|
|
|
14
14
|
}
|
|
15
15
|
export async function rmCommand(cfg, feature, service, force) {
|
|
16
16
|
await withLock(cfg.workspaceRoot, async () => {
|
|
17
|
+
let removed = 0;
|
|
17
18
|
for (const o of resolveRm(cfg, feature, service)) {
|
|
18
19
|
const repo = repoPath(cfg, o.service);
|
|
19
20
|
const branch = currentBranch(o.dir);
|
|
@@ -28,9 +29,13 @@ export async function rmCommand(cfg, feature, service, force) {
|
|
|
28
29
|
}
|
|
29
30
|
removeWorktree(repo, o.dir, force);
|
|
30
31
|
log(`✓ 移除 ${o.service}`);
|
|
32
|
+
removed++;
|
|
31
33
|
}
|
|
32
34
|
const slot = slotOfFeature(cfg, feature);
|
|
33
|
-
if (!service && (scanOccupancy(cfg).get(slot) ?? []).length === 0)
|
|
35
|
+
if (!service && (scanOccupancy(cfg).get(slot) ?? []).length === 0) {
|
|
34
36
|
removeLabel(cfg, slot);
|
|
37
|
+
if (removed === 0)
|
|
38
|
+
log(`✓ 释放空槽预约 "${feature}"(槽 ${slot})`);
|
|
39
|
+
}
|
|
35
40
|
});
|
|
36
41
|
}
|