@blogic-cz/agent-tools 1.7.5 → 1.8.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/README.md +2 -1
- package/dist/db-tool/service.d.ts.map +1 -1
- package/dist/gh-tool/branch.d.ts +2 -3
- package/dist/gh-tool/branch.d.ts.map +1 -1
- package/dist/gh-tool/environment.d.ts +1 -1
- package/dist/gh-tool/environment.d.ts.map +1 -1
- package/dist/gh-tool/gist.d.ts +8 -28
- package/dist/gh-tool/gist.d.ts.map +1 -1
- package/dist/gh-tool/issue/commands.d.ts +9 -9
- package/dist/gh-tool/issue/commands.d.ts.map +1 -1
- package/dist/gh-tool/issue/core.d.ts +103 -9
- package/dist/gh-tool/issue/core.d.ts.map +1 -1
- package/dist/gh-tool/issue/triage.d.ts +6 -6
- package/dist/gh-tool/issue/triage.d.ts.map +1 -1
- package/dist/gh-tool/pr/commands.d.ts +53 -46
- package/dist/gh-tool/pr/commands.d.ts.map +1 -1
- package/dist/gh-tool/pr/core.d.ts +156 -86
- package/dist/gh-tool/pr/core.d.ts.map +1 -1
- package/dist/gh-tool/pr/review.d.ts +16 -16
- package/dist/gh-tool/pr/review.d.ts.map +1 -1
- package/dist/gh-tool/pr/snapshot.d.ts +9 -0
- package/dist/gh-tool/pr/snapshot.d.ts.map +1 -0
- package/dist/gh-tool/pr/stack-read.d.ts +1 -6
- package/dist/gh-tool/pr/stack-read.d.ts.map +1 -1
- package/dist/gh-tool/pr/stack.d.ts +3 -3
- package/dist/gh-tool/pr/stack.d.ts.map +1 -1
- package/dist/gh-tool/{api.d.ts → read/api.d.ts} +9 -3
- package/dist/gh-tool/read/api.d.ts.map +1 -0
- package/dist/gh-tool/read/cache.d.ts +44 -0
- package/dist/gh-tool/read/cache.d.ts.map +1 -0
- package/dist/gh-tool/read/catalog.d.ts +170 -0
- package/dist/gh-tool/read/catalog.d.ts.map +1 -0
- package/dist/gh-tool/read/classes.d.ts +94 -0
- package/dist/gh-tool/read/classes.d.ts.map +1 -0
- package/dist/gh-tool/read/commands.d.ts +3 -0
- package/dist/gh-tool/read/commands.d.ts.map +1 -0
- package/dist/gh-tool/read/gated.d.ts +14 -0
- package/dist/gh-tool/read/gated.d.ts.map +1 -0
- package/dist/gh-tool/read/index.d.ts +5 -0
- package/dist/gh-tool/read/index.d.ts.map +1 -0
- package/dist/gh-tool/read/issues.d.ts +68 -0
- package/dist/gh-tool/read/issues.d.ts.map +1 -0
- package/dist/gh-tool/read/keys.d.ts +61 -0
- package/dist/gh-tool/read/keys.d.ts.map +1 -0
- package/dist/gh-tool/read/porcelain.d.ts +68 -0
- package/dist/gh-tool/read/porcelain.d.ts.map +1 -0
- package/dist/gh-tool/read/pulls.d.ts +137 -0
- package/dist/gh-tool/read/pulls.d.ts.map +1 -0
- package/dist/gh-tool/read/reads.d.ts +209 -0
- package/dist/gh-tool/read/reads.d.ts.map +1 -0
- package/dist/gh-tool/read/rest.d.ts +49 -0
- package/dist/gh-tool/read/rest.d.ts.map +1 -0
- package/dist/gh-tool/read/review-guards.d.ts +20 -0
- package/dist/gh-tool/read/review-guards.d.ts.map +1 -0
- package/dist/gh-tool/read/review-model.d.ts +190 -0
- package/dist/gh-tool/read/review-model.d.ts.map +1 -0
- package/dist/gh-tool/read/reviews.d.ts +9 -0
- package/dist/gh-tool/read/reviews.d.ts.map +1 -0
- package/dist/gh-tool/read/stacks.d.ts +7 -0
- package/dist/gh-tool/read/stacks.d.ts.map +1 -0
- package/dist/gh-tool/read/store.d.ts +70 -0
- package/dist/gh-tool/read/store.d.ts.map +1 -0
- package/dist/gh-tool/{service.d.ts → read/transport.d.ts} +5 -3
- package/dist/gh-tool/read/transport.d.ts.map +1 -0
- package/dist/gh-tool/read/waits.d.ts +22 -0
- package/dist/gh-tool/read/waits.d.ts.map +1 -0
- package/dist/gh-tool/read/writes.d.ts +16 -0
- package/dist/gh-tool/read/writes.d.ts.map +1 -0
- package/dist/gh-tool/release.d.ts +10 -26
- package/dist/gh-tool/release.d.ts.map +1 -1
- package/dist/gh-tool/repo.d.ts +4 -4
- package/dist/gh-tool/repo.d.ts.map +1 -1
- package/dist/gh-tool/types.d.ts +1 -1
- package/dist/gh-tool/types.d.ts.map +1 -1
- package/dist/gh-tool/workflow.d.ts +43 -21
- package/dist/gh-tool/workflow.d.ts.map +1 -1
- package/dist/observability-tool/shared.d.ts.map +1 -1
- package/dist/shared/content-security.d.ts +2 -0
- package/dist/shared/content-security.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/api-tool/proxy-entry.ts +3 -1
- package/src/db-tool/service.ts +4 -1
- package/src/gh-tool/branch.ts +5 -8
- package/src/gh-tool/environment.ts +2 -1
- package/src/gh-tool/gist.ts +8 -35
- package/src/gh-tool/issue/commands.ts +1 -1
- package/src/gh-tool/issue/core.ts +55 -122
- package/src/gh-tool/issue/triage.ts +4 -26
- package/src/gh-tool/main.ts +5 -2
- package/src/gh-tool/pr/commands.ts +17 -15
- package/src/gh-tool/pr/core.ts +486 -582
- package/src/gh-tool/pr/review.ts +106 -454
- package/src/gh-tool/pr/snapshot.ts +23 -0
- package/src/gh-tool/pr/stack-read.ts +1 -73
- package/src/gh-tool/pr/stack.ts +37 -36
- package/src/gh-tool/{api.ts → read/api.ts} +40 -7
- package/src/gh-tool/read/cache.ts +192 -0
- package/src/gh-tool/read/catalog.ts +310 -0
- package/src/gh-tool/read/classes.ts +30 -0
- package/src/gh-tool/read/commands.ts +25 -0
- package/src/gh-tool/read/gated.ts +56 -0
- package/src/gh-tool/read/index.ts +4 -0
- package/src/gh-tool/read/issues.ts +107 -0
- package/src/gh-tool/read/keys.ts +102 -0
- package/src/gh-tool/read/porcelain.ts +58 -0
- package/src/gh-tool/read/pulls.ts +266 -0
- package/src/gh-tool/read/reads.ts +306 -0
- package/src/gh-tool/read/rest.ts +111 -0
- package/src/gh-tool/read/review-guards.ts +61 -0
- package/src/gh-tool/read/review-model.ts +286 -0
- package/src/gh-tool/read/reviews.ts +114 -0
- package/src/gh-tool/read/stacks.ts +73 -0
- package/src/gh-tool/read/store.ts +504 -0
- package/src/gh-tool/{service.ts → read/transport.ts} +26 -6
- package/src/gh-tool/read/waits.ts +52 -0
- package/src/gh-tool/read/writes.ts +37 -0
- package/src/gh-tool/release.ts +15 -168
- package/src/gh-tool/repo.ts +5 -78
- package/src/gh-tool/types.ts +1 -1
- package/src/gh-tool/workflow.ts +123 -214
- package/src/observability-tool/shared.ts +2 -1
- package/src/shared/content-security.ts +10 -1
- package/src/shared/credential-patterns.ts +1 -1
- package/dist/gh-tool/api.d.ts.map +0 -1
- package/dist/gh-tool/pr/check-status-cache.d.ts +0 -6
- package/dist/gh-tool/pr/check-status-cache.d.ts.map +0 -1
- package/dist/gh-tool/service.d.ts.map +0 -1
- package/src/gh-tool/pr/check-status-cache.ts +0 -142
package/src/gh-tool/branch.ts
CHANGED
|
@@ -3,7 +3,9 @@ import { Effect, Option } from "effect";
|
|
|
3
3
|
|
|
4
4
|
import { formatOption, logFormatted } from "#shared";
|
|
5
5
|
import type { BranchRenameResult } from "./types";
|
|
6
|
-
import {
|
|
6
|
+
import { writes } from "./read/writes";
|
|
7
|
+
import { resolveRepo } from "./read/reads";
|
|
8
|
+
import { repoSlug } from "./read/keys";
|
|
7
9
|
|
|
8
10
|
// ---------------------------------------------------------------------------
|
|
9
11
|
// Internal handlers
|
|
@@ -15,8 +17,6 @@ export const renameBranch = Effect.fn("branch.renameBranch")(function* (opts: {
|
|
|
15
17
|
confirm: boolean;
|
|
16
18
|
repo: string | null;
|
|
17
19
|
}) {
|
|
18
|
-
const gh = yield* GitHubService;
|
|
19
|
-
|
|
20
20
|
if (!opts.confirm) {
|
|
21
21
|
const scope = opts.repo !== null ? ` in ${opts.repo}` : "";
|
|
22
22
|
|
|
@@ -31,10 +31,7 @@ export const renameBranch = Effect.fn("branch.renameBranch")(function* (opts: {
|
|
|
31
31
|
return dryRun;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const repoInfo =
|
|
35
|
-
opts.repo !== null
|
|
36
|
-
? opts.repo
|
|
37
|
-
: yield* gh.getRepoInfo().pipe(Effect.map((r) => `${r.owner}/${r.name}`));
|
|
34
|
+
const repoInfo = opts.repo !== null ? opts.repo : repoSlug(yield* resolveRepo(null));
|
|
38
35
|
|
|
39
36
|
const args = [
|
|
40
37
|
"api",
|
|
@@ -45,7 +42,7 @@ export const renameBranch = Effect.fn("branch.renameBranch")(function* (opts: {
|
|
|
45
42
|
`new_name=${opts.newName}`,
|
|
46
43
|
];
|
|
47
44
|
|
|
48
|
-
yield*
|
|
45
|
+
yield* writes.run(args, [`repo:${repoInfo.toLowerCase()}`]);
|
|
49
46
|
|
|
50
47
|
const result: BranchRenameResult = {
|
|
51
48
|
renamed: true,
|
|
@@ -41,10 +41,11 @@ const GH_ENVIRONMENT_NAMES = [
|
|
|
41
41
|
|
|
42
42
|
export const ghEnvironment = (
|
|
43
43
|
environment: Record<string, string | undefined> = process.env,
|
|
44
|
+
credential: string | null = null,
|
|
44
45
|
): Record<string, string> =>
|
|
45
46
|
Object.fromEntries(
|
|
46
47
|
GH_ENVIRONMENT_NAMES.flatMap((name) => {
|
|
47
|
-
const value = environment[name];
|
|
48
|
+
const value = name === "GH_TOKEN" && credential !== null ? credential : environment[name];
|
|
48
49
|
return value === undefined ? [] : [[name, value]];
|
|
49
50
|
}),
|
|
50
51
|
);
|
package/src/gh-tool/gist.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { passthrough } from "./read/catalog";
|
|
2
|
+
import type { GistApi } from "./read/catalog";
|
|
3
|
+
import { writes } from "./read/writes";
|
|
1
4
|
import { Command, Flag } from "effect/cli";
|
|
2
5
|
import { Effect, Option } from "effect";
|
|
3
6
|
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
@@ -11,33 +14,12 @@ import {
|
|
|
11
14
|
resolveOptionalTextInput,
|
|
12
15
|
} from "#gh/text-input";
|
|
13
16
|
import { GitHubCommandError } from "./errors";
|
|
14
|
-
import { GitHubService } from "./service";
|
|
15
17
|
|
|
16
18
|
// ---------------------------------------------------------------------------
|
|
17
19
|
// Types
|
|
18
20
|
// ---------------------------------------------------------------------------
|
|
19
21
|
|
|
20
22
|
// `gh gist list/view` have no --json, so reads go through `gh api gists` (REST shape).
|
|
21
|
-
type GistApiFile = {
|
|
22
|
-
filename: string;
|
|
23
|
-
language: string | null;
|
|
24
|
-
type: string;
|
|
25
|
-
size: number;
|
|
26
|
-
truncated?: boolean;
|
|
27
|
-
content?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type GistApi = {
|
|
31
|
-
id: string;
|
|
32
|
-
description: string | null;
|
|
33
|
-
public: boolean;
|
|
34
|
-
html_url: string;
|
|
35
|
-
created_at: string;
|
|
36
|
-
updated_at: string;
|
|
37
|
-
owner: { login: string } | null;
|
|
38
|
-
files: Record<string, GistApiFile>;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
23
|
type GistListItem = {
|
|
42
24
|
id: string;
|
|
43
25
|
description: string | null;
|
|
@@ -247,9 +229,7 @@ const listGists = Effect.fn("gist.listGists")(function* (opts: {
|
|
|
247
229
|
limit: number;
|
|
248
230
|
visibility: string | null;
|
|
249
231
|
}) {
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
const gists = yield* gh.runGhJson<GistApi[]>(["api", `gists?per_page=${opts.limit}`]);
|
|
232
|
+
const gists = yield* passthrough.gistList(opts.limit);
|
|
253
233
|
|
|
254
234
|
return gists
|
|
255
235
|
.filter(
|
|
@@ -264,9 +244,7 @@ const viewGist = Effect.fn("gist.viewGist")(function* (opts: {
|
|
|
264
244
|
filename: string | null;
|
|
265
245
|
withContent: boolean;
|
|
266
246
|
}) {
|
|
267
|
-
const
|
|
268
|
-
|
|
269
|
-
const gist = yield* gh.runGhJson<GistApi>(["api", `gists/${opts.id}`]);
|
|
247
|
+
const gist = yield* passthrough.gistView(opts.id);
|
|
270
248
|
|
|
271
249
|
return toGistDetail(gist, { filename: opts.filename, withContent: opts.withContent });
|
|
272
250
|
});
|
|
@@ -276,7 +254,6 @@ export const createGist = Effect.fn("gist.createGist")(function* (opts: {
|
|
|
276
254
|
description: string | null;
|
|
277
255
|
public: boolean;
|
|
278
256
|
}) {
|
|
279
|
-
const gh = yield* GitHubService;
|
|
280
257
|
return yield* Effect.scoped(
|
|
281
258
|
Effect.gen(function* () {
|
|
282
259
|
const snapshots: string[] = [];
|
|
@@ -298,7 +275,7 @@ export const createGist = Effect.fn("gist.createGist")(function* (opts: {
|
|
|
298
275
|
args.push("--public");
|
|
299
276
|
}
|
|
300
277
|
|
|
301
|
-
const result = yield*
|
|
278
|
+
const result = yield* writes.run(args, []);
|
|
302
279
|
const url =
|
|
303
280
|
result.stdout
|
|
304
281
|
.trim()
|
|
@@ -333,8 +310,6 @@ export const editGist = Effect.fn("gist.editGist")(function* (opts: {
|
|
|
333
310
|
filename: string | null;
|
|
334
311
|
sourcePath: string | null;
|
|
335
312
|
}) {
|
|
336
|
-
const gh = yield* GitHubService;
|
|
337
|
-
|
|
338
313
|
const args = ["gist", "edit", opts.id];
|
|
339
314
|
const changes: string[] = [];
|
|
340
315
|
|
|
@@ -371,7 +346,7 @@ export const editGist = Effect.fn("gist.editGist")(function* (opts: {
|
|
|
371
346
|
args.push("--filename", opts.filename);
|
|
372
347
|
}
|
|
373
348
|
|
|
374
|
-
yield*
|
|
349
|
+
yield* writes.run(args, []);
|
|
375
350
|
|
|
376
351
|
const edited: GistEditResult = { edited: true, id: opts.id, changes };
|
|
377
352
|
|
|
@@ -379,8 +354,6 @@ export const editGist = Effect.fn("gist.editGist")(function* (opts: {
|
|
|
379
354
|
});
|
|
380
355
|
|
|
381
356
|
const deleteGist = Effect.fn("gist.deleteGist")(function* (opts: { id: string; confirm: boolean }) {
|
|
382
|
-
const gh = yield* GitHubService;
|
|
383
|
-
|
|
384
357
|
if (!opts.confirm) {
|
|
385
358
|
const dryRun: GistDeleteResult = {
|
|
386
359
|
deleted: false,
|
|
@@ -392,7 +365,7 @@ const deleteGist = Effect.fn("gist.deleteGist")(function* (opts: { id: string; c
|
|
|
392
365
|
return dryRun;
|
|
393
366
|
}
|
|
394
367
|
|
|
395
|
-
yield*
|
|
368
|
+
yield* writes.run(["gist", "delete", opts.id, "--yes"], []);
|
|
396
369
|
|
|
397
370
|
const deleted: GistDeleteResult = { deleted: true, id: opts.id };
|
|
398
371
|
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
reopenIssue,
|
|
19
19
|
viewIssue,
|
|
20
20
|
} from "./core";
|
|
21
|
-
import { GitHubService } from "#gh/
|
|
21
|
+
import { GitHubService } from "#gh/read/transport";
|
|
22
22
|
|
|
23
23
|
const repoOption = Flag.String("repo").pipe(
|
|
24
24
|
Flag.withDescription("Target repository profile name or owner/name"),
|
|
@@ -3,7 +3,11 @@ import { Effect } from "effect";
|
|
|
3
3
|
import type { GitHubIssueCommentUrl, IssueComment, IssueCommentId, IsoTimestamp } from "#gh/types";
|
|
4
4
|
|
|
5
5
|
import { GitHubCommandError } from "#gh/errors";
|
|
6
|
-
import { GitHubService } from "#gh/
|
|
6
|
+
import { GitHubService } from "#gh/read/transport";
|
|
7
|
+
import { reads, resolveRepo } from "#gh/read/reads";
|
|
8
|
+
import { writes } from "#gh/read/writes";
|
|
9
|
+
import { project } from "#gh/read/porcelain";
|
|
10
|
+
import { repoSlug } from "#gh/read/keys";
|
|
7
11
|
|
|
8
12
|
export type IssueInfo = {
|
|
9
13
|
number: number;
|
|
@@ -34,52 +38,6 @@ export type RawIssueComment = {
|
|
|
34
38
|
html_url: string;
|
|
35
39
|
};
|
|
36
40
|
|
|
37
|
-
const REST_PAGE_SIZE = 100;
|
|
38
|
-
|
|
39
|
-
const parseJson = <T>(
|
|
40
|
-
stdout: string,
|
|
41
|
-
command: string,
|
|
42
|
-
parseFailurePrefix: string,
|
|
43
|
-
): Effect.Effect<T, GitHubCommandError> =>
|
|
44
|
-
Effect.try({
|
|
45
|
-
try: () => JSON.parse(stdout) as T,
|
|
46
|
-
catch: (error) =>
|
|
47
|
-
new GitHubCommandError({
|
|
48
|
-
command,
|
|
49
|
-
exitCode: 0,
|
|
50
|
-
stderr: `${parseFailurePrefix}: ${error instanceof Error ? error.message : String(error)}`,
|
|
51
|
-
message: `${parseFailurePrefix}: ${error instanceof Error ? error.message : String(error)}`,
|
|
52
|
-
}),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const fetchAllRestPages = Effect.fn("issue.fetchAllRestPages")(function* <T>(
|
|
56
|
-
endpoint: string,
|
|
57
|
-
command: string,
|
|
58
|
-
parseFailurePrefix: string,
|
|
59
|
-
) {
|
|
60
|
-
const service = yield* GitHubService;
|
|
61
|
-
|
|
62
|
-
const results: T[] = [];
|
|
63
|
-
let page = 1;
|
|
64
|
-
|
|
65
|
-
while (true) {
|
|
66
|
-
const separator = endpoint.includes("?") ? "&" : "?";
|
|
67
|
-
const result = yield* service.runGh([
|
|
68
|
-
"api",
|
|
69
|
-
`${endpoint}${separator}per_page=${REST_PAGE_SIZE}&page=${page}`,
|
|
70
|
-
]);
|
|
71
|
-
|
|
72
|
-
const rawPage = yield* parseJson<T[]>(result.stdout, command, parseFailurePrefix);
|
|
73
|
-
results.push(...rawPage);
|
|
74
|
-
|
|
75
|
-
if (rawPage.length < REST_PAGE_SIZE) {
|
|
76
|
-
return results;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
page += 1;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
41
|
const mapRawIssueComment = (comment: RawIssueComment): IssueComment => ({
|
|
84
42
|
id: comment.id as IssueCommentId,
|
|
85
43
|
commitSha: null,
|
|
@@ -95,35 +53,21 @@ export const listIssues = Effect.fn("issue.listIssues")(function* (opts: {
|
|
|
95
53
|
labels: string | null;
|
|
96
54
|
limit: number;
|
|
97
55
|
}) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const args = [
|
|
101
|
-
"issue",
|
|
102
|
-
"list",
|
|
103
|
-
"--state",
|
|
104
|
-
opts.state,
|
|
105
|
-
"--limit",
|
|
106
|
-
String(opts.limit),
|
|
107
|
-
"--json",
|
|
108
|
-
"number,title,state,url,labels,createdAt",
|
|
109
|
-
];
|
|
110
|
-
|
|
111
|
-
if (opts.labels !== null) {
|
|
112
|
-
args.push("--label", opts.labels);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return yield* gh.runGhJson<IssueListItem[]>(args);
|
|
56
|
+
return yield* reads.issueList(yield* resolveRepo(null), opts);
|
|
116
57
|
});
|
|
117
58
|
|
|
118
59
|
export const viewIssue = Effect.fn("issue.viewIssue")(function* (issueNumber: number) {
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"
|
|
123
|
-
"
|
|
124
|
-
|
|
125
|
-
"
|
|
126
|
-
"
|
|
60
|
+
const value = yield* reads.issueView(yield* resolveRepo(null), issueNumber);
|
|
61
|
+
return project(value, [
|
|
62
|
+
"number",
|
|
63
|
+
"title",
|
|
64
|
+
"state",
|
|
65
|
+
"url",
|
|
66
|
+
"labels",
|
|
67
|
+
"assignees",
|
|
68
|
+
"author",
|
|
69
|
+
"createdAt",
|
|
70
|
+
"closedAt",
|
|
127
71
|
]);
|
|
128
72
|
});
|
|
129
73
|
|
|
@@ -133,14 +77,7 @@ export const fetchIssueComments = Effect.fn("issue.fetchIssueComments")(function
|
|
|
133
77
|
author: string | null,
|
|
134
78
|
bodyContains: string | null,
|
|
135
79
|
) {
|
|
136
|
-
const
|
|
137
|
-
const repoInfo = yield* gh.getRepoInfo();
|
|
138
|
-
|
|
139
|
-
const raw = yield* fetchAllRestPages<RawIssueComment>(
|
|
140
|
-
`repos/${repoInfo.owner}/${repoInfo.name}/issues/${issueNumber}/comments`,
|
|
141
|
-
"gh-tool issue comments",
|
|
142
|
-
"Failed to parse response",
|
|
143
|
-
);
|
|
80
|
+
const raw = yield* reads.issueComments(yield* resolveRepo(null), issueNumber);
|
|
144
81
|
|
|
145
82
|
let comments = raw.map(mapRawIssueComment);
|
|
146
83
|
|
|
@@ -167,46 +104,40 @@ export const closeIssue = Effect.fn("issue.closeIssue")(function* (opts: {
|
|
|
167
104
|
comment: string | null;
|
|
168
105
|
reason: string;
|
|
169
106
|
}) {
|
|
170
|
-
const gh = yield* GitHubService;
|
|
171
|
-
|
|
172
107
|
const args = ["issue", "close", String(opts.issue), "--reason", opts.reason];
|
|
173
108
|
|
|
174
109
|
if (opts.comment !== null) {
|
|
175
110
|
args.push("--comment", opts.comment);
|
|
176
111
|
}
|
|
177
112
|
|
|
178
|
-
yield*
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
String(opts.issue),
|
|
184
|
-
"--json",
|
|
185
|
-
"number,title,state,url,labels,assignees,author,createdAt,closedAt",
|
|
113
|
+
const repo = yield* resolveRepo(null);
|
|
114
|
+
yield* writes.run(args, [
|
|
115
|
+
`issue:${repoSlug(repo)}#${opts.issue}`,
|
|
116
|
+
`issues:${repoSlug(repo)}`,
|
|
117
|
+
`issue-comments:${repoSlug(repo)}#${opts.issue}`,
|
|
186
118
|
]);
|
|
119
|
+
|
|
120
|
+
return yield* viewIssue(opts.issue);
|
|
187
121
|
});
|
|
188
122
|
|
|
189
123
|
export const reopenIssue = Effect.fn("issue.reopenIssue")(function* (opts: {
|
|
190
124
|
issue: number;
|
|
191
125
|
comment: string | null;
|
|
192
126
|
}) {
|
|
193
|
-
const gh = yield* GitHubService;
|
|
194
|
-
|
|
195
127
|
const args = ["issue", "reopen", String(opts.issue)];
|
|
196
128
|
|
|
197
129
|
if (opts.comment !== null) {
|
|
198
130
|
args.push("--comment", opts.comment);
|
|
199
131
|
}
|
|
200
132
|
|
|
201
|
-
yield*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
String(opts.issue),
|
|
207
|
-
"--json",
|
|
208
|
-
"number,title,state,url,labels,assignees,author,createdAt,closedAt",
|
|
133
|
+
const repo = yield* resolveRepo(null);
|
|
134
|
+
yield* writes.run(args, [
|
|
135
|
+
`issue:${repoSlug(repo)}#${opts.issue}`,
|
|
136
|
+
`issues:${repoSlug(repo)}`,
|
|
137
|
+
`issue-comments:${repoSlug(repo)}#${opts.issue}`,
|
|
209
138
|
]);
|
|
139
|
+
|
|
140
|
+
return yield* viewIssue(opts.issue);
|
|
210
141
|
});
|
|
211
142
|
|
|
212
143
|
export const commentOnIssue = Effect.fn("issue.commentOnIssue")(function* (opts: {
|
|
@@ -227,14 +158,20 @@ export const commentOnIssue = Effect.fn("issue.commentOnIssue")(function* (opts:
|
|
|
227
158
|
);
|
|
228
159
|
}
|
|
229
160
|
|
|
230
|
-
const result = yield*
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
161
|
+
const result = yield* writes.run(
|
|
162
|
+
[
|
|
163
|
+
"api",
|
|
164
|
+
"-X",
|
|
165
|
+
"POST",
|
|
166
|
+
`repos/${repoInfo.owner}/${repoInfo.name}/issues/${opts.issue}/comments`,
|
|
167
|
+
"-f",
|
|
168
|
+
`body=${opts.body}`,
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
`issue-comments:${repoInfo.owner.toLowerCase()}/${repoInfo.name.toLowerCase()}#${opts.issue}`,
|
|
172
|
+
`issue:${repoInfo.owner.toLowerCase()}/${repoInfo.name.toLowerCase()}#${opts.issue}`,
|
|
173
|
+
],
|
|
174
|
+
);
|
|
238
175
|
|
|
239
176
|
const rawComment = yield* Effect.try({
|
|
240
177
|
try: () => JSON.parse(result.stdout) as RawIssueComment,
|
|
@@ -262,8 +199,6 @@ export const createIssue = Effect.fn("issue.createIssue")(function* (opts: {
|
|
|
262
199
|
assignee: string | null;
|
|
263
200
|
labels: string | null;
|
|
264
201
|
}) {
|
|
265
|
-
const gh = yield* GitHubService;
|
|
266
|
-
|
|
267
202
|
const args = ["issue", "create", "--title", opts.title, "--body", opts.body];
|
|
268
203
|
|
|
269
204
|
if (opts.assignee !== null) {
|
|
@@ -273,7 +208,8 @@ export const createIssue = Effect.fn("issue.createIssue")(function* (opts: {
|
|
|
273
208
|
args.push("--label", opts.labels);
|
|
274
209
|
}
|
|
275
210
|
|
|
276
|
-
const
|
|
211
|
+
const repo = yield* resolveRepo(null);
|
|
212
|
+
const result = yield* writes.run(args, [`repo:${repoSlug(repo)}`]);
|
|
277
213
|
|
|
278
214
|
const urlMatch = result.stdout.match(/\/issues\/(\d+)/);
|
|
279
215
|
if (!urlMatch?.[1]) {
|
|
@@ -299,8 +235,6 @@ export const editIssue = Effect.fn("issue.editIssue")(function* (opts: {
|
|
|
299
235
|
addAssignee: string | null;
|
|
300
236
|
removeAssignee: string | null;
|
|
301
237
|
}) {
|
|
302
|
-
const gh = yield* GitHubService;
|
|
303
|
-
|
|
304
238
|
const args = ["issue", "edit", String(opts.issue)];
|
|
305
239
|
|
|
306
240
|
if (opts.title !== null) {
|
|
@@ -322,13 +256,12 @@ export const editIssue = Effect.fn("issue.editIssue")(function* (opts: {
|
|
|
322
256
|
args.push("--remove-assignee", opts.removeAssignee);
|
|
323
257
|
}
|
|
324
258
|
|
|
325
|
-
yield*
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
String(opts.issue),
|
|
331
|
-
"--json",
|
|
332
|
-
"number,title,state,url,labels,assignees,author,createdAt,closedAt",
|
|
259
|
+
const repo = yield* resolveRepo(null);
|
|
260
|
+
yield* writes.run(args, [
|
|
261
|
+
`issue:${repoSlug(repo)}#${opts.issue}`,
|
|
262
|
+
`issues:${repoSlug(repo)}`,
|
|
263
|
+
`issue-comments:${repoSlug(repo)}#${opts.issue}`,
|
|
333
264
|
]);
|
|
265
|
+
|
|
266
|
+
return yield* viewIssue(opts.issue);
|
|
334
267
|
});
|
|
@@ -4,10 +4,11 @@ import { Effect, Option, Schema } from "effect";
|
|
|
4
4
|
import type { CheckResult, IssueComment, PRViewInfo, ReviewThread } from "#gh/types";
|
|
5
5
|
|
|
6
6
|
import { formatOption, logFormatted } from "#shared";
|
|
7
|
-
import { GitHubService } from "#gh/
|
|
7
|
+
import { GitHubService } from "#gh/read/transport";
|
|
8
8
|
import { fetchReviewTriage } from "#gh/pr/commands";
|
|
9
9
|
|
|
10
10
|
import { fetchIssueComments } from "./core";
|
|
11
|
+
import { reads, resolveRepo } from "#gh/read/reads";
|
|
11
12
|
|
|
12
13
|
const repoOption = Flag.String("repo").pipe(
|
|
13
14
|
Flag.withDescription("Target repository profile name or owner/name"),
|
|
@@ -23,19 +24,6 @@ const withRepo = <A, E, R>(repo: Option.Option<string>, effect: Effect.Effect<A,
|
|
|
23
24
|
const TriageVerbosity = Schema.Literals(["compact", "full"]);
|
|
24
25
|
type TriageVerbosity = typeof TriageVerbosity.Type;
|
|
25
26
|
|
|
26
|
-
type RawTriageIssue = {
|
|
27
|
-
number: number;
|
|
28
|
-
title: string;
|
|
29
|
-
state: string;
|
|
30
|
-
url: string;
|
|
31
|
-
labels: Array<{ name: string }>;
|
|
32
|
-
assignees: Array<{ login: string }>;
|
|
33
|
-
author: { login: string };
|
|
34
|
-
body: string;
|
|
35
|
-
createdAt: string;
|
|
36
|
-
closedAt: string | null;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
27
|
type TriageIssue = {
|
|
40
28
|
number: number;
|
|
41
29
|
title: string;
|
|
@@ -114,19 +102,9 @@ export const fetchIssueTriage = Effect.fn("issue.fetchIssueTriage")(function* (o
|
|
|
114
102
|
issue: number;
|
|
115
103
|
verbosity: TriageVerbosity;
|
|
116
104
|
}) {
|
|
117
|
-
const
|
|
118
|
-
|
|
105
|
+
const repo = yield* resolveRepo(null);
|
|
119
106
|
const [rawIssue, comments] = yield* Effect.all(
|
|
120
|
-
[
|
|
121
|
-
gh.runGhJson<RawTriageIssue>([
|
|
122
|
-
"issue",
|
|
123
|
-
"view",
|
|
124
|
-
String(opts.issue),
|
|
125
|
-
"--json",
|
|
126
|
-
"number,title,state,url,labels,assignees,author,body,createdAt,closedAt",
|
|
127
|
-
]),
|
|
128
|
-
fetchIssueComments(opts.issue, null, null, null),
|
|
129
|
-
],
|
|
107
|
+
[reads.issueView(repo, opts.issue), fetchIssueComments(opts.issue, null, null, null)],
|
|
130
108
|
{ concurrency: "unbounded" },
|
|
131
109
|
);
|
|
132
110
|
|
package/src/gh-tool/main.ts
CHANGED
|
@@ -72,7 +72,9 @@ import {
|
|
|
72
72
|
releaseViewCommand,
|
|
73
73
|
} from "./release";
|
|
74
74
|
import { repoInfoCommand, repoListCommand, repoSearchCodeCommand } from "./repo";
|
|
75
|
-
import { GitHubService } from "./
|
|
75
|
+
import { GitHubService } from "./read/transport";
|
|
76
|
+
import { withReadCache } from "./read";
|
|
77
|
+
import { cacheCommand } from "./read/commands";
|
|
76
78
|
import {
|
|
77
79
|
workflowAnnotationsCommand,
|
|
78
80
|
workflowCancelCommand,
|
|
@@ -240,6 +242,7 @@ WORKFLOW FOR AI AGENTS:
|
|
|
240
242
|
releaseCommand,
|
|
241
243
|
gistCommand,
|
|
242
244
|
commandsCommand,
|
|
245
|
+
cacheCommand,
|
|
243
246
|
]),
|
|
244
247
|
);
|
|
245
248
|
|
|
@@ -254,7 +257,7 @@ const MainLayer = GitHubService.layer.pipe(
|
|
|
254
257
|
Layer.provideMerge(ConfigServiceLayer),
|
|
255
258
|
);
|
|
256
259
|
|
|
257
|
-
const program = withRedactedOutput(withAudit("gh", cli)).pipe(
|
|
260
|
+
const program = withReadCache(withRedactedOutput(withAudit("gh", cli))).pipe(
|
|
258
261
|
Effect.provide(MainLayer),
|
|
259
262
|
Effect.tapCause(renderCauseToStderr),
|
|
260
263
|
);
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { reads, writes } from "#gh/read/index";
|
|
2
|
+
import { repoSlug } from "#gh/read/keys";
|
|
1
3
|
import { Command, Flag, Param } from "effect/cli";
|
|
2
4
|
import { Console, Effect, Option } from "effect";
|
|
3
5
|
|
|
4
6
|
import type { CheckResult, PRStatusResult } from "#gh/types";
|
|
5
7
|
|
|
6
8
|
import { formatOption, logFormatted, logText } from "#shared";
|
|
7
|
-
import { GitHubService } from "#gh/
|
|
9
|
+
import { GitHubService } from "#gh/read/transport";
|
|
8
10
|
import { GitHubCommandError } from "#gh/errors";
|
|
9
11
|
|
|
10
12
|
const emptyBatchError = (batch: string) =>
|
|
@@ -152,20 +154,20 @@ export const requestReview = (pr: number, reviewers: string) =>
|
|
|
152
154
|
const repo = yield* gh.getRepoInfo();
|
|
153
155
|
// ponytail: not atomic — a concurrent request between GET and POST misreports newlyRequested.
|
|
154
156
|
const pendingBefore = new Set(
|
|
155
|
-
(yield* confirmedReviewers(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
(yield* confirmedReviewers(yield* reads.reviewGuards.requestedReviewers(repo, pr))).map(
|
|
158
|
+
(login) => login.toLowerCase(),
|
|
159
|
+
),
|
|
160
|
+
);
|
|
161
|
+
const response = yield* writes.json<RequestedReviewersResponse>(
|
|
162
|
+
[
|
|
163
|
+
"api",
|
|
164
|
+
"--method",
|
|
165
|
+
"POST",
|
|
166
|
+
`repos/${repo.owner}/${repo.name}/pulls/${pr}/requested_reviewers`,
|
|
167
|
+
...submittedReviewers.flatMap((reviewer) => ["-f", `reviewers[]=${reviewer}`]),
|
|
168
|
+
],
|
|
169
|
+
[`pr:${repoSlug(repo)}#${pr}`, `reviews:${repoSlug(repo)}#${pr}`, `pulls:${repoSlug(repo)}`],
|
|
161
170
|
);
|
|
162
|
-
const response = yield* gh.runGhJson<RequestedReviewersResponse>([
|
|
163
|
-
"api",
|
|
164
|
-
"--method",
|
|
165
|
-
"POST",
|
|
166
|
-
`repos/${repo.owner}/${repo.name}/pulls/${pr}/requested_reviewers`,
|
|
167
|
-
...submittedReviewers.flatMap((reviewer) => ["-f", `reviewers[]=${reviewer}`]),
|
|
168
|
-
]);
|
|
169
171
|
return {
|
|
170
172
|
pr,
|
|
171
173
|
submittedReviewers,
|
|
@@ -239,7 +241,7 @@ const withStableHead = Effect.fn("pr.withStableHead")(function* <A, E, R>(
|
|
|
239
241
|
initial,
|
|
240
242
|
(info) => collect(info.number, info.headSha),
|
|
241
243
|
(info) =>
|
|
242
|
-
fetchPRView(info.number).pipe(
|
|
244
|
+
fetchPRView(info.number, "origin").pipe(
|
|
243
245
|
Effect.map((refreshed) => ({ ...refreshed, baseSha: initial.baseSha })),
|
|
244
246
|
),
|
|
245
247
|
(before, after) => after.headSha === before.headSha,
|