@geeseeker/easyai-dev 3.0.0-alpha.1 → 3.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/README.md +90 -88
- package/README_AI.md +143 -0
- package/bin/easyai-dev.js +127 -1
- package/lib/init.js +425 -0
- package/lib/server/index.d.ts +14 -0
- package/lib/server/index.d.ts.map +1 -0
- package/lib/server/index.js +126 -0
- package/lib/server/index.js.map +1 -0
- package/lib/server/resources/journal-resource.d.ts +8 -0
- package/lib/server/resources/journal-resource.d.ts.map +1 -0
- package/lib/server/resources/journal-resource.js +46 -0
- package/lib/server/resources/journal-resource.js.map +1 -0
- package/lib/server/resources/spec-resource.d.ts +11 -0
- package/lib/server/resources/spec-resource.d.ts.map +1 -0
- package/lib/server/resources/spec-resource.js +126 -0
- package/lib/server/resources/spec-resource.js.map +1 -0
- package/lib/server/resources/status-resource.d.ts +8 -0
- package/lib/server/resources/status-resource.d.ts.map +1 -0
- package/lib/server/resources/status-resource.js +36 -0
- package/lib/server/resources/status-resource.js.map +1 -0
- package/lib/server/resources/subtask-context-resource.d.ts +8 -0
- package/lib/server/resources/subtask-context-resource.d.ts.map +1 -0
- package/lib/server/resources/subtask-context-resource.js +93 -0
- package/lib/server/resources/subtask-context-resource.js.map +1 -0
- package/lib/server/resources/task-context-resource.d.ts +8 -0
- package/lib/server/resources/task-context-resource.d.ts.map +1 -0
- package/lib/server/resources/task-context-resource.js +76 -0
- package/lib/server/resources/task-context-resource.js.map +1 -0
- package/lib/server/tools/conflict-check.d.ts +7 -0
- package/lib/server/tools/conflict-check.d.ts.map +1 -0
- package/lib/server/tools/conflict-check.js +242 -0
- package/lib/server/tools/conflict-check.js.map +1 -0
- package/lib/server/tools/context-budget.d.ts +7 -0
- package/lib/server/tools/context-budget.d.ts.map +1 -0
- package/lib/server/tools/context-budget.js +178 -0
- package/lib/server/tools/context-budget.js.map +1 -0
- package/lib/server/tools/context-generate.d.ts +7 -0
- package/lib/server/tools/context-generate.d.ts.map +1 -0
- package/lib/server/tools/context-generate.js +208 -0
- package/lib/server/tools/context-generate.js.map +1 -0
- package/lib/server/tools/framework-tools.d.ts +20 -0
- package/lib/server/tools/framework-tools.d.ts.map +1 -0
- package/lib/server/tools/framework-tools.js +412 -0
- package/lib/server/tools/framework-tools.js.map +1 -0
- package/lib/server/tools/journal-append.d.ts +7 -0
- package/lib/server/tools/journal-append.d.ts.map +1 -0
- package/lib/server/tools/journal-append.js +55 -0
- package/lib/server/tools/journal-append.js.map +1 -0
- package/lib/server/tools/journal-search.d.ts +7 -0
- package/lib/server/tools/journal-search.d.ts.map +1 -0
- package/lib/server/tools/journal-search.js +63 -0
- package/lib/server/tools/journal-search.js.map +1 -0
- package/lib/server/tools/plan-validate.d.ts +7 -0
- package/lib/server/tools/plan-validate.d.ts.map +1 -0
- package/lib/server/tools/plan-validate.js +146 -0
- package/lib/server/tools/plan-validate.js.map +1 -0
- package/lib/server/tools/spec-validate.d.ts +7 -0
- package/lib/server/tools/spec-validate.d.ts.map +1 -0
- package/lib/server/tools/spec-validate.js +170 -0
- package/lib/server/tools/spec-validate.js.map +1 -0
- package/lib/server/tools/subtask-tools.d.ts +12 -0
- package/lib/server/tools/subtask-tools.d.ts.map +1 -0
- package/lib/server/tools/subtask-tools.js +383 -0
- package/lib/server/tools/subtask-tools.js.map +1 -0
- package/lib/server/tools/task-append-log.d.ts +7 -0
- package/lib/server/tools/task-append-log.d.ts.map +1 -0
- package/lib/server/tools/task-append-log.js +108 -0
- package/lib/server/tools/task-append-log.js.map +1 -0
- package/lib/server/tools/task-cancel.d.ts +7 -0
- package/lib/server/tools/task-cancel.d.ts.map +1 -0
- package/lib/server/tools/task-cancel.js +104 -0
- package/lib/server/tools/task-cancel.js.map +1 -0
- package/lib/server/tools/task-create.d.ts +7 -0
- package/lib/server/tools/task-create.d.ts.map +1 -0
- package/lib/server/tools/task-create.js +98 -0
- package/lib/server/tools/task-create.js.map +1 -0
- package/lib/server/tools/task-get.d.ts +7 -0
- package/lib/server/tools/task-get.d.ts.map +1 -0
- package/lib/server/tools/task-get.js +152 -0
- package/lib/server/tools/task-get.js.map +1 -0
- package/lib/server/tools/task-list.d.ts +7 -0
- package/lib/server/tools/task-list.d.ts.map +1 -0
- package/lib/server/tools/task-list.js +66 -0
- package/lib/server/tools/task-list.js.map +1 -0
- package/lib/server/tools/task-transition.d.ts +7 -0
- package/lib/server/tools/task-transition.d.ts.map +1 -0
- package/lib/server/tools/task-transition.js +259 -0
- package/lib/server/tools/task-transition.js.map +1 -0
- package/lib/server/tools/worktree-tools.d.ts +17 -0
- package/lib/server/tools/worktree-tools.d.ts.map +1 -0
- package/lib/server/tools/worktree-tools.js +336 -0
- package/lib/server/tools/worktree-tools.js.map +1 -0
- package/lib/server/utils/capability-gate.d.ts +50 -0
- package/lib/server/utils/capability-gate.d.ts.map +1 -0
- package/lib/server/utils/capability-gate.js +146 -0
- package/lib/server/utils/capability-gate.js.map +1 -0
- package/lib/server/utils/git-utils.d.ts +33 -0
- package/lib/server/utils/git-utils.d.ts.map +1 -0
- package/lib/server/utils/git-utils.js +84 -0
- package/lib/server/utils/git-utils.js.map +1 -0
- package/lib/server/utils/hash-utils.d.ts +78 -0
- package/lib/server/utils/hash-utils.d.ts.map +1 -0
- package/lib/server/utils/hash-utils.js +153 -0
- package/lib/server/utils/hash-utils.js.map +1 -0
- package/lib/server/utils/journal-utils.d.ts +69 -0
- package/lib/server/utils/journal-utils.d.ts.map +1 -0
- package/lib/server/utils/journal-utils.js +387 -0
- package/lib/server/utils/journal-utils.js.map +1 -0
- package/lib/server/utils/status-utils.d.ts +58 -0
- package/lib/server/utils/status-utils.d.ts.map +1 -0
- package/lib/server/utils/status-utils.js +70 -0
- package/lib/server/utils/status-utils.js.map +1 -0
- package/lib/server/utils/task-utils.d.ts +104 -0
- package/lib/server/utils/task-utils.d.ts.map +1 -0
- package/lib/server/utils/task-utils.js +396 -0
- package/lib/server/utils/task-utils.js.map +1 -0
- package/lib/server/utils/uri-utils.d.ts +9 -0
- package/lib/server/utils/uri-utils.d.ts.map +1 -0
- package/lib/server/utils/uri-utils.js +21 -0
- package/lib/server/utils/uri-utils.js.map +1 -0
- package/package.json +30 -21
- package/skeleton/.agents/rules/anti-hallucination.md +42 -0
- package/skeleton/.agents/rules/coding-standards.md +41 -0
- package/skeleton/.agents/rules/project-identity.md +71 -0
- package/skeleton/.agents/skills/common-framework-evolve/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-framework-evolve/SKILL.md +105 -0
- package/skeleton/.agents/skills/common-session-close/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-session-close/SKILL.md +83 -0
- package/skeleton/.agents/skills/common-spec-update/.gitkeep +0 -0
- package/skeleton/.agents/skills/common-spec-update/SKILL.md +87 -0
- package/skeleton/.agents/skills/pm-brainstorm/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-brainstorm/SKILL.md +114 -0
- package/skeleton/.agents/skills/pm-session-start/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-session-start/SKILL.md +73 -0
- package/skeleton/.agents/skills/pm-task-planning/SKILL.md +200 -0
- package/skeleton/.agents/skills/pm-task-review/.gitkeep +0 -0
- package/skeleton/.agents/skills/pm-task-review/SKILL.md +144 -0
- package/skeleton/.agents/skills/worker-check/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-check/SKILL.md +194 -0
- package/skeleton/.agents/skills/worker-debug/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-debug/SKILL.md +241 -0
- package/skeleton/.agents/skills/worker-implement/.gitkeep +0 -0
- package/skeleton/.agents/skills/worker-implement/SKILL.md +192 -0
- package/skeleton/.agents/workflows/pm.md +81 -0
- package/skeleton/.agents/workflows/worker.md +100 -0
- package/skeleton/.docs/README.md +25 -0
- package/skeleton/.docs/archive/.gitkeep +0 -0
- package/skeleton/.docs/design/.gitkeep +0 -0
- package/skeleton/.docs/guides/.gitkeep +0 -0
- package/skeleton/.docs/notes/.gitkeep +0 -0
- package/skeleton/.docs/requirements/.gitkeep +0 -0
- package/skeleton/.trellis/config/config.yaml +48 -0
- package/skeleton/.trellis/spec/backend/.gitkeep +0 -0
- package/skeleton/.trellis/spec/frontend/.gitkeep +0 -0
- package/skeleton/.trellis/spec/guides/.gitkeep +0 -0
- package/skeleton/.trellis/spec/guides/external-cli-guide.md +253 -0
- package/skeleton/.trellis/spec/guides/task-workflow.md +34 -0
- package/skeleton/.trellis/spec/guides/testing.md +32 -0
- package/skeleton/.trellis/spec/spec-schema.json +64 -0
- package/skeleton/.trellis/tasks/.gitkeep +0 -0
- package/skeleton/.trellis/workspace/.gitkeep +0 -0
- package/skeleton/README.md +25 -0
- package/LICENSE +0 -21
- package/src/cli/index.js +0 -40
- package/src/commands/init.js +0 -37
- package/src/commands/update.js +0 -33
- package/templates/README.md +0 -22
- package/templates/agents/README.md +0 -4
- package/templates/trellis/README.md +0 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
/**
|
|
3
|
+
* 注册 worktree_create 工具
|
|
4
|
+
* 为任务创建隔离的 Git worktree
|
|
5
|
+
*/
|
|
6
|
+
export declare function registerWorktreeCreate(server: McpServer): void;
|
|
7
|
+
/**
|
|
8
|
+
* 注册 worktree_merge 工具
|
|
9
|
+
* 将 worktree 分支合并回目标分支
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerWorktreeMerge(server: McpServer): void;
|
|
12
|
+
/**
|
|
13
|
+
* 注册 worktree_cleanup 工具
|
|
14
|
+
* 清理已完成任务的 worktree
|
|
15
|
+
*/
|
|
16
|
+
export declare function registerWorktreeCleanup(server: McpServer): void;
|
|
17
|
+
//# sourceMappingURL=worktree-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-tools.d.ts","sourceRoot":"","sources":["../../src/tools/worktree-tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgEpE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuG9D;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAsH7D;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6F/D"}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { execFileSync } from "node:child_process";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { getTaskDir } from "../utils/task-utils.js";
|
|
6
|
+
import { checkCapability, capabilityError, isValidGitRef, } from "../utils/capability-gate.js";
|
|
7
|
+
// ============ 内部工具函数 ============
|
|
8
|
+
/**
|
|
9
|
+
* 获取 Git 仓库根目录
|
|
10
|
+
*/
|
|
11
|
+
function getGitRoot() {
|
|
12
|
+
return execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
}).trim();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 获取任务对应的 worktree 分支名
|
|
18
|
+
*/
|
|
19
|
+
function getWorktreeBranch(taskId) {
|
|
20
|
+
return `worktree/${taskId}`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 获取任务对应的 worktree 目录路径
|
|
24
|
+
*/
|
|
25
|
+
function getWorktreePath(taskId) {
|
|
26
|
+
const gitRoot = getGitRoot();
|
|
27
|
+
return path.join(gitRoot, ".worktrees", taskId);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 校验 Git ref 合法性并返回错误响应(如果非法)
|
|
31
|
+
*/
|
|
32
|
+
function validateRef(ref, label) {
|
|
33
|
+
if (!isValidGitRef(ref)) {
|
|
34
|
+
return {
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: "text",
|
|
38
|
+
text: JSON.stringify({
|
|
39
|
+
error: true,
|
|
40
|
+
message: `非法的 ${label}: "${ref}"。` +
|
|
41
|
+
"分支名不能包含特殊字符、空格或以 - 开头。",
|
|
42
|
+
}),
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
// ============ Tool 注册 ============
|
|
51
|
+
/**
|
|
52
|
+
* 注册 worktree_create 工具
|
|
53
|
+
* 为任务创建隔离的 Git worktree
|
|
54
|
+
*/
|
|
55
|
+
export function registerWorktreeCreate(server) {
|
|
56
|
+
server.tool("worktree_create", "为指定任务创建 Git worktree,提供并行任务的物理隔离。", {
|
|
57
|
+
task_id: z.string(),
|
|
58
|
+
base_branch: z.string().optional(),
|
|
59
|
+
role: z.string().optional(),
|
|
60
|
+
}, async ({ task_id, base_branch, role }) => {
|
|
61
|
+
try {
|
|
62
|
+
// Capability Gate
|
|
63
|
+
const reject = checkCapability(role, "worktree_create");
|
|
64
|
+
if (reject) {
|
|
65
|
+
return capabilityError(reject);
|
|
66
|
+
}
|
|
67
|
+
// 检查任务是否存在
|
|
68
|
+
const taskDir = getTaskDir(task_id);
|
|
69
|
+
if (!fs.existsSync(taskDir)) {
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: JSON.stringify({
|
|
75
|
+
error: true,
|
|
76
|
+
message: `任务 ${task_id} 不存在`,
|
|
77
|
+
}),
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
isError: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const worktreePath = getWorktreePath(task_id);
|
|
84
|
+
const branch = getWorktreeBranch(task_id);
|
|
85
|
+
const baseBranch = base_branch || "main";
|
|
86
|
+
// 校验分支名合法性(防注入)
|
|
87
|
+
const refError = validateRef(baseBranch, "base_branch");
|
|
88
|
+
if (refError)
|
|
89
|
+
return refError;
|
|
90
|
+
// 检查 worktree 是否已存在
|
|
91
|
+
if (fs.existsSync(worktreePath)) {
|
|
92
|
+
return {
|
|
93
|
+
content: [
|
|
94
|
+
{
|
|
95
|
+
type: "text",
|
|
96
|
+
text: JSON.stringify({
|
|
97
|
+
error: true,
|
|
98
|
+
message: `任务 ${task_id} 的 worktree 已存在: ` + worktreePath,
|
|
99
|
+
}),
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// 创建 worktree 目录
|
|
106
|
+
fs.mkdirSync(path.dirname(worktreePath), { recursive: true });
|
|
107
|
+
// 使用 execFileSync 创建 worktree(防 shell 注入)
|
|
108
|
+
execFileSync("git", ["worktree", "add", "-b", branch, worktreePath, baseBranch], { encoding: "utf-8" });
|
|
109
|
+
return {
|
|
110
|
+
content: [
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: JSON.stringify({
|
|
114
|
+
task_id,
|
|
115
|
+
worktree_path: worktreePath,
|
|
116
|
+
branch,
|
|
117
|
+
base_branch: baseBranch,
|
|
118
|
+
message: `任务 ${task_id} 的 worktree 已创建`,
|
|
119
|
+
}, null, 2),
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
return {
|
|
126
|
+
content: [
|
|
127
|
+
{
|
|
128
|
+
type: "text",
|
|
129
|
+
text: JSON.stringify({
|
|
130
|
+
error: true,
|
|
131
|
+
message: error instanceof Error ? error.message : String(error),
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
isError: true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 注册 worktree_merge 工具
|
|
142
|
+
* 将 worktree 分支合并回目标分支
|
|
143
|
+
*/
|
|
144
|
+
export function registerWorktreeMerge(server) {
|
|
145
|
+
server.tool("worktree_merge", "将指定任务的 worktree 分支合并回目标分支。", {
|
|
146
|
+
task_id: z.string(),
|
|
147
|
+
target_branch: z.string().optional(),
|
|
148
|
+
role: z.string().optional(),
|
|
149
|
+
}, async ({ task_id, target_branch, role }) => {
|
|
150
|
+
try {
|
|
151
|
+
// Capability Gate
|
|
152
|
+
const reject = checkCapability(role, "worktree_merge");
|
|
153
|
+
if (reject) {
|
|
154
|
+
return capabilityError(reject);
|
|
155
|
+
}
|
|
156
|
+
const worktreePath = getWorktreePath(task_id);
|
|
157
|
+
const branch = getWorktreeBranch(task_id);
|
|
158
|
+
const target = target_branch || "main";
|
|
159
|
+
// 校验分支名合法性
|
|
160
|
+
const refError = validateRef(target, "target_branch");
|
|
161
|
+
if (refError)
|
|
162
|
+
return refError;
|
|
163
|
+
// 检查 worktree 是否存在
|
|
164
|
+
if (!fs.existsSync(worktreePath)) {
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: JSON.stringify({
|
|
170
|
+
error: true,
|
|
171
|
+
message: `任务 ${task_id} 的 worktree 不存在`,
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
isError: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const gitRoot = getGitRoot();
|
|
179
|
+
// 先切换到目标分支再合并
|
|
180
|
+
execFileSync("git", ["checkout", target], {
|
|
181
|
+
encoding: "utf-8",
|
|
182
|
+
cwd: gitRoot,
|
|
183
|
+
});
|
|
184
|
+
// 执行合并
|
|
185
|
+
try {
|
|
186
|
+
const mergeMsg = `Merge ${branch} into ${target}`;
|
|
187
|
+
execFileSync("git", ["merge", branch, "--no-ff", "-m", mergeMsg], {
|
|
188
|
+
encoding: "utf-8",
|
|
189
|
+
cwd: gitRoot,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
catch (mergeError) {
|
|
193
|
+
// 合并冲突时中止合并并报告
|
|
194
|
+
try {
|
|
195
|
+
execFileSync("git", ["merge", "--abort"], {
|
|
196
|
+
encoding: "utf-8",
|
|
197
|
+
cwd: gitRoot,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
// 忽略 --abort 错误
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
content: [
|
|
205
|
+
{
|
|
206
|
+
type: "text",
|
|
207
|
+
text: JSON.stringify({
|
|
208
|
+
error: true,
|
|
209
|
+
message: "合并失败:可能存在冲突。" + "请手动解决冲突后重试。",
|
|
210
|
+
details: mergeError instanceof Error
|
|
211
|
+
? mergeError.message
|
|
212
|
+
: String(mergeError),
|
|
213
|
+
}),
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
isError: true,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
content: [
|
|
221
|
+
{
|
|
222
|
+
type: "text",
|
|
223
|
+
text: JSON.stringify({
|
|
224
|
+
task_id,
|
|
225
|
+
merged_branch: branch,
|
|
226
|
+
target_branch: target,
|
|
227
|
+
message: `分支 ${branch} 已合并到 ${target}`,
|
|
228
|
+
}, null, 2),
|
|
229
|
+
},
|
|
230
|
+
],
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
catch (error) {
|
|
234
|
+
return {
|
|
235
|
+
content: [
|
|
236
|
+
{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: JSON.stringify({
|
|
239
|
+
error: true,
|
|
240
|
+
message: error instanceof Error ? error.message : String(error),
|
|
241
|
+
}),
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
isError: true,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* 注册 worktree_cleanup 工具
|
|
251
|
+
* 清理已完成任务的 worktree
|
|
252
|
+
*/
|
|
253
|
+
export function registerWorktreeCleanup(server) {
|
|
254
|
+
server.tool("worktree_cleanup", "清理指定任务的 worktree 及其分支。", {
|
|
255
|
+
task_id: z.string(),
|
|
256
|
+
delete_branch: z.boolean().optional(),
|
|
257
|
+
role: z.string().optional(),
|
|
258
|
+
}, async ({ task_id, delete_branch, role }) => {
|
|
259
|
+
try {
|
|
260
|
+
// Capability Gate
|
|
261
|
+
const reject = checkCapability(role, "worktree_cleanup");
|
|
262
|
+
if (reject) {
|
|
263
|
+
return capabilityError(reject);
|
|
264
|
+
}
|
|
265
|
+
const worktreePath = getWorktreePath(task_id);
|
|
266
|
+
const branch = getWorktreeBranch(task_id);
|
|
267
|
+
// 检查 worktree 是否存在
|
|
268
|
+
if (!fs.existsSync(worktreePath)) {
|
|
269
|
+
return {
|
|
270
|
+
content: [
|
|
271
|
+
{
|
|
272
|
+
type: "text",
|
|
273
|
+
text: JSON.stringify({
|
|
274
|
+
error: true,
|
|
275
|
+
message: `任务 ${task_id} 的 worktree 不存在`,
|
|
276
|
+
}),
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
isError: true,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
// 使用 execFileSync 移除 worktree(防 shell 注入)
|
|
283
|
+
execFileSync("git", ["worktree", "remove", worktreePath, "--force"], {
|
|
284
|
+
encoding: "utf-8",
|
|
285
|
+
});
|
|
286
|
+
// 可选:删除分支
|
|
287
|
+
const branchDeleted = delete_branch !== false;
|
|
288
|
+
if (branchDeleted) {
|
|
289
|
+
try {
|
|
290
|
+
execFileSync("git", ["branch", "-d", branch], {
|
|
291
|
+
encoding: "utf-8",
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
catch {
|
|
295
|
+
// 分支未合并时尝试强制删除
|
|
296
|
+
try {
|
|
297
|
+
execFileSync("git", ["branch", "-D", branch], {
|
|
298
|
+
encoding: "utf-8",
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
// 分支已不存在,忽略
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
content: [
|
|
308
|
+
{
|
|
309
|
+
type: "text",
|
|
310
|
+
text: JSON.stringify({
|
|
311
|
+
task_id,
|
|
312
|
+
worktree_removed: worktreePath,
|
|
313
|
+
branch_deleted: branchDeleted ? branch : null,
|
|
314
|
+
message: `任务 ${task_id} 的 worktree 已清理`,
|
|
315
|
+
}, null, 2),
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
catch (error) {
|
|
321
|
+
return {
|
|
322
|
+
content: [
|
|
323
|
+
{
|
|
324
|
+
type: "text",
|
|
325
|
+
text: JSON.stringify({
|
|
326
|
+
error: true,
|
|
327
|
+
message: error instanceof Error ? error.message : String(error),
|
|
328
|
+
}),
|
|
329
|
+
},
|
|
330
|
+
],
|
|
331
|
+
isError: true,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=worktree-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktree-tools.js","sourceRoot":"","sources":["../../src/tools/worktree-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 角色类型
|
|
3
|
+
*/
|
|
4
|
+
type Role = "pm" | "组长" | "组员" | "worker";
|
|
5
|
+
/**
|
|
6
|
+
* 受限工具名称
|
|
7
|
+
*/
|
|
8
|
+
type RestrictedTool = "task_create" | "task_transition_completed" | "task_transition_archived" | "task_cancel" | "subtask_create" | "subtask_dependency_graph" | "conflict_check" | "worktree_create" | "worktree_merge" | "worktree_cleanup";
|
|
9
|
+
/**
|
|
10
|
+
* 角色权限矩阵(来自 architecture §7.1)
|
|
11
|
+
*
|
|
12
|
+
* true = 允许, false = 拒绝
|
|
13
|
+
*/
|
|
14
|
+
declare const CAPABILITY_MATRIX: Record<RestrictedTool, Record<Role, boolean>>;
|
|
15
|
+
/**
|
|
16
|
+
* 校验角色是否有权调用指定工具
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ 诚实的局限性说明(architecture §7.1):
|
|
19
|
+
* - 角色来源:AI 在 Workflow 触发时自行解析用户输入并写入 Artifacts
|
|
20
|
+
* - 信任模型:MCP Server 信任 AI 传入的 role 参数,无法独立验证 AI 角色
|
|
21
|
+
* - 防护强度:可防止"无意越权",无法防止"故意越权"
|
|
22
|
+
*
|
|
23
|
+
* @param role - 调用者角色(未提供时拒绝受限操作)
|
|
24
|
+
* @param toolName - 受限工具名称
|
|
25
|
+
* @returns null 表示通过,string 表示拒绝理由
|
|
26
|
+
*/
|
|
27
|
+
declare function checkCapability(role: string | undefined, toolName: RestrictedTool): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* 规范化角色名(支持多种写法)
|
|
30
|
+
*/
|
|
31
|
+
declare function normalizeRole(role: string): Role | null;
|
|
32
|
+
/**
|
|
33
|
+
* 校验 Git ref 名称是否合法(防注入)
|
|
34
|
+
* @param ref - 分支名或标签名
|
|
35
|
+
* @returns true 表示合法
|
|
36
|
+
*/
|
|
37
|
+
declare function isValidGitRef(ref: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* 生成 Capability Gate 拒绝的标准 MCP 错误响应
|
|
40
|
+
*/
|
|
41
|
+
declare function capabilityError(rejectReason: string): {
|
|
42
|
+
content: {
|
|
43
|
+
type: "text";
|
|
44
|
+
text: string;
|
|
45
|
+
}[];
|
|
46
|
+
isError: boolean;
|
|
47
|
+
};
|
|
48
|
+
export type { Role, RestrictedTool };
|
|
49
|
+
export { CAPABILITY_MATRIX, checkCapability, normalizeRole, isValidGitRef, capabilityError, };
|
|
50
|
+
//# sourceMappingURL=capability-gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-gate.d.ts","sourceRoot":"","sources":["../../src/utils/capability-gate.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,QAAQ,CAAC;AAE1C;;GAEG;AACH,KAAK,cAAc,GACf,aAAa,GACb,2BAA2B,GAC3B,0BAA0B,GAC1B,aAAa,GACb,gBAAgB,GAChB,0BAA0B,GAC1B,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB;;;;GAIG;AACH,QAAA,MAAM,iBAAiB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CA0BpE,CAAC;AAIF;;;;;;;;;;;GAWG;AACH,iBAAS,eAAe,CACtB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,QAAQ,EAAE,cAAc,GACvB,MAAM,GAAG,IAAI,CAoCf;AAED;;GAEG;AACH,iBAAS,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAkChD;AAED;;;;GAIG;AACH,iBAAS,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAY3C;AAED;;GAEG;AACH,iBAAS,eAAe,CAAC,YAAY,EAAE,MAAM;;;;;;EAc5C;AAID,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AACrC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,aAAa,EACb,aAAa,EACb,eAAe,GAChB,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// ============ 类型定义 ============
|
|
2
|
+
/**
|
|
3
|
+
* 角色权限矩阵(来自 architecture §7.1)
|
|
4
|
+
*
|
|
5
|
+
* true = 允许, false = 拒绝
|
|
6
|
+
*/
|
|
7
|
+
const CAPABILITY_MATRIX = {
|
|
8
|
+
task_create: { pm: true, 组长: false, 组员: false, worker: false },
|
|
9
|
+
task_transition_completed: {
|
|
10
|
+
pm: true,
|
|
11
|
+
组长: false,
|
|
12
|
+
组员: false,
|
|
13
|
+
worker: false,
|
|
14
|
+
},
|
|
15
|
+
task_transition_archived: {
|
|
16
|
+
pm: true,
|
|
17
|
+
组长: false,
|
|
18
|
+
组员: false,
|
|
19
|
+
worker: false,
|
|
20
|
+
},
|
|
21
|
+
task_cancel: { pm: true, 组长: false, 组员: false, worker: false },
|
|
22
|
+
subtask_create: { pm: false, 组长: true, 组员: false, worker: false },
|
|
23
|
+
subtask_dependency_graph: {
|
|
24
|
+
pm: true,
|
|
25
|
+
组长: true,
|
|
26
|
+
组员: false,
|
|
27
|
+
worker: false,
|
|
28
|
+
},
|
|
29
|
+
conflict_check: { pm: true, 组长: true, 组员: false, worker: false },
|
|
30
|
+
worktree_create: { pm: true, 组长: false, 组员: false, worker: false },
|
|
31
|
+
worktree_merge: { pm: true, 组长: false, 组员: false, worker: false },
|
|
32
|
+
worktree_cleanup: { pm: true, 组长: false, 组员: false, worker: false },
|
|
33
|
+
};
|
|
34
|
+
// ============ 校验函数 ============
|
|
35
|
+
/**
|
|
36
|
+
* 校验角色是否有权调用指定工具
|
|
37
|
+
*
|
|
38
|
+
* ⚠️ 诚实的局限性说明(architecture §7.1):
|
|
39
|
+
* - 角色来源:AI 在 Workflow 触发时自行解析用户输入并写入 Artifacts
|
|
40
|
+
* - 信任模型:MCP Server 信任 AI 传入的 role 参数,无法独立验证 AI 角色
|
|
41
|
+
* - 防护强度:可防止"无意越权",无法防止"故意越权"
|
|
42
|
+
*
|
|
43
|
+
* @param role - 调用者角色(未提供时拒绝受限操作)
|
|
44
|
+
* @param toolName - 受限工具名称
|
|
45
|
+
* @returns null 表示通过,string 表示拒绝理由
|
|
46
|
+
*/
|
|
47
|
+
function checkCapability(role, toolName) {
|
|
48
|
+
// 受限工具必须提供角色参数
|
|
49
|
+
if (!role) {
|
|
50
|
+
return (`调用 ${toolName} 需要提供 role 参数。` +
|
|
51
|
+
"请在 Workflow 触发时传入角色标识(pm / 组长 / 组员 / worker)。" +
|
|
52
|
+
"(Capability Gate, architecture §7.1)");
|
|
53
|
+
}
|
|
54
|
+
// 规范化角色名
|
|
55
|
+
const normalizedRole = normalizeRole(role);
|
|
56
|
+
if (!normalizedRole) {
|
|
57
|
+
return `未识别的角色: "${role}"。合法角色: pm, 组长, 组员, worker`;
|
|
58
|
+
}
|
|
59
|
+
// 查询权限矩阵
|
|
60
|
+
const toolPermissions = CAPABILITY_MATRIX[toolName];
|
|
61
|
+
if (!toolPermissions) {
|
|
62
|
+
// 非受限工具,不做限制
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (!toolPermissions[normalizedRole]) {
|
|
66
|
+
const allowedRoles = Object.entries(toolPermissions)
|
|
67
|
+
.filter(([, allowed]) => allowed)
|
|
68
|
+
.map(([r]) => r);
|
|
69
|
+
return (`角色"${normalizedRole}"无权调用 ${toolName}。` +
|
|
70
|
+
` 允许的角色: ${allowedRoles.join(", ")}。` +
|
|
71
|
+
"(Capability Gate, architecture §7.1)");
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 规范化角色名(支持多种写法)
|
|
77
|
+
*/
|
|
78
|
+
function normalizeRole(role) {
|
|
79
|
+
const lower = role.toLowerCase().trim();
|
|
80
|
+
// PM 角色
|
|
81
|
+
if (lower === "pm" || lower === "项目经理" || lower === "project_manager") {
|
|
82
|
+
return "pm";
|
|
83
|
+
}
|
|
84
|
+
// 组长
|
|
85
|
+
if (lower === "组长" || lower === "leader" || lower === "team_lead") {
|
|
86
|
+
return "组长";
|
|
87
|
+
}
|
|
88
|
+
// 组员(支持 "组员", "组员A", "组员1" 等变体)
|
|
89
|
+
if (lower.startsWith("组员") ||
|
|
90
|
+
lower === "member" ||
|
|
91
|
+
lower === "team_member" ||
|
|
92
|
+
/^组员\d+$/.test(lower)) {
|
|
93
|
+
return "组员";
|
|
94
|
+
}
|
|
95
|
+
// Worker / 独立执行者
|
|
96
|
+
if (lower === "worker" ||
|
|
97
|
+
lower === "独立执行者" ||
|
|
98
|
+
lower === "执行者" ||
|
|
99
|
+
lower === "executor") {
|
|
100
|
+
return "worker";
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* 校验 Git ref 名称是否合法(防注入)
|
|
106
|
+
* @param ref - 分支名或标签名
|
|
107
|
+
* @returns true 表示合法
|
|
108
|
+
*/
|
|
109
|
+
function isValidGitRef(ref) {
|
|
110
|
+
// 禁止空字符串
|
|
111
|
+
if (!ref || ref.trim() === "")
|
|
112
|
+
return false;
|
|
113
|
+
// 禁止包含 shell 特殊字符
|
|
114
|
+
if (/[;&|`$(){}[\]!'"\\<>]/.test(ref))
|
|
115
|
+
return false;
|
|
116
|
+
// 禁止路径遍历
|
|
117
|
+
if (ref.includes(".."))
|
|
118
|
+
return false;
|
|
119
|
+
// 禁止以 - 开头(防止被解析为命令行参数)
|
|
120
|
+
if (ref.startsWith("-"))
|
|
121
|
+
return false;
|
|
122
|
+
// 禁止空格和控制字符
|
|
123
|
+
if (/[\s\x00-\x1f\x7f]/.test(ref))
|
|
124
|
+
return false;
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* 生成 Capability Gate 拒绝的标准 MCP 错误响应
|
|
129
|
+
*/
|
|
130
|
+
function capabilityError(rejectReason) {
|
|
131
|
+
return {
|
|
132
|
+
content: [
|
|
133
|
+
{
|
|
134
|
+
type: "text",
|
|
135
|
+
text: JSON.stringify({
|
|
136
|
+
error: true,
|
|
137
|
+
gate: "capability",
|
|
138
|
+
message: rejectReason,
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
isError: true,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export { CAPABILITY_MATRIX, checkCapability, normalizeRole, isValidGitRef, capabilityError, };
|
|
146
|
+
//# sourceMappingURL=capability-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability-gate.js","sourceRoot":"","sources":["../../src/utils/capability-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git commit 信息接口
|
|
3
|
+
*/
|
|
4
|
+
interface GitCommit {
|
|
5
|
+
hash: string;
|
|
6
|
+
message: string;
|
|
7
|
+
date: string;
|
|
8
|
+
author: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 获取当前 Git 分支名
|
|
12
|
+
* @returns 当前分支名,失败返回 'HEAD'
|
|
13
|
+
*/
|
|
14
|
+
declare function getGitBranch(): string;
|
|
15
|
+
/**
|
|
16
|
+
* 获取 Git 状态(简短格式)
|
|
17
|
+
* @returns `git status --short` 输出,失败返回空字符串
|
|
18
|
+
*/
|
|
19
|
+
declare function getGitStatus(): string;
|
|
20
|
+
/**
|
|
21
|
+
* 获取最近 N 条 commit 记录
|
|
22
|
+
* @param count - 获取的 commit 数量,默认为 10
|
|
23
|
+
* @returns commit 信息列表
|
|
24
|
+
*/
|
|
25
|
+
declare function getRecentCommits(count?: number): GitCommit[];
|
|
26
|
+
/**
|
|
27
|
+
* 检查当前目录是否在 Git 仓库中
|
|
28
|
+
* @returns 是否在 Git 仓库中
|
|
29
|
+
*/
|
|
30
|
+
declare function isGitRepo(): boolean;
|
|
31
|
+
export type { GitCommit };
|
|
32
|
+
export { getGitBranch, getGitStatus, getRecentCommits, isGitRepo, };
|
|
33
|
+
//# sourceMappingURL=git-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-utils.d.ts","sourceRoot":"","sources":["../../src/utils/git-utils.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAID;;;GAGG;AACH,iBAAS,YAAY,IAAI,MAAM,CAU9B;AAED;;;GAGG;AACH,iBAAS,YAAY,IAAI,MAAM,CAU9B;AAED;;;;GAIG;AACH,iBAAS,gBAAgB,CAAC,KAAK,GAAE,MAAW,GAAG,SAAS,EAAE,CA4BzD;AAED;;;GAGG;AACH,iBAAS,SAAS,IAAI,OAAO,CAU5B;AAID,YAAY,EAAE,SAAS,EAAE,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,SAAS,GACV,CAAC"}
|