@rumen.rusanov/pi-github 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/LICENSE +21 -0
- package/README.md +103 -0
- package/package.json +36 -0
- package/src/format.ts +22 -0
- package/src/gh-cli.ts +23 -0
- package/src/gh-data.ts +393 -0
- package/src/index.ts +47 -0
- package/src/repo.ts +54 -0
- package/src/settings.ts +58 -0
- package/src/types.ts +106 -0
- package/src/ui/app.ts +632 -0
- package/src/ui/filter.ts +12 -0
- package/src/ui/messages.ts +24 -0
- package/src/ui/rows.ts +98 -0
- package/src/ui/two-line-list.ts +78 -0
- package/tests/app.test.ts +235 -0
- package/tests/filter.test.ts +41 -0
- package/tests/format.test.ts +34 -0
- package/tests/gh-cli.test.ts +31 -0
- package/tests/gh-data.test.ts +259 -0
- package/tests/messages.test.ts +24 -0
- package/tests/repo.test.ts +76 -0
- package/tests/rows.test.ts +90 -0
- package/tests/settings.test.ts +54 -0
- package/tests/two-line-list.test.ts +62 -0
- package/tsconfig.json +17 -0
- package/vitest.config.ts +7 -0
package/src/settings.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { readFile as fsReadFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_FETCH_LIMIT = 20;
|
|
6
|
+
|
|
7
|
+
interface PiGithubSettings {
|
|
8
|
+
fetchLimit?: unknown;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface GetFetchLimitOptions {
|
|
12
|
+
cwd: string;
|
|
13
|
+
home?: string;
|
|
14
|
+
readFile?: (path: string) => Promise<string>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function readPiGithubSettings(
|
|
18
|
+
path: string,
|
|
19
|
+
readFile: (path: string) => Promise<string>,
|
|
20
|
+
): Promise<PiGithubSettings | undefined> {
|
|
21
|
+
let content: string;
|
|
22
|
+
try {
|
|
23
|
+
content = await readFile(path);
|
|
24
|
+
} catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(content) as Record<string, unknown>;
|
|
30
|
+
const section = parsed["pi-github"];
|
|
31
|
+
if (section && typeof section === "object") {
|
|
32
|
+
return section as PiGithubSettings;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
} catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function asPositiveInteger(value: unknown): number | undefined {
|
|
41
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Reads the `pi-github.fetchLimit` setting, project settings taking precedence over global. */
|
|
45
|
+
export async function getFetchLimit(options: GetFetchLimitOptions): Promise<number> {
|
|
46
|
+
const readFile = options.readFile ?? ((path: string) => fsReadFile(path, "utf8"));
|
|
47
|
+
const home = options.home ?? homedir();
|
|
48
|
+
|
|
49
|
+
const globalPath = join(home, ".pi", "agent", "settings.json");
|
|
50
|
+
const projectPath = join(options.cwd, ".pi", "settings.json");
|
|
51
|
+
|
|
52
|
+
const [global, project] = await Promise.all([
|
|
53
|
+
readPiGithubSettings(globalPath, readFile),
|
|
54
|
+
readPiGithubSettings(projectPath, readFile),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
return asPositiveInteger(project?.fetchLimit) ?? asPositiveInteger(global?.fetchLimit) ?? DEFAULT_FETCH_LIMIT;
|
|
58
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export interface ExecResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
code: number;
|
|
5
|
+
killed: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ExecOptions {
|
|
9
|
+
signal?: AbortSignal;
|
|
10
|
+
timeout?: number;
|
|
11
|
+
cwd?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ExecFn = (command: string, args: string[], options?: ExecOptions) => Promise<ExecResult>;
|
|
15
|
+
|
|
16
|
+
export type Result<T> = { ok: true; data: T } | { ok: false; error: string };
|
|
17
|
+
|
|
18
|
+
export interface Actor {
|
|
19
|
+
login: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface Label {
|
|
24
|
+
name: string;
|
|
25
|
+
color?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Comment {
|
|
29
|
+
author: string;
|
|
30
|
+
body: string;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type CheckState = "pass" | "fail" | "pending";
|
|
35
|
+
|
|
36
|
+
export interface CheckRun {
|
|
37
|
+
name: string;
|
|
38
|
+
state: CheckState;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type ReviewState = "APPROVED" | "CHANGES_REQUESTED" | "COMMENTED" | "DISMISSED" | "PENDING";
|
|
42
|
+
|
|
43
|
+
export interface Review {
|
|
44
|
+
author: string;
|
|
45
|
+
state: ReviewState;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface FileChange {
|
|
49
|
+
path: string;
|
|
50
|
+
additions: number;
|
|
51
|
+
deletions: number;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PullRequestSummary {
|
|
55
|
+
number: number;
|
|
56
|
+
title: string;
|
|
57
|
+
author: string;
|
|
58
|
+
isDraft: boolean;
|
|
59
|
+
checkState: CheckState | "none";
|
|
60
|
+
approvals: number;
|
|
61
|
+
changesRequested: number;
|
|
62
|
+
updatedAt: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface IssueSummary {
|
|
66
|
+
number: number;
|
|
67
|
+
title: string;
|
|
68
|
+
author: string;
|
|
69
|
+
commentCount: number;
|
|
70
|
+
labels: string[];
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface PullRequestDetail {
|
|
75
|
+
number: number;
|
|
76
|
+
title: string;
|
|
77
|
+
author: string;
|
|
78
|
+
state: string;
|
|
79
|
+
isDraft: boolean;
|
|
80
|
+
labels: string[];
|
|
81
|
+
assignees: string[];
|
|
82
|
+
createdAt: string;
|
|
83
|
+
updatedAt: string;
|
|
84
|
+
body: string;
|
|
85
|
+
comments: Comment[];
|
|
86
|
+
baseRefName: string;
|
|
87
|
+
headRefName: string;
|
|
88
|
+
checks: CheckRun[];
|
|
89
|
+
reviews: Review[];
|
|
90
|
+
files: FileChange[];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface IssueDetail {
|
|
94
|
+
number: number;
|
|
95
|
+
title: string;
|
|
96
|
+
author: string;
|
|
97
|
+
state: string;
|
|
98
|
+
labels: string[];
|
|
99
|
+
assignees: string[];
|
|
100
|
+
createdAt: string;
|
|
101
|
+
updatedAt: string;
|
|
102
|
+
body: string;
|
|
103
|
+
comments: Comment[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export type MergeMethod = "squash" | "merge" | "rebase";
|