worktree-bay 2.5.0 → 4.0.0
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/README.md +1 -1
- package/dist/cli.js +12 -17
- package/dist/commands/completion.js +6 -6
- package/dist/commands/lifecycle.js +14 -8
- package/dist/commands/rm.js +12 -5
- package/dist/mcp.js +12 -12
- package/package.json +1 -1
- package/skill.md +7 -8
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ worktree-bay gc
|
|
|
47
47
|
|
|
48
48
|
> 运行体随起随停(不动 worktree/代码):`worktree-bay stop drill-fix` 停掉(docker 容器 + dev server 一起)、`start` 起回来、`restart` 重启。
|
|
49
49
|
>
|
|
50
|
-
> 更细的控制:`claim <feature>` 单独占槽、`add <feature> <service> [branch]` 单加一个服务(branch 可自定义,省略则用功能名)、`
|
|
50
|
+
> 更细的控制:`claim <feature>` 单独占槽、`add <feature> <service> [branch]` 单加一个服务(branch 可自定义,省略则用功能名)、`down <feature> <service>` 只拆某个服务(省略服务则拆整功能)。
|
|
51
51
|
|
|
52
52
|
## 配置
|
|
53
53
|
|
package/dist/cli.js
CHANGED
|
@@ -73,8 +73,10 @@ catch (e) {
|
|
|
73
73
|
die(e.message);
|
|
74
74
|
} });
|
|
75
75
|
program.command('add <feature> <service> [branch] [base]').description(t('为功能在某服务开 worktree(branch 默认 = 功能名)', 'open a worktree for a feature on one service (branch defaults to feature name)'))
|
|
76
|
-
.
|
|
77
|
-
|
|
76
|
+
.option('--branch <branch>', t('要创建的分支名(默认 = 功能名)', 'branch to create (default = feature name)'))
|
|
77
|
+
.option('--base <base>', t('分支基点(默认 = origin/<主分支>)', 'base ref for the branch (default = origin/<main>)'))
|
|
78
|
+
.action(async (f, s, b, base, o) => { try {
|
|
79
|
+
await addCommand(loadConfig(process.cwd()), f, s, o.branch ?? b, o.base ?? base);
|
|
78
80
|
}
|
|
79
81
|
catch (e) {
|
|
80
82
|
die(e.message);
|
|
@@ -83,37 +85,30 @@ program.command('run <feature> <service> <name> [args...]').description(t('在
|
|
|
83
85
|
.action((f, s, n, args) => sync((c) => runCommand(c, f, s, n, args ?? [])));
|
|
84
86
|
program.command('sh <feature> <service>').description(t('进入服务运行体的 shell', 'open a shell inside the service runtime'))
|
|
85
87
|
.action((f, s) => sync((c) => shCommand(c, f, s)));
|
|
86
|
-
program.command('start <feature> [
|
|
88
|
+
program.command('start <feature> [services...]').description(t('启动功能的运行体(docker 容器 + dev server);省略 service = 全部,可列多个。不动 worktree', 'start the feature\'s runtime (docker + dev server); omit services = all, or list several. Leaves the worktree untouched'))
|
|
87
89
|
.action(async (f, s) => { try {
|
|
88
|
-
await startCommand(loadConfig(process.cwd()), f, s);
|
|
90
|
+
await startCommand(loadConfig(process.cwd()), f, s ?? []);
|
|
89
91
|
}
|
|
90
92
|
catch (e) {
|
|
91
93
|
die(e.message);
|
|
92
94
|
} });
|
|
93
|
-
program.command('stop <feature> [
|
|
95
|
+
program.command('stop <feature> [services...]').description(t('停止功能的运行体(停 docker + 杀 dev server);省略 = 全部,可列多个。保留 worktree', 'stop the feature\'s runtime (stop docker + kill dev server); omit = all, or list several. Keeps the worktree'))
|
|
94
96
|
.action(async (f, s) => { try {
|
|
95
|
-
await stopCommand(loadConfig(process.cwd()), f, s);
|
|
97
|
+
await stopCommand(loadConfig(process.cwd()), f, s ?? []);
|
|
96
98
|
}
|
|
97
99
|
catch (e) {
|
|
98
100
|
die(e.message);
|
|
99
101
|
} });
|
|
100
|
-
program.command('restart <feature> [
|
|
102
|
+
program.command('restart <feature> [services...]').description(t('重启功能的运行体(停掉再起);省略 = 全部,可列多个', 'restart the feature\'s runtime (stop then start); omit = all, or list several'))
|
|
101
103
|
.action(async (f, s) => { try {
|
|
102
|
-
await restartCommand(loadConfig(process.cwd()), f, s);
|
|
104
|
+
await restartCommand(loadConfig(process.cwd()), f, s ?? []);
|
|
103
105
|
}
|
|
104
106
|
catch (e) {
|
|
105
107
|
die(e.message);
|
|
106
108
|
} });
|
|
107
|
-
program.command('down <feature>').description(t('
|
|
108
|
-
.action(async (f, o) => { try {
|
|
109
|
-
await rmCommand(loadConfig(process.cwd()), f, undefined, !!o.force);
|
|
110
|
-
}
|
|
111
|
-
catch (e) {
|
|
112
|
-
die(e.message);
|
|
113
|
-
} });
|
|
114
|
-
program.command('rm <feature> [service]').description(t('拆除某服务或整槽的 worktree(默认查脏/未推保护)', 'remove one service\'s or the whole slot\'s worktree (dirty/unpushed protected by default)')).option('-f, --force', t('跳过脏/未推检查强制删除', 'skip dirty/unpushed checks and force-remove'))
|
|
109
|
+
program.command('down <feature> [services...]').description(t('拆除功能的 worktree(停运行体 + teardown + 删 worktree);省略 services = 整功能,可列多个只拆这些。默认查脏/未推保护', 'tear down a feature\'s worktree(s) (stop runtime + teardown + remove worktree); omit services = whole feature, or list several. Dirty/unpushed protected by default')).option('-f, --force', t('跳过脏/未推检查强制删除', 'skip dirty/unpushed checks and force-remove'))
|
|
115
110
|
.action(async (f, s, o) => { try {
|
|
116
|
-
await rmCommand(loadConfig(process.cwd()), f, s, !!o.force);
|
|
111
|
+
await rmCommand(loadConfig(process.cwd()), f, s ?? [], !!o.force);
|
|
117
112
|
}
|
|
118
113
|
catch (e) {
|
|
119
114
|
die(e.message);
|
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { readLabels } from '../slots.js';
|
|
5
5
|
import { log } from '../util/log.js';
|
|
6
6
|
import { t } from '../i18n.js';
|
|
7
|
-
const SUBCMDS = ['init', 'doctor', 'claim', 'up', 'add', 'ls', 'path', 'gc', 'down', '
|
|
7
|
+
const SUBCMDS = ['init', 'doctor', 'claim', 'up', 'add', 'ls', 'path', 'gc', 'down', 'run', 'sh', 'start', 'stop', 'restart', 'completion', 'mcp', 'skill', 'version', 'help'];
|
|
8
8
|
// words = 命令名 + 光标前已输入完的词(不含当前正在补的词)
|
|
9
9
|
export function complete(cfg, words) {
|
|
10
10
|
const prev = words.slice(1);
|
|
@@ -14,15 +14,15 @@ export function complete(cfg, words) {
|
|
|
14
14
|
return []; // 无配置(不在工作区内):子命令已补全,feature/service 无从读取
|
|
15
15
|
const sub = prev[0];
|
|
16
16
|
const pos = prev.length;
|
|
17
|
-
const featureSubs = ['up', 'add', '
|
|
17
|
+
const featureSubs = ['up', 'add', 'down', 'run', 'sh', 'path', 'start', 'stop', 'restart'];
|
|
18
18
|
if (featureSubs.includes(sub) && pos === 1)
|
|
19
19
|
return Object.values(readLabels(cfg));
|
|
20
|
-
if (['add', 'run', 'sh', 'path'
|
|
21
|
-
return Object.keys(cfg.services);
|
|
20
|
+
if (['add', 'run', 'sh', 'path'].includes(sub) && pos === 2)
|
|
21
|
+
return Object.keys(cfg.services); // 单服务
|
|
22
22
|
if (sub === 'run' && pos === 3)
|
|
23
23
|
return Object.keys(cfg.services[prev[2]]?.run ?? {}); // run <feature> <service> <name>:补该服务的 run 命令名
|
|
24
|
-
if (
|
|
25
|
-
return Object.keys(cfg.services); //
|
|
24
|
+
if (['up', 'start', 'stop', 'restart', 'down'].includes(sub) && pos >= 2)
|
|
25
|
+
return Object.keys(cfg.services); // 变长服务列表
|
|
26
26
|
return [];
|
|
27
27
|
}
|
|
28
28
|
export function completionScript(shell) {
|
|
@@ -7,12 +7,18 @@ import { log } from '../util/log.js';
|
|
|
7
7
|
import { color as c } from '../util/color.js';
|
|
8
8
|
import { t } from '../i18n.js';
|
|
9
9
|
// dev server + infra 生命周期:stop/start/restart 同时管 node(managed 进程)与 docker(stop 钩子 + setup 恢复),不动 worktree。
|
|
10
|
-
|
|
10
|
+
// services 为空 = 整功能;否则只这些服务
|
|
11
|
+
function occupantsOf(cfg, feature, services = []) {
|
|
11
12
|
const slot = slotOfFeature(cfg, feature);
|
|
12
13
|
if (slot === undefined)
|
|
13
14
|
throw new Error(t(`功能「${feature}」未占槽。先 \`worktree-bay up ${feature} <服务...>\` 起它。`, `feature "${feature}" hasn't claimed a slot. Run \`worktree-bay up ${feature} <services...>\` first.`));
|
|
14
15
|
const all = scanOccupancy(cfg).get(slot) ?? [];
|
|
15
|
-
|
|
16
|
+
if (!services.length)
|
|
17
|
+
return all;
|
|
18
|
+
for (const s of services)
|
|
19
|
+
if (!all.some((o) => o.service === s))
|
|
20
|
+
throw new Error(t(`服务「${s}」不在功能「${feature}」里。用 \`worktree-bay ls\` 看已起的服务。`, `service "${s}" is not in feature "${feature}". See \`worktree-bay ls\`.`));
|
|
21
|
+
return all.filter((o) => services.includes(o.service));
|
|
16
22
|
}
|
|
17
23
|
function ctxOf(cfg, o) {
|
|
18
24
|
const base = { cfg, service: o.service, sp: cfg.services[o.service], slot: o.slot, slug: o.slug, dir: o.dir, repo: repoPath(cfg, o.service) };
|
|
@@ -20,10 +26,10 @@ function ctxOf(cfg, o) {
|
|
|
20
26
|
}
|
|
21
27
|
// 该服务是否有「可停起的运行体」:managed dev server(start) 或可停的 infra(stop 钩子)
|
|
22
28
|
const hasRuntime = (cfg, service) => { const sp = cfg.services[service]; return !!(sp.start || sp.stop); };
|
|
23
|
-
export async function stopCommand(cfg, feature,
|
|
29
|
+
export async function stopCommand(cfg, feature, services = []) {
|
|
24
30
|
await withLock(cfg.workspaceRoot, async () => {
|
|
25
31
|
let any = false;
|
|
26
|
-
for (const o of occupantsOf(cfg, feature,
|
|
32
|
+
for (const o of occupantsOf(cfg, feature, services)) {
|
|
27
33
|
if (!hasRuntime(cfg, o.service))
|
|
28
34
|
continue;
|
|
29
35
|
any = true;
|
|
@@ -34,10 +40,10 @@ export async function stopCommand(cfg, feature, service) {
|
|
|
34
40
|
log(t('没有可停止的运行体(相关服务未配置 start/stop)', 'nothing to stop (no start/stop configured for those services)'));
|
|
35
41
|
});
|
|
36
42
|
}
|
|
37
|
-
export async function startCommand(cfg, feature,
|
|
43
|
+
export async function startCommand(cfg, feature, services = []) {
|
|
38
44
|
await withLock(cfg.workspaceRoot, async () => {
|
|
39
45
|
let any = false;
|
|
40
|
-
for (const o of occupantsOf(cfg, feature,
|
|
46
|
+
for (const o of occupantsOf(cfg, feature, services)) {
|
|
41
47
|
if (!hasRuntime(cfg, o.service))
|
|
42
48
|
continue;
|
|
43
49
|
any = true;
|
|
@@ -48,9 +54,9 @@ export async function startCommand(cfg, feature, service) {
|
|
|
48
54
|
log(t('没有可启动的运行体(相关服务未配置 start/stop)', 'nothing to start (no start/stop configured for those services)'));
|
|
49
55
|
});
|
|
50
56
|
}
|
|
51
|
-
export async function restartCommand(cfg, feature,
|
|
57
|
+
export async function restartCommand(cfg, feature, services = []) {
|
|
52
58
|
await withLock(cfg.workspaceRoot, async () => {
|
|
53
|
-
for (const o of occupantsOf(cfg, feature,
|
|
59
|
+
for (const o of occupantsOf(cfg, feature, services)) {
|
|
54
60
|
if (!hasRuntime(cfg, o.service))
|
|
55
61
|
continue;
|
|
56
62
|
const ctx = ctxOf(cfg, o);
|
package/dist/commands/rm.js
CHANGED
|
@@ -9,17 +9,24 @@ import { stopManaged } from '../proc.js';
|
|
|
9
9
|
import { log, warn } from '../util/log.js';
|
|
10
10
|
import { color as c } from '../util/color.js';
|
|
11
11
|
import { t } from '../i18n.js';
|
|
12
|
-
|
|
12
|
+
// services 为空 = 整功能;否则只这些服务(顺带校验服务名确实在该功能里)
|
|
13
|
+
export function resolveRm(cfg, feature, services = []) {
|
|
13
14
|
const slot = slotOfFeature(cfg, feature);
|
|
14
15
|
if (slot === undefined)
|
|
15
16
|
throw new Error(t(`功能「${feature}」未占槽,无需拆除。用 \`worktree-bay ls\` 看在用的功能。`, `feature "${feature}" has no slot — nothing to tear down. See \`worktree-bay ls\`.`));
|
|
16
17
|
const all = scanOccupancy(cfg).get(slot) ?? [];
|
|
17
|
-
|
|
18
|
+
if (!services.length)
|
|
19
|
+
return all;
|
|
20
|
+
for (const s of services)
|
|
21
|
+
if (!all.some((o) => o.service === s))
|
|
22
|
+
throw new Error(t(`服务「${s}」不在功能「${feature}」里。用 \`worktree-bay ls\` 看已起的服务。`, `service "${s}" is not in feature "${feature}". See \`worktree-bay ls\`.`));
|
|
23
|
+
return all.filter((o) => services.includes(o.service));
|
|
18
24
|
}
|
|
19
|
-
export async function rmCommand(cfg, feature,
|
|
25
|
+
export async function rmCommand(cfg, feature, services, force) {
|
|
20
26
|
await withLock(cfg.workspaceRoot, async () => {
|
|
21
27
|
let removed = 0;
|
|
22
|
-
const
|
|
28
|
+
const wholeFeature = services.length === 0;
|
|
29
|
+
const occs = resolveRm(cfg, feature, services);
|
|
23
30
|
for (const o of occs) {
|
|
24
31
|
const repo = repoPath(cfg, o.service);
|
|
25
32
|
const branch = currentBranch(o.dir);
|
|
@@ -41,7 +48,7 @@ export async function rmCommand(cfg, feature, service, force) {
|
|
|
41
48
|
removed++;
|
|
42
49
|
}
|
|
43
50
|
const slot = slotOfFeature(cfg, feature);
|
|
44
|
-
if (
|
|
51
|
+
if (wholeFeature && (scanOccupancy(cfg).get(slot) ?? []).length === 0) {
|
|
45
52
|
removeLabel(cfg, slot);
|
|
46
53
|
if (removed === 0)
|
|
47
54
|
log(`${c.green('✓')} ` + t(`释放空槽预约 "${feature}"(槽 ${slot})`, `released empty slot reservation "${feature}" (slot ${slot})`));
|
package/dist/mcp.js
CHANGED
|
@@ -52,18 +52,18 @@ export const TOOLS = [
|
|
|
52
52
|
{ name: 'worktree_bay_run', description: '在某功能某服务的运行体里跑预设命令(如 test),可透传额外参数',
|
|
53
53
|
inputSchema: { type: 'object', properties: { feature: str, service: str, name: str, args: { type: 'array', items: str } }, required: ['feature', 'service', 'name'] },
|
|
54
54
|
toArgs: (a) => ['run', String(a.feature), String(a.service), String(a.name), ...(a.args ?? [])] },
|
|
55
|
-
{ name: 'worktree_bay_start', description: '启动功能的运行体(docker 容器 + node dev server 一起),不动 worktree。
|
|
56
|
-
inputSchema: { type: 'object', properties: { feature: str,
|
|
57
|
-
toArgs: (a) => ['start', String(a.feature), ...(a.
|
|
58
|
-
{ name: 'worktree_bay_stop', description: '停止功能的运行体(停 docker 容器 + 杀 node dev server),保留 worktree。
|
|
59
|
-
inputSchema: { type: 'object', properties: { feature: str,
|
|
60
|
-
toArgs: (a) => ['stop', String(a.feature), ...(a.
|
|
61
|
-
{ name: 'worktree_bay_restart', description: '重启功能的运行体(停掉再起,docker + node 一起)。改了配置或端口卡住时用。
|
|
62
|
-
inputSchema: { type: 'object', properties: { feature: str,
|
|
63
|
-
toArgs: (a) => ['restart', String(a.feature), ...(a.
|
|
64
|
-
{ name: 'worktree_bay_down', description: '
|
|
65
|
-
inputSchema: { type: 'object', properties: { feature: str,
|
|
66
|
-
toArgs: (a) => ['
|
|
55
|
+
{ name: 'worktree_bay_start', description: '启动功能的运行体(docker 容器 + node dev server 一起),不动 worktree。services 省略=该功能所有服务,也可列多个。',
|
|
56
|
+
inputSchema: { type: 'object', properties: { feature: str, services: { type: 'array', items: str } }, required: ['feature'] },
|
|
57
|
+
toArgs: (a) => ['start', String(a.feature), ...(a.services ?? [])] },
|
|
58
|
+
{ name: 'worktree_bay_stop', description: '停止功能的运行体(停 docker 容器 + 杀 node dev server),保留 worktree。services 省略=全部,也可列多个。',
|
|
59
|
+
inputSchema: { type: 'object', properties: { feature: str, services: { type: 'array', items: str } }, required: ['feature'] },
|
|
60
|
+
toArgs: (a) => ['stop', String(a.feature), ...(a.services ?? [])] },
|
|
61
|
+
{ name: 'worktree_bay_restart', description: '重启功能的运行体(停掉再起,docker + node 一起)。改了配置或端口卡住时用。services 省略=全部,也可列多个。',
|
|
62
|
+
inputSchema: { type: 'object', properties: { feature: str, services: { type: 'array', items: str } }, required: ['feature'] },
|
|
63
|
+
toArgs: (a) => ['restart', String(a.feature), ...(a.services ?? [])] },
|
|
64
|
+
{ name: 'worktree_bay_down', description: '拆除 worktree:省略 services 拆整个功能(所有服务),给 services 只拆这些服务(默认查脏/未推保护,force=true 强删)',
|
|
65
|
+
inputSchema: { type: 'object', properties: { feature: str, services: { type: 'array', items: str }, force: { type: 'boolean' } }, required: ['feature'] },
|
|
66
|
+
toArgs: (a) => ['down', String(a.feature), ...(a.services ?? []), ...(a.force ? ['-f'] : [])] },
|
|
67
67
|
{ name: 'worktree_bay_gc', description: '合并感知回收:默认 dry-run 只列建议,apply=true 才实际删除「已合并且干净」的功能',
|
|
68
68
|
inputSchema: { type: 'object', properties: { apply: { type: 'boolean' } } },
|
|
69
69
|
toArgs: (a) => ['gc', ...(a.apply ? ['--apply'] : [])] },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "worktree-bay",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
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",
|
package/skill.md
CHANGED
|
@@ -35,11 +35,10 @@ worktree-bay completion install # 一键装 shell 补全(可选)
|
|
|
35
35
|
| `worktree-bay path <feature> <service>` | 打印某服务 worktree 的绝对路径(可 `cd $(worktree-bay path f api)`) |
|
|
36
36
|
| `worktree-bay run <feature> <service> <name> [args...]` | 在某服务运行体里跑配置的 `run.<name>`(如 test),透传 args |
|
|
37
37
|
| `worktree-bay sh <feature> <service>` | 进入某服务运行体的 shell |
|
|
38
|
-
| `worktree-bay start <feature> [
|
|
39
|
-
| `worktree-bay stop <feature> [
|
|
40
|
-
| `worktree-bay restart <feature> [
|
|
41
|
-
| `worktree-bay down <feature> [
|
|
42
|
-
| `worktree-bay rm <feature> [service] [-f]` | 拆除某服务或整槽。默认查脏/未推保护,`-f` 强删 |
|
|
38
|
+
| `worktree-bay start <feature> [services...]` | 启动功能的运行体(docker 容器 + node dev server 一起);**省略 = 全部**,也可列多个。不动 worktree |
|
|
39
|
+
| `worktree-bay stop <feature> [services...]` | 停止功能的运行体(停 docker + 杀 node dev server);省略 = 全部,可列多个。保留 worktree |
|
|
40
|
+
| `worktree-bay restart <feature> [services...]` | 重启运行体(停掉再起);省略 = 全部,可列多个 |
|
|
41
|
+
| `worktree-bay down <feature> [services...]` | 拆除 worktree(停运行体 + teardown + 删 worktree);**省略 services = 整功能**,也可列多个只拆这些。默认查脏/未推保护,`-f` 强删 |
|
|
43
42
|
| `worktree-bay gc [--apply]` | 合并感知回收:默认 dry-run 只列建议,`--apply` 才删「已合并且干净」的 |
|
|
44
43
|
| `worktree-bay completion <install\|bash\|zsh\|fish>` | `install` 一键装进 shell;或打印补全脚本 |
|
|
45
44
|
| `worktree-bay mcp` | 启动 MCP 服务(stdio,轻量脚本,客户端按需 spawn),供 AI 调用 |
|
|
@@ -157,8 +156,8 @@ worktree-bay gc # 回收已合并的
|
|
|
157
156
|
| ③ 在运行体里执行 | 跑命令 / 开 shell | — | `run` / `sh` | — |
|
|
158
157
|
|
|
159
158
|
- `up`:建 worktree+infra(首次)并起运行体;**重入 = 恢复运行体**(docker 挂了重跑 `up` 能拉回来,等价 `start`)。
|
|
160
|
-
- `start
|
|
161
|
-
- `down`
|
|
159
|
+
- 整套 runtime/teardown 命令统一为「一个动词 + `[services...]`(省略=全部)」:`start` / `stop` / `restart` / `down`。
|
|
160
|
+
- `up`(创建,服务必填)↔ `down`(拆除,服务可省=整功能)。`add` 是「单服务 + 自定义分支/基点」的精细创建,其反操作 = `down <feature> <service>`。
|
|
162
161
|
|
|
163
162
|
## 工作原理要点
|
|
164
163
|
|
|
@@ -172,7 +171,7 @@ worktree-bay gc # 回收已合并的
|
|
|
172
171
|
|
|
173
172
|
## 给 AI(MCP)
|
|
174
173
|
|
|
175
|
-
`worktree-bay mcp` 暴露工具:`worktree_bay_doctor / ls / up / claim / add / path / run / start / stop / restart / down / gc / init / skill`。`doctor` 列出全部服务(AI 借此得知服务名);`ls` 以 JSON 返回(含各 worktree 绝对路径、`▸run`);`path` 给某功能某服务的 worktree 目录;`start/stop/restart` 控制运行体(docker+node);`down` 省略
|
|
174
|
+
`worktree-bay mcp` 暴露工具:`worktree_bay_doctor / ls / up / claim / add / path / run / start / stop / restart / down / gc / init / skill`。`doctor` 列出全部服务(AI 借此得知服务名);`ls` 以 JSON 返回(含各 worktree 绝对路径、`▸run`);`path` 给某功能某服务的 worktree 目录;`start/stop/restart` 控制运行体(docker+node);`down` 省略 services 拆整功能、给 services 只拆这些。要写或修改 `worktree-bay.config.json`、或拿不准命令/配置细节时,调用 `worktree_bay_skill` 取本指南全文。
|
|
176
175
|
|
|
177
176
|
## 常见坑
|
|
178
177
|
|