pi-onedev-toolkit 0.2.0 → 0.2.2
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 +18 -0
- package/README.md +8 -0
- package/package.json +5 -4
- package/skills/onedev-issue-to-pr/SKILL.md +16 -50
- package/skills/onedev-pr-review/SKILL.md +19 -62
- package/src/mutation-approvals.ts +32 -9
- package/src/tools/build.ts +30 -31
- package/src/tools/common.ts +26 -5
- package/src/tools/index.ts +2 -5
- package/src/tools/issue.ts +20 -30
- package/src/tools/pull.ts +30 -59
- package/src/tools/watch.ts +3 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.2.2 — 2026-09-04
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Compressed model-visible tool schemas and bundled workflow prompts without changing tool names, actions, validations, or approval gates; tests now enforce schema and skill byte budgets.
|
|
10
|
+
- Model-visible output now defaults to 16 KB for normal results and 32 KB for PR patches, build logs, and build-spec schemas. `max_bytes` can request up to 128 KB; internal watch polling remains independent.
|
|
11
|
+
|
|
12
|
+
## 0.2.1 — 2026-09-03
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- "Always allow" now saves one project-wide approval (`[server, project, "*"]`) instead of a single operation, so new operations no longer re-prompt after approving. Legacy per-operation entries are still honored.
|
|
17
|
+
- "Allow for this session" also covers every operation in the project for the session.
|
|
18
|
+
- Concurrent identical mutations share one approval dialog instead of opening several.
|
|
19
|
+
- Safer dialog default (session-wide allow) and explicit "ALL OneDev mutations" labels; Enter no longer silently picks "Allow once".
|
|
20
|
+
|
|
3
21
|
## 0.2.0 — 2026-08-26
|
|
4
22
|
|
|
5
23
|
### Security and correctness
|
package/README.md
CHANGED
|
@@ -37,6 +37,8 @@ When the current directory is a OneDev repository, the status line shows the act
|
|
|
37
37
|
|
|
38
38
|
Lazy by design: domain tools activate only through `onedev_tools`, keeping the default tool list and system prompt light. Activation performs the first authenticated check and returns the server, project, and login context in the same response.
|
|
39
39
|
|
|
40
|
+
Model-visible issue, PR, and build output defaults to 16 KB. PR patches, build logs, and build-spec schemas default to 32 KB. Use `max_bytes` to raise or lower a call's budget up to 128 KB; truncation keeps the payload head/tail and is reported explicitly. Internal watch polling remains separately bounded and is never copied into the model context.
|
|
41
|
+
|
|
40
42
|
Remote and local mutations use Pi's real interactive approval UI. An approval can apply once, for the session, or persist for the exact server/project/operation in `~/.pi/agent/onedev-toolkit.json`; remove that file to revoke all saved approvals. Non-interactive sessions reject unapproved mutations. `build run` in local mode uses an isolated temporary Git index so TOD cannot leave the user's index staged; `check_spec` is treated as a mutation because TOD may upgrade `.onedev-buildspec.yml`.
|
|
41
43
|
|
|
42
44
|
Watches are session-scoped and one-shot. They use one timer, bounded polling, expiration and backoff, and wake the agent with metadata only. The agent retrieves logs, comments, or build details with the corresponding read tool. At most ten watches may be active; session changes and shutdown clear them.
|
|
@@ -60,6 +62,12 @@ Attachment download is intentionally not exposed: current TOD releases may send
|
|
|
60
62
|
- `onedev-issue-to-pr` — gather issue context, branch, implement, present for review, then push and open the PR
|
|
61
63
|
- `onedev-pr-review` — full-context PR review with line-anchored findings; submits only on explicit request
|
|
62
64
|
|
|
65
|
+
If you use only tools and slash commands, omit both workflow entries from every prompt while keeping the extension and tools:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{ "source": "npm:pi-onedev-toolkit", "skills": [] }
|
|
69
|
+
```
|
|
70
|
+
|
|
63
71
|
## Development
|
|
64
72
|
|
|
65
73
|
```bash
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-onedev-toolkit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Lightweight OneDev integration for Pi via TOD: repo-aware issue, pull request, build, and watch tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": {
|
|
@@ -53,11 +53,12 @@
|
|
|
53
53
|
"typebox": "*"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@earendil-works/pi-ai": "0.
|
|
57
|
-
"@earendil-works/pi-
|
|
56
|
+
"@earendil-works/pi-ai": "0.85.0",
|
|
57
|
+
"@earendil-works/pi-server": "0.85.0",
|
|
58
|
+
"@earendil-works/pi-coding-agent": "0.85.0",
|
|
58
59
|
"@types/node": "^22.19.0",
|
|
59
60
|
"@types/proper-lockfile": "4.1.4",
|
|
60
|
-
"typebox": "1.3.
|
|
61
|
+
"typebox": "1.3.25",
|
|
61
62
|
"typescript": "^7.0.2",
|
|
62
63
|
"vitest": "^4.1.10"
|
|
63
64
|
},
|
|
@@ -1,60 +1,26 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: onedev-issue-to-pr
|
|
3
|
-
description: Implement a OneDev issue
|
|
3
|
+
description: "Implement a OneDev issue and open a linked PR only after user approval."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# OneDev
|
|
6
|
+
# OneDev Issue to Pull Request
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Rules
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- Activate `issue` and `pull` together with `onedev_tools`; note the returned login. On readiness failure, use `onedev_context setup` and stop.
|
|
11
|
+
- Plain refs use the current repository's OneDev project. Never guess a missing ref or project.
|
|
12
|
+
- Preserve unrelated local changes. If checkout is dirty, report and stop; never stash automatically.
|
|
13
|
+
- Do not push, comment, or open a PR before the workflow checkpoint and explicit user approval. Toolkit mutations still require Pi UI approval.
|
|
12
14
|
|
|
13
15
|
## Workflow
|
|
14
16
|
|
|
15
|
-
1.
|
|
16
|
-
|
|
17
|
+
1. Resolve the prompt ref or use `onedev_issue current_reference`; stop if neither works.
|
|
18
|
+
2. Prepare the branch with `onedev_issue checkout` using `for_write: true`.
|
|
19
|
+
3. Read `onedev_issue get` and `get_comments`; use author/login context and derive acceptance criteria from the full discussion.
|
|
20
|
+
4. When failure evidence matters, activate `build`; inspect build metadata and start `get_log` with `max_bytes=32000`, raising it only if truncation hides required evidence. Follow same-commit dependency failures as the likely root cause; different-commit failures are inherited.
|
|
21
|
+
5. Implement the smallest complete change and run the narrowest relevant test. Optionally run local OneDev CI with `onedev_build run mode=local`.
|
|
22
|
+
6. **Stop for review.** Show the change, checks, and any issue comment you intend to post. Do not submit anything.
|
|
23
|
+
7. After explicit approval, read `onedev_pull commit_message_requirement` and `title_description_requirement`; empty output means no extra requirement. Commit and push with local Git, then create the PR against the intended target branch. Link the issue in the description when the issue branch does not imply it. Post only the approved issue comment.
|
|
24
|
+
8. For long CI, activate `watch` and start `onedev_watch watch_build`; re-read the build after the metadata-only notification.
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
`onedev_issue` action `checkout` with `ref` and `for_write: true`.
|
|
20
|
-
It creates the server-side issue branch and sets up tracking.
|
|
21
|
-
If the working copy is dirty, report it and stop — do not stash on your own.
|
|
22
|
-
|
|
23
|
-
3. **Read the full issue context** — never work from the prompt alone:
|
|
24
|
-
- `onedev_issue` `get` (title, description, fields, submitter)
|
|
25
|
-
- `onedev_issue` `get_comments`
|
|
26
|
-
- Match your login name against submitter/comment authors to understand your role.
|
|
27
|
-
- If a failed build is part of the issue, gather evidence with `onedev_build`
|
|
28
|
-
after activating the `build` domain (`get`, `get_log`, and a named
|
|
29
|
-
`get_unit_test_report` when useful) before planning changes. Follow `Dependency build … failed`
|
|
30
|
-
chains: same-commit dependency failures are the real target; different-commit
|
|
31
|
-
ones mean the failure is inherited.
|
|
32
|
-
|
|
33
|
-
4. **Implement the work.** Code changes, or an explanatory issue comment if no code
|
|
34
|
-
is needed. Run the smallest relevant test. Optionally validate CI locally with
|
|
35
|
-
`onedev_build` `run` (`mode: "local"`) before committing.
|
|
36
|
-
|
|
37
|
-
5. **STOP — present for review.** Summarize the change and the comment you intend
|
|
38
|
-
to post. Do not push or post anything yet. This is the mandatory checkpoint.
|
|
39
|
-
|
|
40
|
-
6. **After explicit user approval, submit:**
|
|
41
|
-
- Compose the commit message against the server requirements:
|
|
42
|
-
`onedev_pull` `commit_message_requirement` (and `title_description_requirement`
|
|
43
|
-
before creating the PR). Empty output means no requirement.
|
|
44
|
-
- `git add -A && git commit && git push` on the issue branch.
|
|
45
|
-
- Create the PR: `onedev_pull` `create` with `title`, `description`, and
|
|
46
|
-
`target_branch` (source branch defaults to the current branch). The issue link
|
|
47
|
-
is inferred from the branch; state it in the description if not.
|
|
48
|
-
- Post the drafted comment with `onedev_issue` `add_comment` if one was prepared.
|
|
49
|
-
|
|
50
|
-
7. **For long-running CI**, activate `watch` and use `onedev_watch` `watch_build`
|
|
51
|
-
after obtaining a build reference. The notification is one-shot and metadata-only;
|
|
52
|
-
inspect the build with `onedev_build` when it fires.
|
|
53
|
-
|
|
54
|
-
## Notes
|
|
55
|
-
|
|
56
|
-
- Write comment text in Markdown.
|
|
57
|
-
- Reference entities as `#123` (current project), `project#123`, or `PROJ-123`.
|
|
58
|
-
- If blocked mid-workflow, report the command and error, and stop.
|
|
59
|
-
- Toolkit mutations still open Pi's interactive approval UI. Do not try to bypass
|
|
60
|
-
it with a confirmation parameter.
|
|
26
|
+
Use Markdown for comments and `#123`, `project#123`, or `PROJ-123` for entities. On failure, report the command/error and stop; never invent a confirmation parameter.
|
|
@@ -1,71 +1,28 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: onedev-pr-review
|
|
3
|
-
description: Review a OneDev
|
|
3
|
+
description: "Review a OneDev PR; publish findings or merge only when asked."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# OneDev
|
|
6
|
+
# OneDev Pull Request Review
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Rules
|
|
9
9
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
10
|
+
- Activate `pull`, `issue`, and `build` together with `onedev_tools`; note the returned login. On readiness failure, use `onedev_context setup` and stop.
|
|
11
|
+
- Resolve the exact PR in its source/target repository. Never review from a patch alone.
|
|
12
|
+
- Analysis is read-only. Draft first; publish findings, change review state, or merge only after explicit user request and Pi UI approval.
|
|
13
|
+
- Never alter another user's code comments.
|
|
12
14
|
|
|
13
|
-
##
|
|
15
|
+
## Workflow
|
|
14
16
|
|
|
15
|
-
1.
|
|
17
|
+
1. Resolve the prompt ref or use `onedev_pull current_reference`.
|
|
18
|
+
2. Checkout for inspection; use `for_write: true` only when changing code. Dirty checkout means report and stop.
|
|
19
|
+
3. Read PR metadata, comments, code comments, and builds. Query fixed issues with `fixed in pull request "<ref>"`, then read their bodies/comments as the primary specification. Match authors against the returned login.
|
|
20
|
+
4. Investigate every failed build. Start `onedev_build get_log` with `max_bytes=32000`; raise it only if truncation hides required evidence. Follow same-commit dependency failures before blaming the current job.
|
|
21
|
+
5. Read `onedev_pull get_patch` with `for_code_review: true` and `max_bytes=32000`; inspect checkout files and callers when context is missing.
|
|
22
|
+
6. Keep only concrete correctness, regression, security, data-loss, error-handling, or coverage findings. Triage prior discussion: reply where needed, resolve only addressed comments you own, and leave unrelated comments alone.
|
|
23
|
+
7. Draft line findings with file/right-side lines, outside-patch findings as one overall comment, and `approve` or `request_changes` only when acting as a pending reviewer.
|
|
24
|
+
8. **Stop and present** findings, replies, outcome, and merge plan. Submit nothing.
|
|
25
|
+
9. On explicit request, publish the approved draft. For merge, satisfy `commit_message_requirement`; squash messages should reflect PR and fixed issues. Ask before rewriting commits for rebase-based conflict resolution.
|
|
26
|
+
10. When waiting, activate `watch` and use `watch_pull_attention`; re-read PR state after its metadata-only notification.
|
|
16
27
|
|
|
17
|
-
|
|
18
|
-
will change code). Dirty working copy → report and stop.
|
|
19
|
-
|
|
20
|
-
3. **Read everything:**
|
|
21
|
-
- `onedev_pull` `get` — title, description, source/target, merge strategy, status,
|
|
22
|
-
submitter, reviewers, review state.
|
|
23
|
-
- `onedev_pull` `get_comments` and `get_code_comments` — note code-comment `id`s,
|
|
24
|
-
file, line range, resolution state, replies.
|
|
25
|
-
- Fixed issues: `onedev_issue` `list` with query `fixed in pull request "<ref>"`,
|
|
26
|
-
then `get` / `get_comments` on each. Treat fixed issues as the primary spec
|
|
27
|
-
for what the PR should accomplish.
|
|
28
|
-
- `onedev_pull` `get_builds` — investigate every `FAILED` build with
|
|
29
|
-
`onedev_build` `get` / `get_log` before reviewing code.
|
|
30
|
-
- Match your login name against authors to understand your role
|
|
31
|
-
(pending reviewer, prior commenter, outsider).
|
|
32
|
-
|
|
33
|
-
## Review
|
|
34
|
-
|
|
35
|
-
1. Read the review-scoped patch: `onedev_pull` `get_patch` with
|
|
36
|
-
`for_code_review: true`. Read files in the checkout when the patch lacks context.
|
|
37
|
-
Check correctness, edge cases, security, style, and test coverage.
|
|
38
|
-
|
|
39
|
-
2. **Triage prior discussion:** resolve addressed code comments, reply where new
|
|
40
|
-
information is needed, leave unrelated unresolved ones alone. Never modify
|
|
41
|
-
another user's code comments. Use `reply_code_comment`, `resolve_code_comment`,
|
|
42
|
-
or `unresolve_code_comment` with the comment `id`.
|
|
43
|
-
|
|
44
|
-
3. **Draft findings:**
|
|
45
|
-
- Line-anchored findings → `onedev_pull` `add_code_comment` (`file`, `from_line`,
|
|
46
|
-
optional `to_line` — must be an added or context line visible in the patch).
|
|
47
|
-
- Outside-patch findings → one overall PR comment with file paths and lines.
|
|
48
|
-
- Review outcome if you are a pending reviewer: `approve` or `request_changes`
|
|
49
|
-
with a `summary`.
|
|
50
|
-
|
|
51
|
-
4. **STOP — present the draft** (findings, replies, outcomes, merge plan).
|
|
52
|
-
Submit nothing yet.
|
|
53
|
-
|
|
54
|
-
5. **On explicit request only:**
|
|
55
|
-
- Post findings/comments/review outcome.
|
|
56
|
-
- Merge: the toolkit asks for real interactive approval. For squash merges,
|
|
57
|
-
compose the commit message from PR title/description + fixed issues,
|
|
58
|
-
satisfying `commit_message_requirement` for the target project/branch.
|
|
59
|
-
- Resolving merge conflicts: fetch the target branch, merge with the PR's
|
|
60
|
-
strategy without committing, resolve, verify clean `git status`, commit.
|
|
61
|
-
For rebase-based strategies, ask for direction before rewriting commits.
|
|
62
|
-
|
|
63
|
-
6. **When waiting on updates**, activate `watch` and use `onedev_watch`
|
|
64
|
-
`watch_pull_attention`. It wakes once for a head/state/review/comment/build
|
|
65
|
-
signal change and includes no comment bodies; re-read the PR after it fires.
|
|
66
|
-
|
|
67
|
-
## Notes
|
|
68
|
-
|
|
69
|
-
- Comment text is Markdown; entity refs are `#123`, `project#123`, or `PROJ-123`.
|
|
70
|
-
- Toolkit mutations still open Pi's interactive approval UI. Do not add or invent
|
|
71
|
-
a confirmation parameter.
|
|
28
|
+
Use Markdown and `#123`, `project#123`, or `PROJ-123` refs. Never invent a confirmation parameter.
|
|
@@ -10,10 +10,12 @@ import {
|
|
|
10
10
|
} from "./config-storage.js";
|
|
11
11
|
|
|
12
12
|
const ALLOW_ONCE = "Allow once";
|
|
13
|
-
const ALLOW_SESSION = "Allow
|
|
14
|
-
const ALLOW_SAVED = "Always allow
|
|
13
|
+
const ALLOW_SESSION = "Allow ALL OneDev mutations in this project this session";
|
|
14
|
+
const ALLOW_SAVED = "Always allow ALL OneDev mutations in this project";
|
|
15
15
|
const CANCEL = "Cancel";
|
|
16
16
|
|
|
17
|
+
const ALL_OPERATIONS = "*";
|
|
18
|
+
|
|
17
19
|
export const MUTATION_OPERATIONS = [
|
|
18
20
|
"issue.create",
|
|
19
21
|
"issue.edit",
|
|
@@ -50,13 +52,14 @@ export interface MutationApprovalRequest {
|
|
|
50
52
|
|
|
51
53
|
function scopeKey(
|
|
52
54
|
context: OneDevSessionContext,
|
|
53
|
-
operation: MutationOperation,
|
|
55
|
+
operation: MutationOperation | typeof ALL_OPERATIONS,
|
|
54
56
|
): string {
|
|
55
57
|
return JSON.stringify([context.serverUrl, context.project, operation]);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
export class MutationApprovalManager {
|
|
59
61
|
readonly #session = new Set<string>();
|
|
62
|
+
readonly #pending = new Map<string, Promise<void>>();
|
|
60
63
|
|
|
61
64
|
constructor(
|
|
62
65
|
readonly configPath = join(getAgentDir(), "onedev-toolkit.json"),
|
|
@@ -70,6 +73,24 @@ export class MutationApprovalManager {
|
|
|
70
73
|
context: OneDevSessionContext,
|
|
71
74
|
ctx: ExtensionContext,
|
|
72
75
|
request: MutationApprovalRequest,
|
|
76
|
+
): Promise<void> {
|
|
77
|
+
const key = `${context.serverUrl}\n${context.project}\n${request.operation}`;
|
|
78
|
+
// ponytail: coalesces identical in-flight confirms only; parallel
|
|
79
|
+
// different-operation dialogs still queue on Pi core's single selector
|
|
80
|
+
const inFlight = this.#pending.get(key);
|
|
81
|
+
if (inFlight) return inFlight;
|
|
82
|
+
|
|
83
|
+
const approval = this.#runConfirm(context, ctx, request).finally(() => {
|
|
84
|
+
this.#pending.delete(key);
|
|
85
|
+
});
|
|
86
|
+
this.#pending.set(key, approval);
|
|
87
|
+
return approval;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async #runConfirm(
|
|
91
|
+
context: OneDevSessionContext,
|
|
92
|
+
ctx: ExtensionContext,
|
|
93
|
+
request: MutationApprovalRequest,
|
|
73
94
|
): Promise<void> {
|
|
74
95
|
if (request.signal?.aborted) {
|
|
75
96
|
throw request.signal.reason instanceof Error
|
|
@@ -80,11 +101,13 @@ export class MutationApprovalManager {
|
|
|
80
101
|
throw new Error("OneDev mutation requires a ready server and project context");
|
|
81
102
|
}
|
|
82
103
|
|
|
83
|
-
const
|
|
84
|
-
|
|
104
|
+
const operationScope = scopeKey(context, request.operation);
|
|
105
|
+
const projectScope = scopeKey(context, ALL_OPERATIONS);
|
|
106
|
+
if (this.#session.has(projectScope)) return;
|
|
85
107
|
try {
|
|
86
108
|
const savedScopes = await readAllowedMutationScopes(this.configPath);
|
|
87
|
-
|
|
109
|
+
// legacy per-operation entries saved by older versions stay honored
|
|
110
|
+
if (savedScopes.includes(projectScope) || savedScopes.includes(operationScope)) return;
|
|
88
111
|
} catch (error) {
|
|
89
112
|
if (ctx.hasUI) {
|
|
90
113
|
ctx.ui.notify(
|
|
@@ -107,7 +130,7 @@ export class MutationApprovalManager {
|
|
|
107
130
|
].join("\n");
|
|
108
131
|
const choice = await ctx.ui.select(
|
|
109
132
|
prompt,
|
|
110
|
-
[
|
|
133
|
+
[ALLOW_SESSION, ALLOW_SAVED, ALLOW_ONCE, CANCEL],
|
|
111
134
|
{ signal: request.signal },
|
|
112
135
|
);
|
|
113
136
|
if (!choice || choice === CANCEL) {
|
|
@@ -115,10 +138,10 @@ export class MutationApprovalManager {
|
|
|
115
138
|
}
|
|
116
139
|
if (choice === ALLOW_ONCE) return;
|
|
117
140
|
|
|
118
|
-
this.#session.add(
|
|
141
|
+
this.#session.add(projectScope);
|
|
119
142
|
if (choice === ALLOW_SAVED) {
|
|
120
143
|
try {
|
|
121
|
-
await saveAllowedMutationScope(this.configPath,
|
|
144
|
+
await saveAllowedMutationScope(this.configPath, projectScope);
|
|
122
145
|
} catch (error) {
|
|
123
146
|
ctx.ui.notify(
|
|
124
147
|
`Approval applies to this session only; it could not be saved: ${error instanceof Error ? error.message : String(error)}`,
|
package/src/tools/build.ts
CHANGED
|
@@ -6,6 +6,9 @@ import { StringEnum } from "@earendil-works/pi-ai";
|
|
|
6
6
|
import { Type, type Static } from "typebox";
|
|
7
7
|
import {
|
|
8
8
|
confirmMutation,
|
|
9
|
+
DEFAULT_LARGE_MODEL_OUTPUT_BYTES,
|
|
10
|
+
modelOutputBytes,
|
|
11
|
+
modelOutputLimit,
|
|
9
12
|
pushRepeated,
|
|
10
13
|
QUERY_DESCRIPTION,
|
|
11
14
|
REF_DESCRIPTION,
|
|
@@ -59,6 +62,7 @@ export interface BuildParams {
|
|
|
59
62
|
query?: string;
|
|
60
63
|
count?: number;
|
|
61
64
|
offset?: number;
|
|
65
|
+
max_bytes?: number;
|
|
62
66
|
}
|
|
63
67
|
|
|
64
68
|
export function buildBuildArgs(params: BuildParams): string[] {
|
|
@@ -154,6 +158,7 @@ async function runLocalBuildWithIsolatedIndex(
|
|
|
154
158
|
deps: ToolDeps,
|
|
155
159
|
args: string[],
|
|
156
160
|
signal?: AbortSignal,
|
|
161
|
+
maxOutputBytes?: number,
|
|
157
162
|
): Promise<TodOutput> {
|
|
158
163
|
if (process.platform === "win32") {
|
|
159
164
|
throw new TodError(
|
|
@@ -183,7 +188,7 @@ async function runLocalBuildWithIsolatedIndex(
|
|
|
183
188
|
cwd: context.cwd,
|
|
184
189
|
signal,
|
|
185
190
|
timeoutMs: BUILD_RUN_TIMEOUT_MS,
|
|
186
|
-
maxOutputBytes: 24_000,
|
|
191
|
+
maxOutputBytes: modelOutputLimit(maxOutputBytes, 24_000),
|
|
187
192
|
environment: { GIT_INDEX_FILE: isolatedIndex },
|
|
188
193
|
});
|
|
189
194
|
} catch (error) {
|
|
@@ -201,51 +206,33 @@ async function runLocalBuildWithIsolatedIndex(
|
|
|
201
206
|
|
|
202
207
|
export function registerBuildTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
203
208
|
const parameters = Type.Object({
|
|
204
|
-
action: StringEnum(BUILD_ACTIONS,
|
|
205
|
-
description:
|
|
206
|
-
"list, get, get_log, get_code_problems, get_unit_test_report, get_changes_since_success, run, check_spec (may upgrade .onedev-buildspec.yml), get_spec_schema, query_description",
|
|
207
|
-
}),
|
|
209
|
+
action: StringEnum(BUILD_ACTIONS),
|
|
208
210
|
ref: Type.Optional(Type.String({ description: REF_DESCRIPTION })),
|
|
209
|
-
report_name: Type.Optional(
|
|
210
|
-
Type.String({ description: "Report name quoted in the build log" }),
|
|
211
|
-
),
|
|
211
|
+
report_name: Type.Optional(Type.String()),
|
|
212
212
|
severity: Type.Optional(StringEnum(SEVERITY_LEVELS)),
|
|
213
|
-
job: Type.Optional(
|
|
214
|
-
Type.String({ description: "Job name defined in .onedev-buildspec.yml" }),
|
|
215
|
-
),
|
|
213
|
+
job: Type.Optional(Type.String()),
|
|
216
214
|
mode: Type.Optional(
|
|
217
|
-
StringEnum(RUN_MODES, {
|
|
218
|
-
description:
|
|
219
|
-
"run: local (uncommitted changes), branch, or tag; default local",
|
|
220
|
-
}),
|
|
221
|
-
),
|
|
222
|
-
branch: Type.Optional(
|
|
223
|
-
Type.String({ description: "run with mode=branch: branch to run against" }),
|
|
224
|
-
),
|
|
225
|
-
tag: Type.Optional(
|
|
226
|
-
Type.String({ description: "run with mode=tag: tag to run against" }),
|
|
215
|
+
StringEnum(RUN_MODES, { description: "Default: local" }),
|
|
227
216
|
),
|
|
217
|
+
branch: Type.Optional(Type.String()),
|
|
218
|
+
tag: Type.Optional(Type.String()),
|
|
228
219
|
params: Type.Optional(
|
|
229
|
-
Type.Array(Type.String(), {
|
|
230
|
-
description: 'Job parameters as "key=value", repeatable (-p)',
|
|
231
|
-
}),
|
|
220
|
+
Type.Array(Type.String(), { description: '"key=value" parameters' }),
|
|
232
221
|
),
|
|
233
222
|
project: Type.Optional(
|
|
234
|
-
Type.String({
|
|
235
|
-
description: "Project path for list; defaults to the current project",
|
|
236
|
-
}),
|
|
223
|
+
Type.String({ description: "Default: current project" }),
|
|
237
224
|
),
|
|
238
225
|
query: Type.Optional(Type.String({ description: QUERY_DESCRIPTION })),
|
|
239
226
|
count: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
|
|
240
227
|
offset: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
228
|
+
max_bytes: modelOutputBytes(),
|
|
241
229
|
}, { additionalProperties: false });
|
|
242
230
|
type Params = Static<typeof parameters>;
|
|
243
231
|
|
|
244
232
|
pi.registerTool({
|
|
245
233
|
name: "onedev_build",
|
|
246
234
|
label: "OneDev Builds",
|
|
247
|
-
description:
|
|
248
|
-
"Inspect OneDev CI/CD: query builds, read logs and code-problem reports, diff changes since the last success, validate the build spec, and run jobs (including against uncommitted local changes).",
|
|
235
|
+
description: "Read OneDev builds, logs, reports, and changes; validate or run jobs.",
|
|
249
236
|
parameters,
|
|
250
237
|
async execute(_toolCallId, params: Params, signal, _onUpdate, ctx) {
|
|
251
238
|
const isRun = params.action === "run";
|
|
@@ -272,12 +259,24 @@ export function registerBuildTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
272
259
|
(params.mode === undefined && !params.branch && !params.tag));
|
|
273
260
|
let output: TodOutput;
|
|
274
261
|
if (isLocalRun) {
|
|
275
|
-
output = await runLocalBuildWithIsolatedIndex(
|
|
262
|
+
output = await runLocalBuildWithIsolatedIndex(
|
|
263
|
+
deps,
|
|
264
|
+
args,
|
|
265
|
+
signal,
|
|
266
|
+
params.max_bytes,
|
|
267
|
+
);
|
|
276
268
|
} else {
|
|
277
269
|
output = await runInContext(deps, args, {
|
|
278
270
|
signal,
|
|
279
271
|
timeoutMs: isRun ? BUILD_RUN_TIMEOUT_MS : undefined,
|
|
280
|
-
maxOutputBytes:
|
|
272
|
+
maxOutputBytes:
|
|
273
|
+
params.max_bytes ??
|
|
274
|
+
(isRun
|
|
275
|
+
? 24_000
|
|
276
|
+
: params.action === "get_log" ||
|
|
277
|
+
params.action === "get_spec_schema"
|
|
278
|
+
? DEFAULT_LARGE_MODEL_OUTPUT_BYTES
|
|
279
|
+
: undefined),
|
|
281
280
|
});
|
|
282
281
|
}
|
|
283
282
|
return toolResult(
|
package/src/tools/common.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { Type } from "typebox";
|
|
2
3
|
import type {
|
|
3
4
|
ContextRefreshOptions,
|
|
4
5
|
OneDevSessionContext,
|
|
@@ -24,12 +25,32 @@ export interface ToolDeps {
|
|
|
24
25
|
approvals: MutationApprovalManager;
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
export const DEFAULT_MODEL_OUTPUT_BYTES = 16_000;
|
|
29
|
+
export const DEFAULT_LARGE_MODEL_OUTPUT_BYTES = 32_000;
|
|
30
|
+
export const MAX_MODEL_OUTPUT_BYTES = 128_000;
|
|
31
|
+
|
|
27
32
|
export const REF_DESCRIPTION =
|
|
28
|
-
"
|
|
33
|
+
"Ref: 123, #123, project#123, or PROJ-123; plain numbers use the current project.";
|
|
29
34
|
export const FIELDS_DESCRIPTION =
|
|
30
|
-
'
|
|
35
|
+
'"key=value" assignments; use valid_fields to discover values.';
|
|
31
36
|
export const QUERY_DESCRIPTION =
|
|
32
|
-
"OneDev query
|
|
37
|
+
"OneDev query; use query_description for syntax.";
|
|
38
|
+
|
|
39
|
+
export function modelOutputBytes() {
|
|
40
|
+
return Type.Optional(
|
|
41
|
+
Type.Integer({ minimum: 1_000, maximum: MAX_MODEL_OUTPUT_BYTES }),
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function modelOutputLimit(
|
|
46
|
+
requested: number | undefined,
|
|
47
|
+
fallback = DEFAULT_MODEL_OUTPUT_BYTES,
|
|
48
|
+
): number {
|
|
49
|
+
return Math.min(
|
|
50
|
+
MAX_MODEL_OUTPUT_BYTES,
|
|
51
|
+
Math.max(1_000, requested ?? fallback),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
33
54
|
|
|
34
55
|
export function toolResult(
|
|
35
56
|
text: string,
|
|
@@ -65,7 +86,7 @@ export async function runInContext(
|
|
|
65
86
|
cwd: context.cwd,
|
|
66
87
|
signal: options.signal,
|
|
67
88
|
timeoutMs: options.timeoutMs,
|
|
68
|
-
maxOutputBytes: options.maxOutputBytes,
|
|
89
|
+
maxOutputBytes: modelOutputLimit(options.maxOutputBytes),
|
|
69
90
|
});
|
|
70
91
|
}
|
|
71
92
|
|
|
@@ -111,7 +132,7 @@ export function withFooter(
|
|
|
111
132
|
): string {
|
|
112
133
|
const parts = [body || "(no output)"];
|
|
113
134
|
if (truncated)
|
|
114
|
-
parts.push("(output truncated; narrow the query or
|
|
135
|
+
parts.push("(output truncated; narrow the query or raise max_bytes)");
|
|
115
136
|
parts.push(contextFooter(context));
|
|
116
137
|
return parts.filter(Boolean).join("\n\n");
|
|
117
138
|
}
|
package/src/tools/index.ts
CHANGED
|
@@ -43,8 +43,7 @@ function registerContextTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
43
43
|
pi.registerTool({
|
|
44
44
|
name: "onedev_context",
|
|
45
45
|
label: "OneDev Context",
|
|
46
|
-
description:
|
|
47
|
-
"Inspect OneDev readiness without loading domain tools. Use health for an authenticated re-check and setup for actionable configuration guidance.",
|
|
46
|
+
description: "Inspect OneDev readiness, health, login, or setup.",
|
|
48
47
|
parameters: Type.Object(
|
|
49
48
|
{
|
|
50
49
|
action: StringEnum(["current", "health", "login_name", "setup"]),
|
|
@@ -85,8 +84,7 @@ export function registerOnedevTools(
|
|
|
85
84
|
pi.registerTool({
|
|
86
85
|
name: "onedev_tools",
|
|
87
86
|
label: "OneDev Tools",
|
|
88
|
-
description:
|
|
89
|
-
"Activate only the OneDev domains needed for the current task. Returns authenticated server, project, and login context with the activation result.",
|
|
87
|
+
description: "Activate needed OneDev domains and return authenticated context.",
|
|
90
88
|
promptGuidelines: [
|
|
91
89
|
"Use onedev_tools before an unavailable OneDev domain operation.",
|
|
92
90
|
],
|
|
@@ -97,7 +95,6 @@ export function registerOnedevTools(
|
|
|
97
95
|
minItems: 1,
|
|
98
96
|
maxItems: 4,
|
|
99
97
|
uniqueItems: true,
|
|
100
|
-
description: "Activate issue, pull, build, and/or watch in one call",
|
|
101
98
|
}),
|
|
102
99
|
},
|
|
103
100
|
{ additionalProperties: false },
|
package/src/tools/issue.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Type, type Static } from "typebox";
|
|
|
4
4
|
import {
|
|
5
5
|
FIELDS_DESCRIPTION,
|
|
6
6
|
confirmMutation,
|
|
7
|
+
modelOutputBytes,
|
|
7
8
|
pushRepeated,
|
|
8
9
|
QUERY_DESCRIPTION,
|
|
9
10
|
REF_DESCRIPTION,
|
|
@@ -65,6 +66,7 @@ export interface IssueParams {
|
|
|
65
66
|
query?: string;
|
|
66
67
|
count?: number;
|
|
67
68
|
offset?: number;
|
|
69
|
+
max_bytes?: number;
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
export function buildIssueArgs(params: IssueParams): string[] {
|
|
@@ -161,66 +163,51 @@ export function buildIssueArgs(params: IssueParams): string[] {
|
|
|
161
163
|
|
|
162
164
|
export function registerIssueTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
163
165
|
const parameters = Type.Object({
|
|
164
|
-
action: StringEnum(ISSUE_ACTIONS,
|
|
165
|
-
description:
|
|
166
|
-
"list (query issues), get, get_comments, create, edit, change_state, add_comment, link, log_work, create_branch, checkout (branch locally), current_reference (issue for current branch), valid_fields, valid_links, query_description",
|
|
167
|
-
}),
|
|
166
|
+
action: StringEnum(ISSUE_ACTIONS),
|
|
168
167
|
ref: Type.Optional(Type.String({ description: REF_DESCRIPTION })),
|
|
169
168
|
title: Type.Optional(Type.String()),
|
|
170
|
-
description: Type.Optional(Type.String(
|
|
169
|
+
description: Type.Optional(Type.String()),
|
|
171
170
|
state: Type.Optional(
|
|
172
|
-
Type.String({
|
|
173
|
-
description:
|
|
174
|
-
"Target state, e.g. Open or Released; discover via valid_fields",
|
|
175
|
-
}),
|
|
176
|
-
),
|
|
177
|
-
comment: Type.Optional(
|
|
178
|
-
Type.String({ description: "Markdown note attached to the action" }),
|
|
171
|
+
Type.String({ description: "Use valid_fields to discover states" }),
|
|
179
172
|
),
|
|
180
|
-
|
|
173
|
+
comment: Type.Optional(Type.String()),
|
|
174
|
+
content: Type.Optional(Type.String()),
|
|
181
175
|
link_name: Type.Optional(
|
|
182
|
-
Type.String({ description: "
|
|
183
|
-
),
|
|
184
|
-
target_ref: Type.Optional(
|
|
185
|
-
Type.String({ description: "Target issue reference for the link action" }),
|
|
186
|
-
),
|
|
187
|
-
hours: Type.Optional(
|
|
188
|
-
Type.Integer({ minimum: 1, description: "Hours to log for log_work" }),
|
|
176
|
+
Type.String({ description: "Use valid_links to discover names" }),
|
|
189
177
|
),
|
|
178
|
+
target_ref: Type.Optional(Type.String()),
|
|
179
|
+
hours: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
190
180
|
fields: Type.Optional(
|
|
191
181
|
Type.Array(Type.String(), { description: FIELDS_DESCRIPTION }),
|
|
192
182
|
),
|
|
193
183
|
iterations: Type.Optional(Type.Array(Type.String())),
|
|
194
184
|
own_estimated_time: Type.Optional(
|
|
195
|
-
Type.Number({ minimum: 0, description: "
|
|
185
|
+
Type.Number({ minimum: 0, description: "Hours" }),
|
|
196
186
|
),
|
|
197
187
|
confidential: Type.Optional(Type.Boolean()),
|
|
198
188
|
for_write: Type.Optional(
|
|
199
|
-
Type.Boolean({ description: "checkout
|
|
189
|
+
Type.Boolean({ description: "Prepare checkout for push" }),
|
|
200
190
|
),
|
|
201
191
|
project: Type.Optional(
|
|
202
|
-
Type.String({
|
|
203
|
-
description:
|
|
204
|
-
"Project path for list/create; defaults to the current project",
|
|
205
|
-
}),
|
|
192
|
+
Type.String({ description: "Default: current project" }),
|
|
206
193
|
),
|
|
207
194
|
query: Type.Optional(Type.String({ description: QUERY_DESCRIPTION })),
|
|
208
195
|
count: Type.Optional(
|
|
209
196
|
Type.Integer({
|
|
210
197
|
minimum: 1,
|
|
211
198
|
maximum: 100,
|
|
212
|
-
description: "
|
|
199
|
+
description: "Default: 25",
|
|
213
200
|
}),
|
|
214
201
|
),
|
|
215
202
|
offset: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
203
|
+
max_bytes: modelOutputBytes(),
|
|
216
204
|
}, { additionalProperties: false });
|
|
217
205
|
type Params = Static<typeof parameters>;
|
|
218
206
|
|
|
219
207
|
pi.registerTool({
|
|
220
208
|
name: "onedev_issue",
|
|
221
209
|
label: "OneDev Issues",
|
|
222
|
-
description:
|
|
223
|
-
"Read and edit OneDev issues: query, inspect, comment, change fields/labels/state, log work, manage issue branches. Runs in the current repository's project; plain numbers resolve against it.",
|
|
210
|
+
description: "Read/manage OneDev issues, comments, fields, work, and branches.",
|
|
224
211
|
parameters,
|
|
225
212
|
async execute(_toolCallId, params: Params, signal, _onUpdate, ctx) {
|
|
226
213
|
const args = buildIssueArgs(params);
|
|
@@ -236,7 +223,10 @@ export function registerIssueTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
236
223
|
signal,
|
|
237
224
|
});
|
|
238
225
|
}
|
|
239
|
-
const output = await runInContext(deps, args, {
|
|
226
|
+
const output = await runInContext(deps, args, {
|
|
227
|
+
signal,
|
|
228
|
+
maxOutputBytes: params.max_bytes,
|
|
229
|
+
});
|
|
240
230
|
return toolResult(
|
|
241
231
|
withFooter(output.text, deps.context(), output.truncated),
|
|
242
232
|
{
|
package/src/tools/pull.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { StringEnum } from "@earendil-works/pi-ai";
|
|
|
3
3
|
import { Type, type Static } from "typebox";
|
|
4
4
|
import {
|
|
5
5
|
confirmMutation,
|
|
6
|
+
DEFAULT_LARGE_MODEL_OUTPUT_BYTES,
|
|
7
|
+
modelOutputBytes,
|
|
6
8
|
pushRepeated,
|
|
7
9
|
QUERY_DESCRIPTION,
|
|
8
10
|
REF_DESCRIPTION,
|
|
@@ -86,6 +88,7 @@ export interface PullParams {
|
|
|
86
88
|
query?: string;
|
|
87
89
|
count?: number;
|
|
88
90
|
offset?: number;
|
|
91
|
+
max_bytes?: number;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
export function buildPullArgs(params: PullParams): string[] {
|
|
@@ -232,92 +235,53 @@ export function buildPullArgs(params: PullParams): string[] {
|
|
|
232
235
|
|
|
233
236
|
export function registerPullTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
234
237
|
const parameters = Type.Object({
|
|
235
|
-
action: StringEnum(PULL_ACTIONS,
|
|
236
|
-
description:
|
|
237
|
-
"list, get, get_comments, get_code_comments, get_builds, get_patch, create, edit, add_comment, add_code_comment, reply_code_comment, resolve_code_comment, unresolve_code_comment, approve, request_changes, merge, discard, checkout, current_reference, valid_labels, query_description, title_description_requirement, commit_message_requirement",
|
|
238
|
-
}),
|
|
238
|
+
action: StringEnum(PULL_ACTIONS),
|
|
239
239
|
ref: Type.Optional(Type.String({ description: REF_DESCRIPTION })),
|
|
240
240
|
title: Type.Optional(Type.String()),
|
|
241
|
-
description: Type.Optional(Type.String(
|
|
242
|
-
content: Type.Optional(Type.String(
|
|
243
|
-
summary: Type.Optional(
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
),
|
|
248
|
-
comment: Type.Optional(
|
|
249
|
-
Type.String({ description: "Markdown note for discard" }),
|
|
250
|
-
),
|
|
251
|
-
commit_message: Type.Optional(
|
|
252
|
-
Type.String({
|
|
253
|
-
description: "Commit message for merge (required by squash merges)",
|
|
254
|
-
}),
|
|
255
|
-
),
|
|
256
|
-
file: Type.Optional(
|
|
257
|
-
Type.String({ description: "add_code_comment: file path in the PR patch" }),
|
|
258
|
-
),
|
|
241
|
+
description: Type.Optional(Type.String()),
|
|
242
|
+
content: Type.Optional(Type.String()),
|
|
243
|
+
summary: Type.Optional(Type.String()),
|
|
244
|
+
comment: Type.Optional(Type.String()),
|
|
245
|
+
commit_message: Type.Optional(Type.String()),
|
|
246
|
+
file: Type.Optional(Type.String()),
|
|
259
247
|
from_line: Type.Optional(
|
|
260
|
-
Type.Integer({
|
|
261
|
-
minimum: 1,
|
|
262
|
-
description: "add_code_comment: 1-based start line (right side of patch)",
|
|
263
|
-
}),
|
|
264
|
-
),
|
|
265
|
-
to_line: Type.Optional(
|
|
266
|
-
Type.Integer({
|
|
267
|
-
minimum: 1,
|
|
268
|
-
description: "add_code_comment: 1-based end line; defaults to from_line",
|
|
269
|
-
}),
|
|
270
|
-
),
|
|
271
|
-
comment_id: Type.Optional(
|
|
272
|
-
Type.Integer({
|
|
273
|
-
minimum: 1,
|
|
274
|
-
description:
|
|
275
|
-
"Code comment id for reply_code_comment, resolve_code_comment, or unresolve_code_comment",
|
|
276
|
-
}),
|
|
248
|
+
Type.Integer({ minimum: 1, description: "Right-side line" }),
|
|
277
249
|
),
|
|
250
|
+
to_line: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
251
|
+
comment_id: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
278
252
|
source_branch: Type.Optional(Type.String()),
|
|
279
253
|
target_branch: Type.Optional(Type.String()),
|
|
280
254
|
source_project: Type.Optional(Type.String()),
|
|
281
255
|
target_project: Type.Optional(Type.String()),
|
|
282
|
-
assignees: Type.Optional(
|
|
283
|
-
|
|
284
|
-
),
|
|
285
|
-
reviewers: Type.Optional(
|
|
286
|
-
Type.Array(Type.String(), { description: "User logins, repeatable" }),
|
|
287
|
-
),
|
|
288
|
-
remove_reviewers: Type.Optional(
|
|
289
|
-
Type.Array(Type.String(), { description: "edit: user logins to remove" }),
|
|
290
|
-
),
|
|
256
|
+
assignees: Type.Optional(Type.Array(Type.String())),
|
|
257
|
+
reviewers: Type.Optional(Type.Array(Type.String())),
|
|
258
|
+
remove_reviewers: Type.Optional(Type.Array(Type.String())),
|
|
291
259
|
labels: Type.Optional(
|
|
292
|
-
Type.Array(Type.String(), {
|
|
293
|
-
description: "Label names; discover via valid_labels",
|
|
294
|
-
}),
|
|
260
|
+
Type.Array(Type.String(), { description: "Use valid_labels" }),
|
|
295
261
|
),
|
|
296
262
|
merge_strategy: Type.Optional(Type.String()),
|
|
297
263
|
auto_merge: Type.Optional(Type.Boolean()),
|
|
298
264
|
auto_merge_commit_message: Type.Optional(Type.String()),
|
|
299
265
|
for_code_review: Type.Optional(
|
|
300
|
-
Type.Boolean({ description: "
|
|
266
|
+
Type.Boolean({ description: "Review-scoped patch" }),
|
|
301
267
|
),
|
|
302
268
|
for_write: Type.Optional(
|
|
303
|
-
Type.Boolean({ description: "checkout
|
|
269
|
+
Type.Boolean({ description: "Prepare checkout for push" }),
|
|
304
270
|
),
|
|
305
271
|
project: Type.Optional(
|
|
306
|
-
Type.String({
|
|
307
|
-
description: "Project path for list; defaults to the current project",
|
|
308
|
-
}),
|
|
272
|
+
Type.String({ description: "Default: current project" }),
|
|
309
273
|
),
|
|
310
274
|
query: Type.Optional(Type.String({ description: QUERY_DESCRIPTION })),
|
|
311
275
|
count: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
|
|
312
276
|
offset: Type.Optional(Type.Integer({ minimum: 0 })),
|
|
277
|
+
max_bytes: modelOutputBytes(),
|
|
313
278
|
}, { additionalProperties: false });
|
|
314
279
|
type Params = Static<typeof parameters>;
|
|
315
280
|
|
|
316
281
|
pi.registerTool({
|
|
317
282
|
name: "onedev_pull",
|
|
318
283
|
label: "OneDev Pull Requests",
|
|
319
|
-
description:
|
|
320
|
-
"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.",
|
|
284
|
+
description: "Read/manage OneDev PRs, patch, comments, reviews, and guarded merge.",
|
|
321
285
|
parameters,
|
|
322
286
|
async execute(_toolCallId, params: Params, signal, _onUpdate, ctx) {
|
|
323
287
|
const args = buildPullArgs(params);
|
|
@@ -334,7 +298,14 @@ export function registerPullTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
334
298
|
signal,
|
|
335
299
|
});
|
|
336
300
|
}
|
|
337
|
-
const output = await runInContext(deps, args, {
|
|
301
|
+
const output = await runInContext(deps, args, {
|
|
302
|
+
signal,
|
|
303
|
+
maxOutputBytes:
|
|
304
|
+
params.max_bytes ??
|
|
305
|
+
(params.action === "get_patch"
|
|
306
|
+
? DEFAULT_LARGE_MODEL_OUTPUT_BYTES
|
|
307
|
+
: undefined),
|
|
308
|
+
});
|
|
338
309
|
return toolResult(
|
|
339
310
|
withFooter(output.text, deps.context(), output.truncated),
|
|
340
311
|
{
|
package/src/tools/watch.ts
CHANGED
|
@@ -11,8 +11,7 @@ export function registerWatchTool(
|
|
|
11
11
|
pi.registerTool({
|
|
12
12
|
name: "onedev_watch",
|
|
13
13
|
label: "OneDev Watch",
|
|
14
|
-
description:
|
|
15
|
-
"Create session-scoped one-shot watches for a build result or pull-request attention, or list/stop active watches. Notifications contain bounded metadata; use read tools for details.",
|
|
14
|
+
description: "Start/list/stop one-shot build or PR-attention watches.",
|
|
16
15
|
parameters: Type.Object(
|
|
17
16
|
{
|
|
18
17
|
action: StringEnum([
|
|
@@ -21,12 +20,8 @@ export function registerWatchTool(
|
|
|
21
20
|
"list",
|
|
22
21
|
"stop",
|
|
23
22
|
]),
|
|
24
|
-
ref: Type.Optional(
|
|
25
|
-
|
|
26
|
-
),
|
|
27
|
-
watch_id: Type.Optional(
|
|
28
|
-
Type.String({ description: "Watch id required by stop" }),
|
|
29
|
-
),
|
|
23
|
+
ref: Type.Optional(Type.String()),
|
|
24
|
+
watch_id: Type.Optional(Type.String()),
|
|
30
25
|
interval_seconds: Type.Optional(
|
|
31
26
|
Type.Integer({ minimum: 15, maximum: 300, default: 30 }),
|
|
32
27
|
),
|