pi-onedev-toolkit 0.3.0 → 0.4.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 +8 -0
- package/README.md +1 -0
- package/package.json +5 -5
- package/src/tools/build.ts +1 -0
- package/src/tools/common.ts +99 -24
- package/src/tools/issue.ts +1 -0
- package/src/tools/pull.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 — 2026-09-05
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- `issue`, `pull`, and `build` `list` actions with an explicit `project` now work even when the current repository has no OneDev remote: the query runs against a temporary scratch remote that is created and removed for the call.
|
|
8
|
+
- Refreshed development dependencies (pi packages 0.85.1, typebox 1.3.27).
|
|
9
|
+
|
|
10
|
+
|
|
3
11
|
## 0.3.0 — 2026-09-05
|
|
4
12
|
|
|
5
13
|
### Changed
|
package/README.md
CHANGED
|
@@ -55,6 +55,7 @@ Attachment download is intentionally not exposed: current TOD releases may send
|
|
|
55
55
|
|
|
56
56
|
- Update TOD regularly from its upstream install script. `get_unit_test_report` reports an actionable upgrade error when the installed TOD predates that command.
|
|
57
57
|
- Plain references require the current repository to have a OneDev remote from which TOD can infer the project. The toolkit reports `no_project` rather than pretending a qualified reference can bypass TOD's resolver.
|
|
58
|
+
- `issue`, `pull`, and `build` `list` calls with an explicit `project` work from any repository: the toolkit binds TOD to a throwaway Git remote for the query and removes it afterwards.
|
|
58
59
|
- Tool calls use `snake_case`, for example `for_code_review`, `target_branch`, `report_name`, and `interval_seconds`.
|
|
59
60
|
|
|
60
61
|
## Skills
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-onedev-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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,12 +53,12 @@
|
|
|
53
53
|
"typebox": "*"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@earendil-works/pi-ai": "0.85.
|
|
57
|
-
"@earendil-works/pi-
|
|
58
|
-
"@earendil-works/pi-
|
|
56
|
+
"@earendil-works/pi-ai": "0.85.1",
|
|
57
|
+
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
58
|
+
"@earendil-works/pi-server": "0.85.1",
|
|
59
59
|
"@types/node": "^22.19.0",
|
|
60
60
|
"@types/proper-lockfile": "4.1.4",
|
|
61
|
-
"typebox": "1.3.
|
|
61
|
+
"typebox": "1.3.27",
|
|
62
62
|
"typescript": "^7.0.2",
|
|
63
63
|
"vitest": "^4.1.10"
|
|
64
64
|
},
|
package/src/tools/build.ts
CHANGED
|
@@ -275,6 +275,7 @@ export function registerBuildTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
275
275
|
if (params.action === "list") {
|
|
276
276
|
output = await runListInContext(deps, args, {
|
|
277
277
|
signal,
|
|
278
|
+
project: params.project,
|
|
278
279
|
full: params.full,
|
|
279
280
|
maxOutputBytes: params.max_bytes,
|
|
280
281
|
digest: digestBuilds,
|
package/src/tools/common.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
1
4
|
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
5
|
import { Type } from "typebox";
|
|
3
6
|
import type {
|
|
@@ -285,40 +288,57 @@ export function digestProjects(text: string): string | undefined {
|
|
|
285
288
|
}
|
|
286
289
|
|
|
287
290
|
/**
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
291
|
+
* Run tod inside a throwaway Git repository whose only remote points at the
|
|
292
|
+
* requested OneDev project. TOD refuses `--project` queries when the working
|
|
293
|
+
* directory has no OneDev remote; the scratch repository supplies one
|
|
294
|
+
* without touching the user's checkout.
|
|
292
295
|
*/
|
|
293
|
-
|
|
294
|
-
|
|
296
|
+
async function runTodWithScratchRemote(
|
|
297
|
+
exec: CommandExecutor,
|
|
295
298
|
args: readonly string[],
|
|
299
|
+
serverUrl: string,
|
|
300
|
+
project: string,
|
|
301
|
+
options: { signal?: AbortSignal; maxOutputBytes: number },
|
|
302
|
+
): Promise<TodOutput> {
|
|
303
|
+
const directory = await mkdtemp(join(tmpdir(), "pi-onedev-scratch-"));
|
|
304
|
+
try {
|
|
305
|
+
for (const gitArgs of [
|
|
306
|
+
["init", "--quiet", directory],
|
|
307
|
+
[
|
|
308
|
+
"remote",
|
|
309
|
+
"add",
|
|
310
|
+
"origin",
|
|
311
|
+
`${serverUrl.replace(/\/$/, "")}/${project}.git`,
|
|
312
|
+
],
|
|
313
|
+
]) {
|
|
314
|
+
const done = await exec("git", gitArgs, { cwd: directory });
|
|
315
|
+
if (done.code !== 0 || done.killed) {
|
|
316
|
+
throw new TodError(
|
|
317
|
+
`could not prepare a temporary OneDev project context: ${(done.stderr || done.stdout).trim() || `git ${gitArgs[0] ?? ""} failed`}`,
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return await runTod(exec, [...args, "--working-dir", directory], {
|
|
322
|
+
signal: options.signal,
|
|
323
|
+
maxOutputBytes: options.maxOutputBytes,
|
|
324
|
+
});
|
|
325
|
+
} finally {
|
|
326
|
+
await rm(directory, { recursive: true, force: true });
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function finishListOutput(
|
|
331
|
+
fetch: (maxOutputBytes: number) => Promise<TodOutput>,
|
|
296
332
|
options: {
|
|
297
|
-
signal?: AbortSignal;
|
|
298
333
|
full?: boolean;
|
|
299
334
|
maxOutputBytes?: number;
|
|
300
335
|
digest: (text: string) => string | undefined;
|
|
301
336
|
},
|
|
302
337
|
): Promise<TodOutput> {
|
|
303
|
-
const context = deps.context();
|
|
304
|
-
if (context.status !== "ready" || !context.project) {
|
|
305
|
-
throw new TodError(
|
|
306
|
-
context.problem ??
|
|
307
|
-
"OneDev tools require a repository whose project can be inferred from a OneDev remote",
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
338
|
if (options.full === true) {
|
|
311
|
-
return
|
|
312
|
-
cwd: context.cwd,
|
|
313
|
-
signal: options.signal,
|
|
314
|
-
maxOutputBytes: modelOutputLimit(options.maxOutputBytes),
|
|
315
|
-
});
|
|
339
|
+
return fetch(modelOutputLimit(options.maxOutputBytes));
|
|
316
340
|
}
|
|
317
|
-
const output = await
|
|
318
|
-
cwd: context.cwd,
|
|
319
|
-
signal: options.signal,
|
|
320
|
-
maxOutputBytes: DIGEST_FETCH_BYTES,
|
|
321
|
-
});
|
|
341
|
+
const output = await fetch(DIGEST_FETCH_BYTES);
|
|
322
342
|
const limit = modelOutputLimit(options.maxOutputBytes);
|
|
323
343
|
const digested = options.digest(output.text);
|
|
324
344
|
if (
|
|
@@ -341,6 +361,61 @@ export async function runListInContext(
|
|
|
341
361
|
};
|
|
342
362
|
}
|
|
343
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Fetch a whole bounded list payload, then reduce it to a digest unless the
|
|
366
|
+
* caller opted into raw output. The internal fetch budget exceeds the
|
|
367
|
+
* model-visible cap on purpose: the digest, not the payload, reaches the
|
|
368
|
+
* model. Without an inferred project, an explicit `project` list query runs
|
|
369
|
+
* against a temporary scratch remote instead of failing.
|
|
370
|
+
*/
|
|
371
|
+
export async function runListInContext(
|
|
372
|
+
deps: ToolDeps,
|
|
373
|
+
args: readonly string[],
|
|
374
|
+
options: {
|
|
375
|
+
signal?: AbortSignal;
|
|
376
|
+
full?: boolean;
|
|
377
|
+
maxOutputBytes?: number;
|
|
378
|
+
project?: string;
|
|
379
|
+
digest: (text: string) => string | undefined;
|
|
380
|
+
},
|
|
381
|
+
): Promise<TodOutput> {
|
|
382
|
+
const context = deps.context();
|
|
383
|
+
if (context.status !== "ready" || !context.project) {
|
|
384
|
+
const scratchServer = context.serverUrl;
|
|
385
|
+
const scratchProject = options.project;
|
|
386
|
+
if (
|
|
387
|
+
context.status !== "no_project" ||
|
|
388
|
+
scratchServer === undefined ||
|
|
389
|
+
scratchProject === undefined
|
|
390
|
+
) {
|
|
391
|
+
throw new TodError(
|
|
392
|
+
context.problem ??
|
|
393
|
+
"OneDev tools require a repository whose project can be inferred from a OneDev remote",
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
return finishListOutput(
|
|
397
|
+
(maxOutputBytes) =>
|
|
398
|
+
runTodWithScratchRemote(
|
|
399
|
+
deps.exec,
|
|
400
|
+
args,
|
|
401
|
+
scratchServer,
|
|
402
|
+
scratchProject,
|
|
403
|
+
{ signal: options.signal, maxOutputBytes },
|
|
404
|
+
),
|
|
405
|
+
options,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
return finishListOutput(
|
|
409
|
+
(maxOutputBytes) =>
|
|
410
|
+
runTod(deps.exec, args, {
|
|
411
|
+
cwd: context.cwd,
|
|
412
|
+
signal: options.signal,
|
|
413
|
+
maxOutputBytes,
|
|
414
|
+
}),
|
|
415
|
+
options,
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
|
|
344
419
|
export function confirmMutation(
|
|
345
420
|
deps: ToolDeps,
|
|
346
421
|
ctx: ExtensionContext,
|
package/src/tools/issue.ts
CHANGED
|
@@ -233,6 +233,7 @@ export function registerIssueTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
233
233
|
params.action === "list"
|
|
234
234
|
? await runListInContext(deps, args, {
|
|
235
235
|
signal,
|
|
236
|
+
project: params.project,
|
|
236
237
|
full: params.full,
|
|
237
238
|
maxOutputBytes: params.max_bytes,
|
|
238
239
|
digest: digestIssues,
|
package/src/tools/pull.ts
CHANGED
|
@@ -308,6 +308,7 @@ export function registerPullTool(pi: ExtensionAPI, deps: ToolDeps): void {
|
|
|
308
308
|
params.action === "list"
|
|
309
309
|
? await runListInContext(deps, args, {
|
|
310
310
|
signal,
|
|
311
|
+
project: params.project,
|
|
311
312
|
full: params.full,
|
|
312
313
|
maxOutputBytes: params.max_bytes,
|
|
313
314
|
digest: digestPulls,
|