@kud/gh 0.2.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.
@@ -0,0 +1,18 @@
1
+ /** A repo-scoped or account-wide inbox. */
2
+ export type InboxQueryOptions = {
3
+ /** `owner/name`. Scopes every search to one repository. */
4
+ repo?: string;
5
+ /** How far back `recentlyDone` looks. Defaults to 14 days. */
6
+ doneWithinDays?: number;
7
+ };
8
+ /**
9
+ * Build the inbox query. Without `repo`, it is account-wide.
10
+ *
11
+ * The two qualifiers do NOT compose. `user:@me` means "in repos I own", and
12
+ * GitHub ANDs search qualifiers — so `user:@me repo:someone-else/x` matches
13
+ * nothing, and a scoped inbox on a repo you contribute to but do not own would
14
+ * render empty and read as "nothing to do here". So `repo:` REPLACES
15
+ * `user:@me` rather than joining it.
16
+ */
17
+ export declare const buildInboxQuery: ({ repo, doneWithinDays, }?: InboxQueryOptions) => string;
18
+ //# sourceMappingURL=inbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.d.ts","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"AAQA,2CAA2C;AAC3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAmDD;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,GAAI,4BAG7B,iBAAsB,WAoFxB,CAAA"}
package/dist/inbox.js ADDED
@@ -0,0 +1,144 @@
1
+ // The inbox query — one GraphQL round-trip for "what is on my plate": my PRs,
2
+ // review requests, reviews I have given, assigned work, issues and PRs on my
3
+ // repos, and what I closed recently.
4
+ //
5
+ // Query-only by design. Assembling the result into sections is the surface's
6
+ // own vocabulary — cockpit splits home from work, a web dashboard may group by
7
+ // project — so nothing here decides what a section is.
8
+ // computeHealth's precedence needs reviewDecision, mergeable and the check
9
+ // rollup. A fragment that omits them does NOT degrade gracefully — it falls
10
+ // straight through to whatever token is left, so a PR you already sent back
11
+ // renders as "awaiting review" and a failing one renders as quiet. Every PR
12
+ // fragment therefore carries the whole set; none of it is optional.
13
+ const PR_HEALTH = `
14
+ isDraft reviewDecision mergeable
15
+ statusCheckRollup { contexts(first: 20) { nodes {
16
+ ... on CheckRun { name conclusion status }
17
+ ... on StatusContext { context state }
18
+ } } }`;
19
+ // Whose turn it is cannot be read off a count, so every comment-bearing edge
20
+ // carries its latest author and timestamp: the conversation, the review bodies,
21
+ // and each thread's last reply. The last commit rides along so a consumer can
22
+ // say whether the author has pushed since being sent back.
23
+ //
24
+ // `__typename` distinguishes a Bot from a User, which a login cannot: GraphQL
25
+ // reports app authors bare (`greptile-apps`), without the `[bot]` suffix REST
26
+ // adds, so there is nothing in the name to match on. A consumer needs it to
27
+ // decide whether a push answers what was said — it does when a machine said it,
28
+ // and does not when a person did. Note it catches GitHub Apps only; a machine
29
+ // ACCOUNT like `raycastbot` is a User and reads as human here.
30
+ const PR_CONVERSATION = `
31
+ comments(last: 1) { totalCount nodes { author { __typename login } createdAt } }
32
+ reviews(last: 1) { nodes { author { __typename login } state submittedAt } }
33
+ reviewThreads(first: 50) { nodes {
34
+ isResolved
35
+ comments(last: 1) { totalCount nodes { author { __typename login } createdAt } }
36
+ } }
37
+ commits(last: 1) { nodes { commit { committedDate } } }`;
38
+ const ISSUE_CONVERSATION = `
39
+ comments(last: 1) { totalCount nodes { author { __typename login } createdAt } }`;
40
+ // Fetched so a consumer can tell a `plan` issue from any other — which decides
41
+ // what a delegated session gets handed. Nothing here renders labels.
42
+ const ISSUE_LABELS = `
43
+ labels(first: 10) { nodes { name } }`;
44
+ /*
45
+ * Computed per call, never at module scope. A CLI process is short-lived and
46
+ * would not notice, but a long-running server imports this once and keeps it
47
+ * for days — a module-level date would freeze "recently done" to the morning
48
+ * the server booted and quietly stop reporting anything closed since.
49
+ */
50
+ const sinceDay = (days) => new Date(Date.now() - days * 86400 * 1000).toISOString().slice(0, 10);
51
+ /**
52
+ * Build the inbox query. Without `repo`, it is account-wide.
53
+ *
54
+ * The two qualifiers do NOT compose. `user:@me` means "in repos I own", and
55
+ * GitHub ANDs search qualifiers — so `user:@me repo:someone-else/x` matches
56
+ * nothing, and a scoped inbox on a repo you contribute to but do not own would
57
+ * render empty and read as "nothing to do here". So `repo:` REPLACES
58
+ * `user:@me` rather than joining it.
59
+ */
60
+ export const buildInboxQuery = ({ repo, doneWithinDays = 14, } = {}) => {
61
+ const scope = repo ? `repo:${repo} ` : "";
62
+ const owned = repo ? "" : "user:@me ";
63
+ const doneSince = sinceDay(doneWithinDays);
64
+ return `
65
+ {
66
+ viewer { login }
67
+ myPRs: search(query: "${scope}is:pr is:open author:@me", type: ISSUE, first: 100) {
68
+ nodes { __typename ... on PullRequest {
69
+ number title createdAt url headRefName
70
+ repository { nameWithOwner }
71
+ ${PR_HEALTH}
72
+ ${PR_CONVERSATION}
73
+ }}
74
+ }
75
+ reviewRequests: search(query: "${scope}is:pr is:open review-requested:@me", type: ISSUE, first: 20) {
76
+ nodes { __typename ... on PullRequest {
77
+ number title createdAt url headRefName
78
+ repository { nameWithOwner }
79
+ author { login }
80
+ ${PR_HEALTH}
81
+ ${PR_CONVERSATION}
82
+ }}
83
+ }
84
+ reviewed: search(query: "${scope}is:pr is:open reviewed-by:@me -author:@me -review-requested:@me", type: ISSUE, first: 20) {
85
+ nodes { __typename ... on PullRequest {
86
+ number title createdAt url headRefName
87
+ repository { nameWithOwner }
88
+ author { login }
89
+ ${PR_HEALTH}
90
+ ${PR_CONVERSATION}
91
+ }}
92
+ }
93
+ assigned: search(query: "${scope}is:open assignee:@me", type: ISSUE, first: 30) {
94
+ nodes {
95
+ __typename
96
+ ... on Issue {
97
+ number title createdAt url repository { nameWithOwner } author { login }
98
+ ${ISSUE_CONVERSATION}
99
+ ${ISSUE_LABELS}
100
+ }
101
+ ... on PullRequest {
102
+ number title createdAt url headRefName repository { nameWithOwner } author { login }
103
+ ${PR_HEALTH}
104
+ ${PR_CONVERSATION}
105
+ }
106
+ }
107
+ }
108
+ repoIssues: search(query: "${scope}${owned}is:issue is:open archived:false", type: ISSUE, first: 30) {
109
+ nodes { __typename ... on Issue {
110
+ number title createdAt url
111
+ repository { nameWithOwner }
112
+ author { login }
113
+ ${ISSUE_CONVERSATION}
114
+ ${ISSUE_LABELS}
115
+ }}
116
+ }
117
+ authoredIssues: search(query: "${scope}is:issue is:open author:@me archived:false", type: ISSUE, first: 30) {
118
+ nodes { ... on Issue {
119
+ number title createdAt url
120
+ repository { nameWithOwner }
121
+ author { login }
122
+ ${ISSUE_CONVERSATION}
123
+ ${ISSUE_LABELS}
124
+ }}
125
+ }
126
+ repoPRs: search(query: "${scope}${owned}is:pr is:open -author:@me archived:false", type: ISSUE, first: 30) {
127
+ nodes { __typename ... on PullRequest {
128
+ number title createdAt url headRefName
129
+ repository { nameWithOwner }
130
+ author { login }
131
+ ${PR_HEALTH}
132
+ ${PR_CONVERSATION}
133
+ }}
134
+ }
135
+ recentlyDone: search(query: "${scope}is:pr author:@me -is:open closed:>=${doneSince}", type: ISSUE, first: 30) {
136
+ nodes { __typename ... on PullRequest {
137
+ number title state isDraft createdAt mergedAt closedAt url
138
+ repository { nameWithOwner }
139
+ }}
140
+ }
141
+ }
142
+ `;
143
+ };
144
+ //# sourceMappingURL=inbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,6EAA6E;AAC7E,qCAAqC;AACrC,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,uDAAuD;AAUvD,2EAA2E;AAC3E,4EAA4E;AAC5E,4EAA4E;AAC5E,4EAA4E;AAC5E,oEAAoE;AACpE,MAAM,SAAS,GAAG;;;;;YAKN,CAAA;AAEZ,6EAA6E;AAC7E,gFAAgF;AAChF,8EAA8E;AAC9E,2DAA2D;AAC3D,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,gFAAgF;AAChF,8EAA8E;AAC9E,+DAA+D;AAC/D,MAAM,eAAe,GAAG;;;;;;;8DAOsC,CAAA;AAE9D,MAAM,kBAAkB,GAAG;uFAC4D,CAAA;AAEvF,+EAA+E;AAC/E,qEAAqE;AACrE,MAAM,YAAY,GAAG;2CACsB,CAAA;AAE3C;;;;;GAKG;AACH,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,EAAE,CAChC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;AAEvE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,EAC9B,IAAI,EACJ,cAAc,GAAG,EAAE,MACE,EAAE,EAAE,EAAE;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAA;IACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;IAE1C,OAAO;;;0BAGiB,KAAK;;;;QAIvB,SAAS;QACT,eAAe;;;mCAGY,KAAK;;;;;QAKhC,SAAS;QACT,eAAe;;;6BAGM,KAAK;;;;;QAK1B,SAAS;QACT,eAAe;;;6BAGM,KAAK;;;;;UAKxB,kBAAkB;UAClB,YAAY;;;;UAIZ,SAAS;UACT,eAAe;;;;+BAIM,KAAK,GAAG,KAAK;;;;;QAKpC,kBAAkB;QAClB,YAAY;;;mCAGe,KAAK;;;;;QAKhC,kBAAkB;QAClB,YAAY;;;4BAGQ,KAAK,GAAG,KAAK;;;;;QAKjC,SAAS;QACT,eAAe;;;iCAGU,KAAK,sCAAsC,SAAS;;;;;;;CAOpF,CAAA;AACD,CAAC,CAAA"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./gh.js";
2
+ export * from "./inbox.js";
2
3
  export * from "./pr.js";
3
4
  export * from "./pr-comments.js";
4
5
  export * from "./health.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAaA,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA"}
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@
12
12
  // The deciding test is "is there a query to optimise?": yes → gh api; no →
13
13
  // porcelain.
14
14
  export * from "./gh.js";
15
+ export * from "./inbox.js";
15
16
  export * from "./pr.js";
16
17
  export * from "./pr-comments.js";
17
18
  export * from "./health.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iFAAiF;AACjF,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,gFAAgF;AAChF,iFAAiF;AACjF,mFAAmF;AACnF,2EAA2E;AAC3E,aAAa;AACb,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,iFAAiF;AACjF,2EAA2E;AAC3E,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,gFAAgF;AAChF,iFAAiF;AACjF,mFAAmF;AACnF,2EAA2E;AAC3E,aAAa;AACb,cAAc,SAAS,CAAA;AACvB,cAAc,YAAY,CAAA;AAC1B,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Surface-agnostic GitHub core — gh CLI primitives, PR review comments, health, and webhook logic.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",