worktree-bay 1.2.0 → 1.3.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/dist/cli.js +3 -3
- package/dist/mcp.js +63 -33
- package/package.json +2 -4
package/dist/cli.js
CHANGED
|
@@ -78,9 +78,9 @@ program.command('completion <target> [shell]').description('install 一键装进
|
|
|
78
78
|
catch (e) {
|
|
79
79
|
die(e.message);
|
|
80
80
|
} });
|
|
81
|
-
program.command('mcp').description('启动 MCP 服务(stdio),供 AI
|
|
82
|
-
.action(
|
|
83
|
-
|
|
81
|
+
program.command('mcp').description('启动 MCP 服务(stdio,轻量脚本,客户端按需 spawn),供 AI 调用 worktree-bay')
|
|
82
|
+
.action(() => { try {
|
|
83
|
+
startMcp();
|
|
84
84
|
}
|
|
85
85
|
catch (e) {
|
|
86
86
|
die(e.message);
|
package/dist/mcp.js
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
|
-
import { z } from 'zod';
|
|
4
1
|
import { spawnSync } from 'node:child_process';
|
|
5
2
|
import { fileURLToPath } from 'node:url';
|
|
6
3
|
import { readFileSync } from 'node:fs';
|
|
4
|
+
import readline from 'node:readline';
|
|
7
5
|
import path from 'node:path';
|
|
6
|
+
// 轻量脚本式 MCP:手写 JSON-RPC over stdio,零依赖。客户端按需 spawn,stdin 关闭即退出,非常驻守护进程。
|
|
8
7
|
const CLI = path.join(path.dirname(fileURLToPath(import.meta.url)), 'cli.js');
|
|
9
8
|
const VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
10
|
-
|
|
11
|
-
function runCli(args) {
|
|
12
|
-
const r = spawnSync(process.execPath, [CLI, ...args], { encoding: 'utf8' });
|
|
13
|
-
const text = [r.stdout, r.stderr].filter(Boolean).join('\n').trim() || '(无输出)';
|
|
14
|
-
return { content: [{ type: 'text', text }] };
|
|
15
|
-
}
|
|
9
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
16
10
|
export const INSTRUCTIONS = `worktree-bay 是「功能 = 槽位」的并行开发编排器。当你需要在一个多服务工作区里并行开发多个功能、又不想让它们的端口/依赖/数据互相干扰时,用本服务的工具来完成开发工作。
|
|
17
11
|
|
|
18
12
|
核心模型:一个功能占一个「槽位」→ 得到一个端口块;该功能用到哪些服务,就在哪些服务上各开一个 git worktree 挂进这个槽,端口自动错开,前端自动连到同槽的后端。
|
|
@@ -28,29 +22,65 @@ export const INSTRUCTIONS = `worktree-bay 是「功能 = 槽位」的并行开
|
|
|
28
22
|
- 只起这个功能「实际要改」的服务,不要全起。
|
|
29
23
|
- 拿不准当前状态时先调 worktree_bay_ls。
|
|
30
24
|
- worktree_bay_gc 默认只读(dry-run 列出建议),apply=true 才真删,且只删「已合并到主分支且工作区干净」的,安全保守、不会误删未完成的工作。`;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
services:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
feature:
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
feature:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
25
|
+
const str = { type: 'string' };
|
|
26
|
+
export const TOOLS = [
|
|
27
|
+
{ name: 'worktree_bay_ls', description: '列出所有功能槽位与占用(功能名、端口块、已起服务及端口、是否已并入主分支)',
|
|
28
|
+
inputSchema: { type: 'object', properties: {} }, toArgs: () => ['ls'] },
|
|
29
|
+
{ name: 'worktree_bay_up', description: '为一个功能一次性起多个服务(自动占槽 + 各服务开 worktree,分支默认=功能名,前端自动接同槽后端)。并行开发新功能首选。',
|
|
30
|
+
inputSchema: { type: 'object', properties: { feature: str, services: { type: 'array', items: str } }, required: ['feature', 'services'] },
|
|
31
|
+
toArgs: (a) => ['up', String(a.feature), ...(a.services ?? [])] },
|
|
32
|
+
{ name: 'worktree_bay_add', description: '为功能在单个服务上开 worktree(branch 省略则用功能名)',
|
|
33
|
+
inputSchema: { type: 'object', properties: { feature: str, service: str, branch: str }, required: ['feature', 'service'] },
|
|
34
|
+
toArgs: (a) => ['add', String(a.feature), String(a.service), ...(a.branch ? [String(a.branch)] : [])] },
|
|
35
|
+
{ name: 'worktree_bay_run', description: '在某功能某服务的运行体里跑预设命令(如 test),可透传额外参数',
|
|
36
|
+
inputSchema: { type: 'object', properties: { feature: str, service: str, name: str, args: { type: 'array', items: str } }, required: ['feature', 'service', 'name'] },
|
|
37
|
+
toArgs: (a) => ['run', String(a.feature), String(a.service), String(a.name), ...(a.args ?? [])] },
|
|
38
|
+
{ name: 'worktree_bay_down', description: '拆除整个功能的所有服务 worktree(默认查脏/未推保护,force=true 强删)',
|
|
39
|
+
inputSchema: { type: 'object', properties: { feature: str, force: { type: 'boolean' } }, required: ['feature'] },
|
|
40
|
+
toArgs: (a) => ['down', String(a.feature), ...(a.force ? ['-f'] : [])] },
|
|
41
|
+
{ name: 'worktree_bay_gc', description: '合并感知回收:默认 dry-run 只列建议,apply=true 才实际删除「已合并且干净」的功能',
|
|
42
|
+
inputSchema: { type: 'object', properties: { apply: { type: 'boolean' } } },
|
|
43
|
+
toArgs: (a) => ['gc', ...(a.apply ? ['--apply'] : [])] },
|
|
44
|
+
];
|
|
45
|
+
function runCli(args) {
|
|
46
|
+
const r = spawnSync(process.execPath, [CLI, ...args], { encoding: 'utf8' });
|
|
47
|
+
return [r.stdout, r.stderr].filter(Boolean).join('\n').trim() || '(无输出)';
|
|
48
|
+
}
|
|
49
|
+
export function handle(msg) {
|
|
50
|
+
const { id, method, params } = msg;
|
|
51
|
+
if (method === 'initialize')
|
|
52
|
+
return { jsonrpc: '2.0', id, result: { protocolVersion: PROTOCOL_VERSION, capabilities: { tools: {} }, serverInfo: { name: 'worktree-bay', version: VERSION }, instructions: INSTRUCTIONS } };
|
|
53
|
+
if (method === 'tools/list')
|
|
54
|
+
return { jsonrpc: '2.0', id, result: { tools: TOOLS.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })) } };
|
|
55
|
+
if (method === 'tools/call') {
|
|
56
|
+
const tool = TOOLS.find((t) => t.name === params?.name);
|
|
57
|
+
if (!tool)
|
|
58
|
+
return { jsonrpc: '2.0', id, error: { code: -32602, message: 'unknown tool: ' + params?.name } };
|
|
59
|
+
return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: runCli(tool.toArgs(params?.arguments ?? {})) }] } };
|
|
60
|
+
}
|
|
61
|
+
if (method === 'ping')
|
|
62
|
+
return { jsonrpc: '2.0', id, result: {} };
|
|
63
|
+
if (method?.startsWith('notifications/'))
|
|
64
|
+
return null;
|
|
65
|
+
if (id !== undefined)
|
|
66
|
+
return { jsonrpc: '2.0', id, error: { code: -32601, message: 'method not found: ' + method } };
|
|
67
|
+
return null;
|
|
53
68
|
}
|
|
54
|
-
export
|
|
55
|
-
|
|
69
|
+
export function startMcp() {
|
|
70
|
+
const rl = readline.createInterface({ input: process.stdin });
|
|
71
|
+
rl.on('line', (line) => {
|
|
72
|
+
const t = line.trim();
|
|
73
|
+
if (!t)
|
|
74
|
+
return;
|
|
75
|
+
let msg;
|
|
76
|
+
try {
|
|
77
|
+
msg = JSON.parse(t);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const res = handle(msg);
|
|
83
|
+
if (res)
|
|
84
|
+
process.stdout.write(JSON.stringify(res) + '\n');
|
|
85
|
+
});
|
|
56
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "worktree-bay",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Config-driven git worktree slot + port orchestrator for parallel multi-service development",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"git",
|
|
@@ -43,9 +43,7 @@
|
|
|
43
43
|
"registry": "https://registry.npmjs.org"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"
|
|
47
|
-
"commander": "^12.1.0",
|
|
48
|
-
"zod": "^3.23.8"
|
|
46
|
+
"commander": "^12.1.0"
|
|
49
47
|
},
|
|
50
48
|
"devDependencies": {
|
|
51
49
|
"@types/node": "^22.0.0",
|