ticketlens 0.1.8 → 0.1.10
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/package.json
CHANGED
|
@@ -8,12 +8,12 @@ const ISSUE_FIELDS = `
|
|
|
8
8
|
description
|
|
9
9
|
state { name }
|
|
10
10
|
priority
|
|
11
|
-
assignee { name
|
|
12
|
-
creator { name
|
|
11
|
+
assignee { name email }
|
|
12
|
+
creator { name email }
|
|
13
13
|
createdAt
|
|
14
14
|
updatedAt
|
|
15
15
|
labels { nodes { name } }
|
|
16
|
-
comments { nodes { body createdAt user { name
|
|
16
|
+
comments { nodes { body createdAt user { name email } } }
|
|
17
17
|
`;
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -26,15 +26,15 @@ export function normalizeLinearIssue(raw) {
|
|
|
26
26
|
type: 'Issue',
|
|
27
27
|
status: raw.state?.name ?? null,
|
|
28
28
|
priority: PRIORITY_LABELS[raw.priority] ?? null,
|
|
29
|
-
assignee: raw.assignee?.
|
|
30
|
-
reporter: raw.creator?.
|
|
29
|
+
assignee: raw.assignee?.name ?? null,
|
|
30
|
+
reporter: raw.creator?.name ?? null,
|
|
31
31
|
description: raw.description ?? null,
|
|
32
32
|
created: raw.createdAt ?? null,
|
|
33
33
|
updated: raw.updatedAt ?? null,
|
|
34
34
|
labels: (raw.labels?.nodes ?? []).map(l => l.name),
|
|
35
35
|
components: [],
|
|
36
36
|
comments: (raw.comments?.nodes ?? []).map(c => ({
|
|
37
|
-
author: c.user?.
|
|
37
|
+
author: c.user?.name ?? null,
|
|
38
38
|
authorAccountId: null,
|
|
39
39
|
authorName: c.user?.name ?? null,
|
|
40
40
|
body: c.body ?? '',
|
|
@@ -51,12 +51,14 @@ async function gql(query, variables, { token, fetcher, signal }) {
|
|
|
51
51
|
headers: {
|
|
52
52
|
Authorization: `Bearer ${token}`,
|
|
53
53
|
'Content-Type': 'application/json',
|
|
54
|
+
Accept: 'application/json',
|
|
54
55
|
},
|
|
55
|
-
body: JSON.stringify({ query, variables }),
|
|
56
|
+
body: JSON.stringify(Object.keys(variables).length ? { query, variables } : { query }),
|
|
56
57
|
signal,
|
|
57
58
|
});
|
|
58
59
|
if (!res.ok) {
|
|
59
|
-
|
|
60
|
+
const detail = await res.text().catch(() => '');
|
|
61
|
+
throw new Error(`Linear API error ${res.status} (${res.statusText})${detail ? ': ' + detail.slice(0, 300) : ''}`);
|
|
60
62
|
}
|
|
61
63
|
const { data, errors } = await res.json();
|
|
62
64
|
if (errors?.length) throw new Error(`Linear GraphQL error: ${errors[0].message}`);
|
|
@@ -76,7 +78,7 @@ export function createLinearAdapter(conn, { fetcher = globalThis.fetch } = {}) {
|
|
|
76
78
|
async fetchTicket(key, opts = {}) {
|
|
77
79
|
const signal = AbortSignal.timeout(opts.timeoutMs ?? 10_000);
|
|
78
80
|
const data = await gql(
|
|
79
|
-
`query
|
|
81
|
+
`query ($id: String!) {
|
|
80
82
|
issues(filter: { identifier: { eq: $id } }, first: 1) {
|
|
81
83
|
nodes { ${ISSUE_FIELDS} }
|
|
82
84
|
}
|
|
@@ -92,18 +94,18 @@ export function createLinearAdapter(conn, { fetcher = globalThis.fetch } = {}) {
|
|
|
92
94
|
async fetchCurrentUser(opts = {}) {
|
|
93
95
|
const signal = AbortSignal.timeout(opts.timeoutMs ?? 10_000);
|
|
94
96
|
const data = await gql(
|
|
95
|
-
`
|
|
97
|
+
`{ viewer { name email } }`,
|
|
96
98
|
{},
|
|
97
99
|
{ token, fetcher, signal },
|
|
98
100
|
);
|
|
99
101
|
const v = data.viewer;
|
|
100
|
-
return { displayName: v.
|
|
102
|
+
return { displayName: v.name, email: v.email ?? null };
|
|
101
103
|
},
|
|
102
104
|
|
|
103
105
|
async searchTickets(_query, opts = {}) {
|
|
104
106
|
const signal = AbortSignal.timeout(opts.timeoutMs ?? 10_000);
|
|
105
107
|
const data = await gql(
|
|
106
|
-
`
|
|
108
|
+
`{
|
|
107
109
|
viewer {
|
|
108
110
|
assignedIssues(
|
|
109
111
|
filter: { state: { type: { nin: ["completed", "cancelled"] } } }
|
|
@@ -122,7 +124,7 @@ export function createLinearAdapter(conn, { fetcher = globalThis.fetch } = {}) {
|
|
|
122
124
|
async fetchStatuses(opts = {}) {
|
|
123
125
|
const signal = AbortSignal.timeout(opts.timeoutMs ?? 10_000);
|
|
124
126
|
const data = await gql(
|
|
125
|
-
`
|
|
127
|
+
`{ workflowStates(first: 50) { nodes { name } } }`,
|
|
126
128
|
{},
|
|
127
129
|
{ token, fetcher, signal },
|
|
128
130
|
);
|
|
@@ -40,9 +40,14 @@ export function createSession(conn, { stream = process.stderr } = {}) {
|
|
|
40
40
|
const profileLabel = conn.profileName || 'default';
|
|
41
41
|
const userLabel = conn.email || (conn.pat ? 'token auth' : 'unknown');
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
:
|
|
43
|
+
const trackerName = hostname.includes('linear.app') ? 'Linear'
|
|
44
|
+
: hostname.includes('github.com') ? 'GitHub'
|
|
45
|
+
: 'Jira';
|
|
46
|
+
const jiraLabel = (trackerName !== 'Jira')
|
|
47
|
+
? trackerName
|
|
48
|
+
: conn.profileName
|
|
49
|
+
? conn.profileName.charAt(0).toUpperCase() + conn.profileName.slice(1) + ' Jira'
|
|
50
|
+
: hostname;
|
|
46
51
|
|
|
47
52
|
// Pre-build the info lines to calculate box width including status line.
|
|
48
53
|
const infoLines = [
|