pi-onedev-toolkit 0.1.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/CHANGELOG.md +9 -0
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/extensions/onedev/index.ts +1 -0
- package/package.json +67 -0
- package/skills/onedev-issue-to-pr/SKILL.md +55 -0
- package/skills/onedev-pr-review/SKILL.md +65 -0
- package/src/context.ts +97 -0
- package/src/extension.ts +72 -0
- package/src/tod.ts +103 -0
- package/src/tools/build.ts +170 -0
- package/src/tools/common.ts +102 -0
- package/src/tools/index.ts +126 -0
- package/src/tools/issue.ts +225 -0
- package/src/tools/pull.ts +298 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
3
|
+
import { Type, type Static } from "typebox";
|
|
4
|
+
import {
|
|
5
|
+
confirmGate,
|
|
6
|
+
pushRepeated,
|
|
7
|
+
QUERY_DESCRIPTION,
|
|
8
|
+
REF_DESCRIPTION,
|
|
9
|
+
requireParam,
|
|
10
|
+
runInContext,
|
|
11
|
+
toolResult,
|
|
12
|
+
withFooter,
|
|
13
|
+
type ToolDeps,
|
|
14
|
+
} from "./common.js";
|
|
15
|
+
|
|
16
|
+
const PULL_ACTIONS = [
|
|
17
|
+
"list",
|
|
18
|
+
"get",
|
|
19
|
+
"get_comments",
|
|
20
|
+
"get_code_comments",
|
|
21
|
+
"get_builds",
|
|
22
|
+
"get_patch",
|
|
23
|
+
"create",
|
|
24
|
+
"edit",
|
|
25
|
+
"add_comment",
|
|
26
|
+
"add_code_comment",
|
|
27
|
+
"approve",
|
|
28
|
+
"request_changes",
|
|
29
|
+
"merge",
|
|
30
|
+
"discard",
|
|
31
|
+
"checkout",
|
|
32
|
+
"current_reference",
|
|
33
|
+
"valid_labels",
|
|
34
|
+
"query_description",
|
|
35
|
+
"title_description_requirement",
|
|
36
|
+
"commit_message_requirement",
|
|
37
|
+
] as const;
|
|
38
|
+
export type PullAction = (typeof PULL_ACTIONS)[number];
|
|
39
|
+
|
|
40
|
+
export interface PullParams {
|
|
41
|
+
action?: PullAction;
|
|
42
|
+
ref?: string;
|
|
43
|
+
title?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
content?: string;
|
|
46
|
+
summary?: string;
|
|
47
|
+
commitMessage?: string;
|
|
48
|
+
comment?: string;
|
|
49
|
+
file?: string;
|
|
50
|
+
fromLine?: number;
|
|
51
|
+
toLine?: number;
|
|
52
|
+
sourceBranch?: string;
|
|
53
|
+
targetBranch?: string;
|
|
54
|
+
sourceProject?: string;
|
|
55
|
+
targetProject?: string;
|
|
56
|
+
assignees?: string[];
|
|
57
|
+
reviewers?: string[];
|
|
58
|
+
removeReviewers?: string[];
|
|
59
|
+
labels?: string[];
|
|
60
|
+
mergeStrategy?: string;
|
|
61
|
+
autoMerge?: boolean;
|
|
62
|
+
autoMergeCommitMessage?: string;
|
|
63
|
+
forCodeReview?: boolean;
|
|
64
|
+
forWrite?: boolean;
|
|
65
|
+
project?: string;
|
|
66
|
+
query?: string;
|
|
67
|
+
count?: number;
|
|
68
|
+
offset?: number;
|
|
69
|
+
confirm?: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildPullArgs(params: PullParams): string[] {
|
|
73
|
+
const args: string[] = ["pr"];
|
|
74
|
+
const action = requireParam(params.action, "pr", "action");
|
|
75
|
+
const ref = (): string => requireParam(params.ref, action, "ref");
|
|
76
|
+
const branchScope = (): void => {
|
|
77
|
+
if (params.sourceBranch !== undefined)
|
|
78
|
+
args.push("--source-branch", params.sourceBranch);
|
|
79
|
+
if (params.targetBranch !== undefined)
|
|
80
|
+
args.push("--target-branch", params.targetBranch);
|
|
81
|
+
if (params.sourceProject !== undefined)
|
|
82
|
+
args.push("--source-project", params.sourceProject);
|
|
83
|
+
if (params.targetProject !== undefined)
|
|
84
|
+
args.push("--target-project", params.targetProject);
|
|
85
|
+
};
|
|
86
|
+
switch (action) {
|
|
87
|
+
case "list":
|
|
88
|
+
args.push("list");
|
|
89
|
+
if (params.project !== undefined) args.push("--project", params.project);
|
|
90
|
+
if (params.query !== undefined) args.push("--query", params.query);
|
|
91
|
+
if (params.offset !== undefined)
|
|
92
|
+
args.push("--offset", String(params.offset));
|
|
93
|
+
args.push("--count", String(params.count ?? 25));
|
|
94
|
+
return args;
|
|
95
|
+
case "get":
|
|
96
|
+
return [...args, "get", ref()];
|
|
97
|
+
case "get_comments":
|
|
98
|
+
return [...args, "get-comments", ref()];
|
|
99
|
+
case "get_code_comments":
|
|
100
|
+
return [...args, "get-code-comments", ref()];
|
|
101
|
+
case "get_builds":
|
|
102
|
+
return [...args, "get-builds", ref()];
|
|
103
|
+
case "get_patch":
|
|
104
|
+
args.push("get-patch", ref());
|
|
105
|
+
if (params.forCodeReview === true) args.push("--for-code-review");
|
|
106
|
+
return args;
|
|
107
|
+
case "create":
|
|
108
|
+
args.push("create", requireParam(params.title, action, "title"));
|
|
109
|
+
branchScope();
|
|
110
|
+
if (params.description !== undefined)
|
|
111
|
+
args.push("--description", params.description);
|
|
112
|
+
pushRepeated(args, "--assignee", params.assignees);
|
|
113
|
+
pushRepeated(args, "--reviewer", params.reviewers);
|
|
114
|
+
pushRepeated(args, "--label", params.labels);
|
|
115
|
+
if (params.mergeStrategy !== undefined)
|
|
116
|
+
args.push("--merge-strategy", params.mergeStrategy);
|
|
117
|
+
return args;
|
|
118
|
+
case "edit":
|
|
119
|
+
args.push("edit", ref());
|
|
120
|
+
if (params.title !== undefined) args.push("--title", params.title);
|
|
121
|
+
if (params.description !== undefined)
|
|
122
|
+
args.push("--description", params.description);
|
|
123
|
+
pushRepeated(args, "--assignee", params.assignees);
|
|
124
|
+
pushRepeated(args, "--add-reviewer", params.reviewers);
|
|
125
|
+
pushRepeated(args, "--remove-reviewer", params.removeReviewers);
|
|
126
|
+
pushRepeated(args, "--label", params.labels);
|
|
127
|
+
if (params.mergeStrategy !== undefined)
|
|
128
|
+
args.push("--merge-strategy", params.mergeStrategy);
|
|
129
|
+
if (params.autoMerge === true) {
|
|
130
|
+
args.push("--auto-merge");
|
|
131
|
+
if (params.autoMergeCommitMessage !== undefined)
|
|
132
|
+
args.push("--auto-merge-commit-message", params.autoMergeCommitMessage);
|
|
133
|
+
}
|
|
134
|
+
return args;
|
|
135
|
+
case "add_comment":
|
|
136
|
+
return [
|
|
137
|
+
...args,
|
|
138
|
+
"add-comment",
|
|
139
|
+
ref(),
|
|
140
|
+
requireParam(params.content, action, "content"),
|
|
141
|
+
];
|
|
142
|
+
case "add_code_comment":
|
|
143
|
+
args.push(
|
|
144
|
+
"add-code-comment",
|
|
145
|
+
ref(),
|
|
146
|
+
requireParam(params.content, action, "content"),
|
|
147
|
+
);
|
|
148
|
+
args.push("--file", requireParam(params.file, action, "file"));
|
|
149
|
+
args.push(
|
|
150
|
+
"--from-line",
|
|
151
|
+
String(requireParam(params.fromLine, action, "from_line")),
|
|
152
|
+
);
|
|
153
|
+
args.push("--to-line", String(params.toLine ?? params.fromLine));
|
|
154
|
+
return args;
|
|
155
|
+
case "approve":
|
|
156
|
+
args.push("approve", ref());
|
|
157
|
+
if (params.summary !== undefined) args.push("--summary", params.summary);
|
|
158
|
+
return args;
|
|
159
|
+
case "request_changes":
|
|
160
|
+
args.push("request-changes", ref());
|
|
161
|
+
if (params.summary !== undefined) args.push("--summary", params.summary);
|
|
162
|
+
return args;
|
|
163
|
+
case "merge":
|
|
164
|
+
confirmGate(action, params.confirm);
|
|
165
|
+
args.push("merge", ref());
|
|
166
|
+
if (params.commitMessage !== undefined)
|
|
167
|
+
args.push("--commit-message", params.commitMessage);
|
|
168
|
+
return args;
|
|
169
|
+
case "discard":
|
|
170
|
+
confirmGate(action, params.confirm);
|
|
171
|
+
args.push("discard", ref());
|
|
172
|
+
if (params.comment !== undefined) args.push("--comment", params.comment);
|
|
173
|
+
return args;
|
|
174
|
+
case "checkout":
|
|
175
|
+
args.push("checkout", ref());
|
|
176
|
+
if (params.forWrite === true) args.push("--for-write");
|
|
177
|
+
return args;
|
|
178
|
+
case "current_reference":
|
|
179
|
+
return [...args, "current-reference"];
|
|
180
|
+
case "valid_labels":
|
|
181
|
+
return ["get-valid-labels"];
|
|
182
|
+
case "query_description":
|
|
183
|
+
return [...args, "get-query-description"];
|
|
184
|
+
case "title_description_requirement":
|
|
185
|
+
args.push("get-title-and-description-requirement");
|
|
186
|
+
branchScope();
|
|
187
|
+
return args;
|
|
188
|
+
case "commit_message_requirement":
|
|
189
|
+
args.push("get-commit-message-requirement");
|
|
190
|
+
branchScope();
|
|
191
|
+
return args;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function registerPullTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
196
|
+
const parameters = Type.Object({
|
|
197
|
+
action: StringEnum(PULL_ACTIONS, {
|
|
198
|
+
description:
|
|
199
|
+
"list, get, get_comments, get_code_comments, get_builds, get_patch (diff; for_code_review scopes it), create, edit, add_comment, add_code_comment (line-anchored), approve, request_changes, merge (confirm), discard (confirm), checkout, current_reference, valid_labels, query_description, title_description_requirement, commit_message_requirement",
|
|
200
|
+
}),
|
|
201
|
+
ref: Type.Optional(Type.String({ description: REF_DESCRIPTION })),
|
|
202
|
+
title: Type.Optional(Type.String()),
|
|
203
|
+
description: Type.Optional(Type.String({ description: "Markdown body" })),
|
|
204
|
+
content: Type.Optional(Type.String({ description: "Markdown comment text" })),
|
|
205
|
+
summary: Type.Optional(
|
|
206
|
+
Type.String({
|
|
207
|
+
description: "Markdown review summary for approve/request_changes",
|
|
208
|
+
}),
|
|
209
|
+
),
|
|
210
|
+
comment: Type.Optional(
|
|
211
|
+
Type.String({ description: "Markdown note for discard" }),
|
|
212
|
+
),
|
|
213
|
+
commitMessage: Type.Optional(
|
|
214
|
+
Type.String({
|
|
215
|
+
description: "Commit message for merge (required by squash merges)",
|
|
216
|
+
}),
|
|
217
|
+
),
|
|
218
|
+
file: Type.Optional(
|
|
219
|
+
Type.String({ description: "add_code_comment: file path in the PR patch" }),
|
|
220
|
+
),
|
|
221
|
+
fromLine: Type.Optional(
|
|
222
|
+
Type.Integer({
|
|
223
|
+
minimum: 1,
|
|
224
|
+
description: "add_code_comment: 1-based start line (right side of patch)",
|
|
225
|
+
}),
|
|
226
|
+
),
|
|
227
|
+
toLine: Type.Optional(
|
|
228
|
+
Type.Integer({
|
|
229
|
+
minimum: 1,
|
|
230
|
+
description: "add_code_comment: 1-based end line; defaults to from_line",
|
|
231
|
+
}),
|
|
232
|
+
),
|
|
233
|
+
sourceBranch: Type.Optional(Type.String()),
|
|
234
|
+
targetBranch: Type.Optional(Type.String()),
|
|
235
|
+
sourceProject: Type.Optional(Type.String()),
|
|
236
|
+
targetProject: Type.Optional(Type.String()),
|
|
237
|
+
assignees: Type.Optional(
|
|
238
|
+
Type.Array(Type.String(), { description: "User logins, repeatable" }),
|
|
239
|
+
),
|
|
240
|
+
reviewers: Type.Optional(
|
|
241
|
+
Type.Array(Type.String(), { description: "User logins, repeatable" }),
|
|
242
|
+
),
|
|
243
|
+
removeReviewers: Type.Optional(
|
|
244
|
+
Type.Array(Type.String(), { description: "edit: user logins to remove" }),
|
|
245
|
+
),
|
|
246
|
+
labels: Type.Optional(
|
|
247
|
+
Type.Array(Type.String(), {
|
|
248
|
+
description: "Label names; discover via valid_labels",
|
|
249
|
+
}),
|
|
250
|
+
),
|
|
251
|
+
mergeStrategy: Type.Optional(Type.String()),
|
|
252
|
+
autoMerge: Type.Optional(Type.Boolean()),
|
|
253
|
+
autoMergeCommitMessage: Type.Optional(Type.String()),
|
|
254
|
+
forCodeReview: Type.Optional(
|
|
255
|
+
Type.Boolean({ description: "get_patch: review-scoped patch" }),
|
|
256
|
+
),
|
|
257
|
+
forWrite: Type.Optional(
|
|
258
|
+
Type.Boolean({ description: "checkout: set up the branch for pushing" }),
|
|
259
|
+
),
|
|
260
|
+
project: Type.Optional(
|
|
261
|
+
Type.String({
|
|
262
|
+
description: "Project path for list; defaults to the current project",
|
|
263
|
+
}),
|
|
264
|
+
),
|
|
265
|
+
query: Type.Optional(Type.String({ description: QUERY_DESCRIPTION })),
|
|
266
|
+
count: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
|
|
267
|
+
offset: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
268
|
+
confirm: Type.Optional(
|
|
269
|
+
Type.Boolean({
|
|
270
|
+
description:
|
|
271
|
+
"Required true for merge/discard: re-run with confirm after the user approves the destructive action",
|
|
272
|
+
}),
|
|
273
|
+
),
|
|
274
|
+
});
|
|
275
|
+
type Params = Static<typeof parameters>;
|
|
276
|
+
|
|
277
|
+
pi.registerTool({
|
|
278
|
+
name: "onedev_pull",
|
|
279
|
+
label: "OneDev Pull Requests",
|
|
280
|
+
description:
|
|
281
|
+
"Read and edit OneDev pull requests: metadata, labels, comments, line-anchored code comments, builds, patch, review outcomes, and guarded merge/discard. Runs in the current repository's project.",
|
|
282
|
+
promptGuidelines: [
|
|
283
|
+
"Use onedev_pull get_patch with for_code_review for review-scoped diffs.",
|
|
284
|
+
"merge and discard require confirm: true after explicit user approval.",
|
|
285
|
+
],
|
|
286
|
+
parameters,
|
|
287
|
+
async execute(_toolCallId, params: Params, signal) {
|
|
288
|
+
const output = await runInContext(deps, buildPullArgs(params), { signal });
|
|
289
|
+
return toolResult(
|
|
290
|
+
withFooter(output.text, deps.context(), output.truncated),
|
|
291
|
+
{
|
|
292
|
+
action: params.action,
|
|
293
|
+
truncated: output.truncated,
|
|
294
|
+
},
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
}
|