@ghfs/cli 0.0.3 → 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/dist/dir.d.mts ADDED
@@ -0,0 +1,4 @@
1
+ //#region src/dir.d.ts
2
+ declare const distDir: string;
3
+ //#endregion
4
+ export { distDir };
package/dist/dir.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { fileURLToPath } from "node:url";
2
+ //#region src/dir.ts
3
+ const distDir = fileURLToPath(new URL("../dist", import.meta.url));
4
+ //#endregion
5
+ export { distDir };
@@ -1,7 +1,6 @@
1
1
  import { retry } from "@octokit/plugin-retry";
2
2
  import { throttling } from "@octokit/plugin-throttling";
3
3
  import { Octokit } from "octokit";
4
-
5
4
  //#region src/utils/repo.ts
6
5
  function splitRepo(repo) {
7
6
  const [owner, name] = repo.split("/");
@@ -11,13 +10,11 @@ function splitRepo(repo) {
11
10
  repo: name
12
11
  };
13
12
  }
14
-
15
13
  //#endregion
16
14
  //#region src/utils/color.ts
17
15
  function randomHexColor() {
18
16
  return Math.floor(Math.random() * 16777216).toString(16).padStart(6, "0");
19
17
  }
20
-
21
18
  //#endregion
22
19
  //#region src/utils/format.ts
23
20
  function formatIssueNumber(number, options = {}) {
@@ -54,7 +51,6 @@ function formatDuration(durationMs) {
54
51
  if (durationMs < 1e3) return `${durationMs}ms`;
55
52
  return `${(durationMs / 1e3).toFixed(2)}s`;
56
53
  }
57
-
58
54
  //#endregion
59
55
  //#region src/utils/reactions.ts
60
56
  const REACTION_KEYS = [
@@ -94,7 +90,6 @@ function normalizeCount(value) {
94
90
  if (value <= 0) return 0;
95
91
  return Math.floor(value);
96
92
  }
97
-
98
93
  //#endregion
99
94
  //#region src/providers/helpers.ts
100
95
  async function collectPages(pages) {
@@ -105,7 +100,6 @@ async function collectPages(pages) {
105
100
  async function* iteratePages(pages) {
106
101
  for await (const page of pages) for (const item of page) yield item;
107
102
  }
108
-
109
103
  //#endregion
110
104
  //#region src/providers/github/client.ts
111
105
  const BaseOctokit = Octokit.plugin(retry, throttling);
@@ -127,7 +121,6 @@ function createGitHubClient(token) {
127
121
  }
128
122
  });
129
123
  }
130
-
131
124
  //#endregion
132
125
  //#region src/providers/github/provider.ts
133
126
  function createGitHubProvider(options) {
@@ -149,6 +142,7 @@ function createGitHubProvider(options) {
149
142
  fetchRepository: () => fetchRepository(octokit, owner, repo, bumpRequestCount),
150
143
  fetchRepositoryLabels: () => fetchRepositoryLabels(octokit, owner, repo, bumpRequestCount),
151
144
  fetchRepositoryMilestones: () => fetchRepositoryMilestones(octokit, owner, repo, bumpRequestCount),
145
+ countUpdatedSince: (since) => countUpdatedSince(octokit, owner, repo, since, bumpRequestCount),
152
146
  getRequestCount: () => requestCount,
153
147
  actionClose: (number) => actionClose(octokit, owner, repo, number, bumpRequestCount),
154
148
  actionReopen: (number) => actionReopen(octokit, owner, repo, number, bumpRequestCount),
@@ -278,6 +272,26 @@ async function fetchRepositoryMilestones(octokit, owner, repo, bumpRequestCount)
278
272
  per_page: 100
279
273
  });
280
274
  }
275
+ async function countUpdatedSince(octokit, owner, repo, since, bumpRequestCount) {
276
+ bumpRequestCount();
277
+ const sinceQuery = normalizeSinceForSearch(since);
278
+ const result = await octokit.graphql(`query CountsUpdated($issuesQuery: String!, $pullsQuery: String!) {
279
+ issues: search(query: $issuesQuery, type: ISSUE, first: 0) { issueCount }
280
+ pulls: search(query: $pullsQuery, type: ISSUE, first: 0) { issueCount }
281
+ }`, {
282
+ issuesQuery: `repo:${owner}/${repo} is:issue updated:>=${sinceQuery}`,
283
+ pullsQuery: `repo:${owner}/${repo} is:pr updated:>=${sinceQuery}`
284
+ });
285
+ return {
286
+ issues: result.issues.issueCount,
287
+ pulls: result.pulls.issueCount
288
+ };
289
+ }
290
+ function normalizeSinceForSearch(since) {
291
+ const date = new Date(since);
292
+ if (Number.isNaN(date.getTime())) return since;
293
+ return date.toISOString();
294
+ }
281
295
  async function actionClose(octokit, owner, repo, number, bumpRequestCount) {
282
296
  bumpRequestCount();
283
297
  await octokit.rest.issues.update({
@@ -499,6 +513,7 @@ function mapIssue(issue) {
499
513
  kind: issue.pull_request ? "pull" : "issue",
500
514
  ...issue.html_url ? { url: issue.html_url } : {},
501
515
  state: issue.state === "closed" ? "closed" : "open",
516
+ stateReason: normalizeStateReason(issue.state_reason),
502
517
  updatedAt: issue.updated_at,
503
518
  createdAt: issue.created_at,
504
519
  closedAt: issue.closed_at,
@@ -514,6 +529,10 @@ function mapIssue(issue) {
514
529
  reactions: mapReactions(issue.reactions)
515
530
  };
516
531
  }
532
+ function normalizeStateReason(reason) {
533
+ if (reason === "completed" || reason === "not_planned" || reason === "reopened") return reason;
534
+ return null;
535
+ }
517
536
  function mapComment(comment) {
518
537
  return {
519
538
  id: comment.id,
@@ -537,7 +556,6 @@ function mapReactions(reactions) {
537
556
  eyes: reactions?.eyes
538
557
  });
539
558
  }
540
-
541
559
  //#endregion
542
560
  //#region src/providers/factory.ts
543
561
  function createRepositoryProvider(options) {
@@ -548,6 +566,5 @@ function createRepositoryProvider(options) {
548
566
  repo
549
567
  });
550
568
  }
551
-
552
569
  //#endregion
553
- export { formatIssueNumber as a, formatDuration as i, normalizeReactions as n, formatTerminalLink as o, countNoun as r, formatValue as s, createRepositoryProvider as t };
570
+ export { formatIssueNumber as a, formatDuration as i, normalizeReactions as n, formatTerminalLink as o, countNoun as r, formatValue as s, createRepositoryProvider as t };
package/dist/index.d.mts CHANGED
@@ -1,198 +1,5 @@
1
- //#region src/types/config.d.ts
2
- interface GhfsUserConfig {
3
- /**
4
- * The repository to sync.
5
- *
6
- * Will try to detect the repository from the current working directory or the `package.json` file.
7
- */
8
- repo?: string;
9
- /**
10
- * The directory to store the synced issues and pull requests.
11
- *
12
- * @default '.ghfs'
13
- */
14
- directory?: string;
15
- /**
16
- * The authentication configuration.
17
- */
18
- auth?: {
19
- /**
20
- * The GitHub personal access token to use for authentication.
21
- *
22
- * When not provided, will try to get the token from `gh auth token` or the environment variables `GH_TOKEN` or `GITHUB_TOKEN`.
23
- */
24
- token?: string;
25
- };
26
- sync?: {
27
- /**
28
- * Whether to sync issues.
29
- *
30
- * @default true
31
- */
32
- issues?: boolean;
33
- /**
34
- * Whether to sync pull requests.
35
- *
36
- * @default true
37
- */
38
- pulls?: boolean;
39
- /**
40
- * When to sync closed issues and pull requests.
41
- *
42
- * - `true`: sync all closed issues and pull requests.
43
- * - `false`: don't sync any closed issues and pull requests. And delete any existing closed issues and pull requests from the local filesystem.
44
- *
45
- * @default false
46
- */
47
- closed?: boolean;
48
- /**
49
- * When to download the pull request patch files.
50
- *
51
- * - `'open'`: only download open pull request patch files.
52
- * - `'all'`: download all pull request patch files.
53
- * - `false`: don't download any pull request patch files.
54
- *
55
- * @default 'open'
56
- */
57
- patches?: 'open' | 'all' | false;
58
- };
59
- }
60
- type GhfsResolvedConfig = Required<GhfsUserConfig> & {
61
- cwd: string;
62
- auth: Required<GhfsUserConfig['auth']>;
63
- sync: Required<GhfsUserConfig['sync']>;
64
- };
65
- //#endregion
66
- //#region src/types/issue.d.ts
67
- type IssueKind = 'issue' | 'pull';
68
- type IssueState = 'open' | 'closed';
69
- //#endregion
70
- //#region src/types/provider.d.ts
71
- interface ProviderReactions {
72
- totalCount: number;
73
- plusOne: number;
74
- minusOne: number;
75
- laugh: number;
76
- hooray: number;
77
- confused: number;
78
- heart: number;
79
- rocket: number;
80
- eyes: number;
81
- }
82
- interface ProviderItem {
83
- number: number;
84
- kind: IssueKind;
85
- url?: string;
86
- state: IssueState;
87
- updatedAt: string;
88
- createdAt: string;
89
- closedAt: string | null;
90
- title: string;
91
- body: string | null;
92
- author: string | null;
93
- labels: string[];
94
- assignees: string[];
95
- milestone: string | null;
96
- reactions?: ProviderReactions;
97
- }
98
- interface ProviderComment {
99
- id: number;
100
- body: string | null;
101
- createdAt: string;
102
- updatedAt: string;
103
- author: string | null;
104
- reactions?: ProviderReactions;
105
- }
106
- interface ProviderPullMetadata {
107
- isDraft: boolean;
108
- merged: boolean;
109
- mergedAt: string | null;
110
- baseRef: string;
111
- headRef: string;
112
- requestedReviewers: string[];
113
- }
114
- interface ProviderRepository {
115
- name: string;
116
- full_name: string;
117
- description: string | null;
118
- private: boolean;
119
- archived: boolean;
120
- default_branch: string;
121
- html_url: string;
122
- fork: boolean;
123
- open_issues_count: number;
124
- has_issues: boolean;
125
- has_projects: boolean;
126
- has_wiki: boolean;
127
- created_at: string;
128
- updated_at: string;
129
- pushed_at: string | null;
130
- owner: {
131
- login: string;
132
- };
133
- }
134
- interface ProviderLabel {
135
- name: string;
136
- color: string;
137
- description: string | null;
138
- default: boolean;
139
- }
140
- interface ProviderMilestone {
141
- number: number;
142
- title: string;
143
- state: 'open' | 'closed';
144
- description: string | null;
145
- due_on: string | null;
146
- open_issues: number;
147
- closed_issues: number;
148
- created_at: string;
149
- updated_at: string;
150
- closed_at: string | null;
151
- }
152
- interface ProviderItemSnapshot {
153
- number: number;
154
- kind: IssueKind;
155
- updatedAt: string | null;
156
- }
157
- type ProviderLockReason = 'resolved' | 'off-topic' | 'too heated' | 'too-heated' | 'spam';
158
- interface PaginateItemsOptions {
159
- state: IssueState | 'all';
160
- since?: string;
161
- }
162
- interface RepositoryProvider {
163
- paginateItems: (options: PaginateItemsOptions) => AsyncIterable<ProviderItem[]>;
164
- fetchItems: (options: PaginateItemsOptions) => Promise<ProviderItem[]>;
165
- eachItem: (options: PaginateItemsOptions) => AsyncIterable<ProviderItem>;
166
- fetchItemsByNumbers: (numbers: number[]) => Promise<ProviderItem[]>;
167
- fetchComments: (number: number) => Promise<ProviderComment[]>;
168
- fetchPullMetadata: (number: number) => Promise<ProviderPullMetadata>;
169
- fetchPullPatch: (number: number) => Promise<string>;
170
- fetchItemSnapshot: (number: number) => Promise<ProviderItemSnapshot>;
171
- fetchRepository: () => Promise<ProviderRepository>;
172
- fetchRepositoryLabels: () => Promise<ProviderLabel[]>;
173
- fetchRepositoryMilestones: () => Promise<ProviderMilestone[]>;
174
- getRequestCount: () => number;
175
- actionClose: (number: number) => Promise<void>;
176
- actionReopen: (number: number) => Promise<void>;
177
- actionSetTitle: (number: number, title: string) => Promise<void>;
178
- actionSetBody: (number: number, body: string) => Promise<void>;
179
- actionAddComment: (number: number, body: string) => Promise<void>;
180
- actionAddLabels: (number: number, labels: string[]) => Promise<void>;
181
- actionRemoveLabels: (number: number, labels: string[]) => Promise<void>;
182
- actionSetLabels: (number: number, labels: string[]) => Promise<void>;
183
- actionAddAssignees: (number: number, assignees: string[]) => Promise<void>;
184
- actionRemoveAssignees: (number: number, assignees: string[]) => Promise<void>;
185
- actionSetAssignees: (number: number, assignees: string[]) => Promise<void>;
186
- actionSetMilestone: (number: number, milestone: string | number) => Promise<void>;
187
- actionClearMilestone: (number: number) => Promise<void>;
188
- actionLock: (number: number, reason?: ProviderLockReason) => Promise<void>;
189
- actionUnlock: (number: number) => Promise<void>;
190
- actionRequestReviewers: (number: number, reviewers: string[]) => Promise<void>;
191
- actionRemoveReviewers: (number: number, reviewers: string[]) => Promise<void>;
192
- actionMarkReadyForReview: (number: number) => Promise<void>;
193
- actionConvertToDraft: (number: number) => Promise<void>;
194
- }
195
- //#endregion
1
+ import { a as ProviderLockReason, c as IssueKind, d as GhfsUserConfig, i as ProviderItemSnapshot, l as IssueState, n as ProviderComment, o as ProviderPullMetadata, r as ProviderItem, s as RepositoryProvider, t as PaginateItemsOptions, u as GhfsResolvedConfig } from "./provider-BFJGpjCs.mjs";
2
+
196
3
  //#region src/providers/factory.d.ts
197
4
  interface CreateRepositoryProviderOptions {
198
5
  token: string;
package/dist/index.mjs CHANGED
@@ -1,9 +1,7 @@
1
- import { t as createRepositoryProvider } from "./factory-COZFMWsb.mjs";
2
-
1
+ import { t as createRepositoryProvider } from "./factory-DypZ8oi9.mjs";
3
2
  //#region src/index.ts
4
3
  function defineConfig(config) {
5
4
  return config;
6
5
  }
7
-
8
6
  //#endregion
9
- export { createRepositoryProvider, defineConfig };
7
+ export { createRepositoryProvider, defineConfig };
@@ -0,0 +1,203 @@
1
+ //#region src/types/config.d.ts
2
+ interface GhfsUserConfig {
3
+ /**
4
+ * The repository to sync.
5
+ *
6
+ * Will try to detect the repository from the current working directory or the `package.json` file.
7
+ */
8
+ repo?: string;
9
+ /**
10
+ * The directory to store the synced issues and pull requests.
11
+ *
12
+ * @default '.ghfs'
13
+ */
14
+ directory?: string;
15
+ /**
16
+ * The authentication configuration.
17
+ */
18
+ auth?: {
19
+ /**
20
+ * The GitHub personal access token to use for authentication.
21
+ *
22
+ * When not provided, will try to get the token from `gh auth token` or the environment variables `GH_TOKEN` or `GITHUB_TOKEN`.
23
+ */
24
+ token?: string;
25
+ };
26
+ sync?: {
27
+ /**
28
+ * Whether to sync issues.
29
+ *
30
+ * @default true
31
+ */
32
+ issues?: boolean;
33
+ /**
34
+ * Whether to sync pull requests.
35
+ *
36
+ * @default true
37
+ */
38
+ pulls?: boolean;
39
+ /**
40
+ * When to sync closed issues and pull requests.
41
+ *
42
+ * - `true`: sync all closed issues and pull requests.
43
+ * - `false`: don't sync any closed issues and pull requests. And delete any existing closed issues and pull requests from the local filesystem.
44
+ *
45
+ * @default false
46
+ */
47
+ closed?: boolean;
48
+ /**
49
+ * When to download the pull request patch files.
50
+ *
51
+ * - `'open'`: only download open pull request patch files.
52
+ * - `'all'`: download all pull request patch files.
53
+ * - `false`: don't download any pull request patch files.
54
+ *
55
+ * @default 'open'
56
+ */
57
+ patches?: 'open' | 'all' | false;
58
+ };
59
+ }
60
+ type GhfsResolvedConfig = Required<GhfsUserConfig> & {
61
+ cwd: string;
62
+ auth: Required<GhfsUserConfig['auth']>;
63
+ sync: Required<GhfsUserConfig['sync']>;
64
+ };
65
+ //#endregion
66
+ //#region src/types/issue.d.ts
67
+ type IssueKind = 'issue' | 'pull';
68
+ type IssueState = 'open' | 'closed';
69
+ //#endregion
70
+ //#region src/types/provider.d.ts
71
+ interface ProviderReactions {
72
+ totalCount: number;
73
+ plusOne: number;
74
+ minusOne: number;
75
+ laugh: number;
76
+ hooray: number;
77
+ confused: number;
78
+ heart: number;
79
+ rocket: number;
80
+ eyes: number;
81
+ }
82
+ type IssueStateReason = 'completed' | 'not_planned' | 'reopened';
83
+ interface ProviderItem {
84
+ number: number;
85
+ kind: IssueKind;
86
+ url?: string;
87
+ state: IssueState;
88
+ stateReason?: IssueStateReason | null;
89
+ updatedAt: string;
90
+ createdAt: string;
91
+ closedAt: string | null;
92
+ title: string;
93
+ body: string | null;
94
+ author: string | null;
95
+ labels: string[];
96
+ assignees: string[];
97
+ milestone: string | null;
98
+ reactions?: ProviderReactions;
99
+ }
100
+ interface ProviderComment {
101
+ id: number;
102
+ body: string | null;
103
+ createdAt: string;
104
+ updatedAt: string;
105
+ author: string | null;
106
+ reactions?: ProviderReactions;
107
+ }
108
+ interface ProviderPullMetadata {
109
+ isDraft: boolean;
110
+ merged: boolean;
111
+ mergedAt: string | null;
112
+ baseRef: string;
113
+ headRef: string;
114
+ requestedReviewers: string[];
115
+ }
116
+ interface ProviderRepository {
117
+ name: string;
118
+ full_name: string;
119
+ description: string | null;
120
+ private: boolean;
121
+ archived: boolean;
122
+ default_branch: string;
123
+ html_url: string;
124
+ fork: boolean;
125
+ open_issues_count: number;
126
+ has_issues: boolean;
127
+ has_projects: boolean;
128
+ has_wiki: boolean;
129
+ created_at: string;
130
+ updated_at: string;
131
+ pushed_at: string | null;
132
+ owner: {
133
+ login: string;
134
+ };
135
+ }
136
+ interface ProviderLabel {
137
+ name: string;
138
+ color: string;
139
+ description: string | null;
140
+ default: boolean;
141
+ }
142
+ interface ProviderMilestone {
143
+ number: number;
144
+ title: string;
145
+ state: 'open' | 'closed';
146
+ description: string | null;
147
+ due_on: string | null;
148
+ open_issues: number;
149
+ closed_issues: number;
150
+ created_at: string;
151
+ updated_at: string;
152
+ closed_at: string | null;
153
+ }
154
+ interface ProviderItemSnapshot {
155
+ number: number;
156
+ kind: IssueKind;
157
+ updatedAt: string | null;
158
+ }
159
+ interface ProviderUpdateCounts {
160
+ issues: number;
161
+ pulls: number;
162
+ }
163
+ type ProviderLockReason = 'resolved' | 'off-topic' | 'too heated' | 'too-heated' | 'spam';
164
+ interface PaginateItemsOptions {
165
+ state: IssueState | 'all';
166
+ since?: string;
167
+ }
168
+ interface RepositoryProvider {
169
+ paginateItems: (options: PaginateItemsOptions) => AsyncIterable<ProviderItem[]>;
170
+ fetchItems: (options: PaginateItemsOptions) => Promise<ProviderItem[]>;
171
+ eachItem: (options: PaginateItemsOptions) => AsyncIterable<ProviderItem>;
172
+ fetchItemsByNumbers: (numbers: number[]) => Promise<ProviderItem[]>;
173
+ fetchComments: (number: number) => Promise<ProviderComment[]>;
174
+ fetchPullMetadata: (number: number) => Promise<ProviderPullMetadata>;
175
+ fetchPullPatch: (number: number) => Promise<string>;
176
+ fetchItemSnapshot: (number: number) => Promise<ProviderItemSnapshot>;
177
+ fetchRepository: () => Promise<ProviderRepository>;
178
+ fetchRepositoryLabels: () => Promise<ProviderLabel[]>;
179
+ fetchRepositoryMilestones: () => Promise<ProviderMilestone[]>;
180
+ countUpdatedSince: (since: string) => Promise<ProviderUpdateCounts>;
181
+ getRequestCount: () => number;
182
+ actionClose: (number: number) => Promise<void>;
183
+ actionReopen: (number: number) => Promise<void>;
184
+ actionSetTitle: (number: number, title: string) => Promise<void>;
185
+ actionSetBody: (number: number, body: string) => Promise<void>;
186
+ actionAddComment: (number: number, body: string) => Promise<void>;
187
+ actionAddLabels: (number: number, labels: string[]) => Promise<void>;
188
+ actionRemoveLabels: (number: number, labels: string[]) => Promise<void>;
189
+ actionSetLabels: (number: number, labels: string[]) => Promise<void>;
190
+ actionAddAssignees: (number: number, assignees: string[]) => Promise<void>;
191
+ actionRemoveAssignees: (number: number, assignees: string[]) => Promise<void>;
192
+ actionSetAssignees: (number: number, assignees: string[]) => Promise<void>;
193
+ actionSetMilestone: (number: number, milestone: string | number) => Promise<void>;
194
+ actionClearMilestone: (number: number) => Promise<void>;
195
+ actionLock: (number: number, reason?: ProviderLockReason) => Promise<void>;
196
+ actionUnlock: (number: number) => Promise<void>;
197
+ actionRequestReviewers: (number: number, reviewers: string[]) => Promise<void>;
198
+ actionRemoveReviewers: (number: number, reviewers: string[]) => Promise<void>;
199
+ actionMarkReadyForReview: (number: number) => Promise<void>;
200
+ actionConvertToDraft: (number: number) => Promise<void>;
201
+ }
202
+ //#endregion
203
+ export { ProviderLockReason as a, IssueKind as c, GhfsUserConfig as d, ProviderItemSnapshot as i, IssueState as l, ProviderComment as n, ProviderPullMetadata as o, ProviderItem as r, RepositoryProvider as s, PaginateItemsOptions as t, GhfsResolvedConfig as u };