@enrichlayer/el-linear 1.7.0 → 1.10.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 +82 -1
- package/claude-skills/linear-operations/SKILL.md +55 -0
- package/dist/auth/oauth-callback.js +14 -7
- package/dist/auth/oauth-fs.d.ts +22 -0
- package/dist/auth/oauth-fs.js +77 -6
- package/dist/auth/oauth-headless.d.ts +13 -8
- package/dist/auth/oauth-headless.js +18 -11
- package/dist/auth/oauth-storage.d.ts +11 -3
- package/dist/auth/oauth-storage.js +15 -8
- package/dist/auth/token-resolver.d.ts +9 -0
- package/dist/auth/token-resolver.js +57 -37
- package/dist/commands/attachments.js +2 -1
- package/dist/commands/comments.js +17 -28
- package/dist/commands/cycles.js +2 -1
- package/dist/commands/documents.js +2 -1
- package/dist/commands/graphql.js +4 -6
- package/dist/commands/init/index.js +2 -0
- package/dist/commands/init/oauth.d.ts +6 -0
- package/dist/commands/init/oauth.js +8 -2
- package/dist/commands/init/token.d.ts +0 -8
- package/dist/commands/init/token.js +13 -1
- package/dist/commands/issue-id.js +1 -3
- package/dist/commands/issues/branch.d.ts +17 -0
- package/dist/commands/issues/branch.js +40 -0
- package/dist/commands/issues/description.d.ts +89 -0
- package/dist/commands/issues/description.js +183 -0
- package/dist/commands/issues/link-references.d.ts +21 -0
- package/dist/commands/issues/link-references.js +171 -0
- package/dist/commands/issues/relations.d.ts +55 -0
- package/dist/commands/issues/relations.js +132 -0
- package/dist/commands/issues.js +97 -497
- package/dist/commands/labels.js +20 -28
- package/dist/commands/profile/migrate-legacy.js +10 -33
- package/dist/commands/profile.js +1 -10
- package/dist/commands/project-milestones.js +13 -20
- package/dist/commands/projects.d.ts +5 -1
- package/dist/commands/projects.js +202 -102
- package/dist/commands/read-shortcut.d.ts +6 -0
- package/dist/commands/read-shortcut.js +6 -1
- package/dist/commands/refs.js +10 -1
- package/dist/commands/releases.js +26 -30
- package/dist/commands/search.js +21 -30
- package/dist/commands/teams.js +2 -1
- package/dist/commands/templates.js +128 -7
- package/dist/commands/users.js +3 -1
- package/dist/config/config.js +31 -9
- package/dist/config/issue-validation.js +1 -1
- package/dist/config/paths.d.ts +11 -0
- package/dist/config/paths.js +44 -6
- package/dist/config/resolver.js +2 -3
- package/dist/config/term-enforcer.js +1 -1
- package/dist/main.js +37 -2
- package/dist/queries/attachments-types.d.ts +30 -0
- package/dist/queries/attachments-types.js +5 -0
- package/dist/queries/comments-types.d.ts +49 -0
- package/dist/queries/comments-types.js +5 -0
- package/dist/queries/documents-types.d.ts +61 -0
- package/dist/queries/documents-types.js +9 -0
- package/dist/queries/introspect-types.d.ts +57 -0
- package/dist/queries/introspect-types.js +10 -0
- package/dist/queries/issues-types.d.ts +416 -0
- package/dist/queries/issues-types.js +23 -0
- package/dist/queries/issues.d.ts +2 -0
- package/dist/queries/issues.js +22 -0
- package/dist/queries/labels-types.d.ts +64 -0
- package/dist/queries/labels-types.js +5 -0
- package/dist/queries/project-milestones-types.d.ts +91 -0
- package/dist/queries/project-milestones-types.js +10 -0
- package/dist/queries/projects-types.d.ts +75 -0
- package/dist/queries/projects-types.js +5 -0
- package/dist/queries/projects.d.ts +2 -0
- package/dist/queries/projects.js +22 -0
- package/dist/queries/releases-types.d.ts +84 -0
- package/dist/queries/releases-types.js +5 -0
- package/dist/queries/search-types.d.ts +86 -0
- package/dist/queries/search-types.js +6 -0
- package/dist/queries/templates-types.d.ts +61 -0
- package/dist/queries/templates-types.js +9 -0
- package/dist/queries/templates.d.ts +3 -0
- package/dist/queries/templates.js +43 -0
- package/dist/types/linear.d.ts +8 -2
- package/dist/utils/auth.js +7 -9
- package/dist/utils/auto-link-references.js +44 -25
- package/dist/utils/disk-cache.js +2 -1
- package/dist/utils/formatters/summary.d.ts +62 -0
- package/dist/utils/formatters/summary.js +755 -0
- package/dist/utils/graphql-attachments-service.js +6 -9
- package/dist/utils/graphql-documents-service.js +19 -25
- package/dist/utils/graphql-issues-service.d.ts +118 -5
- package/dist/utils/graphql-issues-service.js +202 -209
- package/dist/utils/issue-reference-extractor.d.ts +9 -1
- package/dist/utils/issue-reference-extractor.js +16 -9
- package/dist/utils/issue-reference-wrapper.js +1 -54
- package/dist/utils/linear-service.d.ts +7 -3
- package/dist/utils/linear-service.js +27 -5
- package/dist/utils/markdown-prosemirror.js +17 -1
- package/dist/utils/mention-resolver.js +17 -5
- package/dist/utils/output.d.ts +7 -1
- package/dist/utils/output.js +38 -1
- package/dist/utils/protected-ranges.d.ts +33 -0
- package/dist/utils/protected-ranges.js +73 -0
- package/dist/utils/table-formatter.d.ts +36 -0
- package/dist/utils/table-formatter.js +46 -24
- package/dist/utils/validators.d.ts +9 -1
- package/dist/utils/validators.js +10 -0
- package/dist/utils/workspace-url.d.ts +5 -1
- package/dist/utils/workspace-url.js +35 -5
- package/package.json +1 -1
|
@@ -4,9 +4,9 @@ function transformAttachment(att) {
|
|
|
4
4
|
return {
|
|
5
5
|
id: att.id,
|
|
6
6
|
url: att.url,
|
|
7
|
-
title: att.title
|
|
8
|
-
createdAt: att.createdAt
|
|
9
|
-
updatedAt: att.updatedAt
|
|
7
|
+
title: att.title ?? undefined,
|
|
8
|
+
createdAt: att.createdAt ?? undefined,
|
|
9
|
+
updatedAt: att.updatedAt ?? undefined,
|
|
10
10
|
};
|
|
11
11
|
}
|
|
12
12
|
class GraphQLAttachmentsService {
|
|
@@ -17,15 +17,14 @@ class GraphQLAttachmentsService {
|
|
|
17
17
|
async createAttachment(input) {
|
|
18
18
|
const result = await this.graphqlService.rawRequest(CREATE_ATTACHMENT_MUTATION, { input });
|
|
19
19
|
const attachmentCreate = result.attachmentCreate;
|
|
20
|
-
if (!attachmentCreate.success) {
|
|
20
|
+
if (!attachmentCreate.success || !attachmentCreate.attachment) {
|
|
21
21
|
throw new Error(`Failed to create attachment on issue ${input.issueId} for URL "${input.url}"`);
|
|
22
22
|
}
|
|
23
23
|
return transformAttachment(attachmentCreate.attachment);
|
|
24
24
|
}
|
|
25
25
|
async deleteAttachment(id) {
|
|
26
26
|
const result = await this.graphqlService.rawRequest(DELETE_ATTACHMENT_MUTATION, { id });
|
|
27
|
-
|
|
28
|
-
if (!attachmentDelete.success) {
|
|
27
|
+
if (!result.attachmentDelete.success) {
|
|
29
28
|
throw new Error(`Failed to delete attachment: ${id}`);
|
|
30
29
|
}
|
|
31
30
|
return true;
|
|
@@ -35,9 +34,7 @@ class GraphQLAttachmentsService {
|
|
|
35
34
|
if (!result.issue) {
|
|
36
35
|
throw new Error(`Issue not found: ${issueId}`);
|
|
37
36
|
}
|
|
38
|
-
|
|
39
|
-
const attachments = issue.attachments;
|
|
40
|
-
return attachments.nodes.map(transformAttachment);
|
|
37
|
+
return result.issue.attachments.nodes.map(transformAttachment);
|
|
41
38
|
}
|
|
42
39
|
}
|
|
43
40
|
export async function createGraphQLAttachmentsService(options) {
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
import { CREATE_DOCUMENT_MUTATION, DELETE_DOCUMENT_MUTATION, GET_DOCUMENT_QUERY, LIST_DOCUMENTS_QUERY, UPDATE_DOCUMENT_MUTATION, } from "../queries/documents.js";
|
|
2
2
|
import { createGraphQLService, } from "./graphql-service.js";
|
|
3
3
|
function transformDocument(doc) {
|
|
4
|
-
const creator = doc.creator;
|
|
5
|
-
const project = doc.project;
|
|
6
|
-
const issue = doc.issue;
|
|
7
4
|
return {
|
|
8
5
|
id: doc.id,
|
|
9
6
|
title: doc.title,
|
|
10
|
-
content: doc.content
|
|
11
|
-
color: doc.color
|
|
12
|
-
icon: doc.icon
|
|
13
|
-
slugId: doc.slugId
|
|
14
|
-
url: doc.url
|
|
15
|
-
creator: creator
|
|
16
|
-
? { id: creator.id, name: creator.name }
|
|
7
|
+
content: doc.content ?? undefined,
|
|
8
|
+
color: doc.color ?? undefined,
|
|
9
|
+
icon: doc.icon ?? undefined,
|
|
10
|
+
slugId: doc.slugId ?? undefined,
|
|
11
|
+
url: doc.url ?? undefined,
|
|
12
|
+
creator: doc.creator
|
|
13
|
+
? { id: doc.creator.id, name: doc.creator.name }
|
|
17
14
|
: undefined,
|
|
18
|
-
project: project
|
|
19
|
-
? { id: project.id, name: project.name }
|
|
15
|
+
project: doc.project
|
|
16
|
+
? { id: doc.project.id, name: doc.project.name }
|
|
20
17
|
: undefined,
|
|
21
|
-
issue: issue
|
|
18
|
+
issue: doc.issue
|
|
22
19
|
? {
|
|
23
|
-
id: issue.id,
|
|
24
|
-
identifier: issue.identifier,
|
|
25
|
-
title: issue.title,
|
|
20
|
+
id: doc.issue.id,
|
|
21
|
+
identifier: doc.issue.identifier,
|
|
22
|
+
title: doc.issue.title,
|
|
26
23
|
}
|
|
27
24
|
: undefined,
|
|
28
|
-
createdAt: doc.createdAt
|
|
29
|
-
updatedAt: doc.updatedAt
|
|
25
|
+
createdAt: doc.createdAt ?? undefined,
|
|
26
|
+
updatedAt: doc.updatedAt ?? undefined,
|
|
30
27
|
};
|
|
31
28
|
}
|
|
32
29
|
class GraphQLDocumentsService {
|
|
@@ -37,7 +34,7 @@ class GraphQLDocumentsService {
|
|
|
37
34
|
async createDocument(input) {
|
|
38
35
|
const result = await this.graphqlService.rawRequest(CREATE_DOCUMENT_MUTATION, { input });
|
|
39
36
|
const createData = result.documentCreate;
|
|
40
|
-
if (!createData.success) {
|
|
37
|
+
if (!createData.success || !createData.document) {
|
|
41
38
|
throw new Error(`Failed to create document "${input.title}"${input.projectId ? ` in project ${input.projectId}` : ""}${input.teamId ? ` for team ${input.teamId}` : ""}`);
|
|
42
39
|
}
|
|
43
40
|
return transformDocument(createData.document);
|
|
@@ -45,15 +42,13 @@ class GraphQLDocumentsService {
|
|
|
45
42
|
async updateDocument(id, input) {
|
|
46
43
|
const result = await this.graphqlService.rawRequest(UPDATE_DOCUMENT_MUTATION, { id, input });
|
|
47
44
|
const updateData = result.documentUpdate;
|
|
48
|
-
if (!updateData.success) {
|
|
45
|
+
if (!updateData.success || !updateData.document) {
|
|
49
46
|
throw new Error(`Failed to update document: ${id}`);
|
|
50
47
|
}
|
|
51
48
|
return transformDocument(updateData.document);
|
|
52
49
|
}
|
|
53
50
|
async getDocument(id) {
|
|
54
|
-
const result = await this.graphqlService.rawRequest(GET_DOCUMENT_QUERY, {
|
|
55
|
-
id,
|
|
56
|
-
});
|
|
51
|
+
const result = await this.graphqlService.rawRequest(GET_DOCUMENT_QUERY, { id });
|
|
57
52
|
if (!result.document) {
|
|
58
53
|
throw new Error(`Document not found: ${id}`);
|
|
59
54
|
}
|
|
@@ -71,8 +66,7 @@ class GraphQLDocumentsService {
|
|
|
71
66
|
}
|
|
72
67
|
async deleteDocument(id) {
|
|
73
68
|
const result = await this.graphqlService.rawRequest(DELETE_DOCUMENT_MUTATION, { id });
|
|
74
|
-
|
|
75
|
-
if (!deleteData.success) {
|
|
69
|
+
if (!result.documentDelete.success) {
|
|
76
70
|
throw new Error(`Failed to delete document: ${id}`);
|
|
77
71
|
}
|
|
78
72
|
return true;
|
|
@@ -1,19 +1,132 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { IssueArchiveEntity, IssueNode, IssueWithCommentsNode } from "../queries/issues-types.js";
|
|
2
|
+
import type { LinearIssue } from "../types/linear.js";
|
|
2
3
|
import type { GraphQLService } from "./graphql-service.js";
|
|
3
4
|
import type { LinearService } from "./linear-service.js";
|
|
5
|
+
/**
|
|
6
|
+
* Arguments accepted by `GraphQLIssuesService.searchIssues`. Two
|
|
7
|
+
* modes:
|
|
8
|
+
* - When `query` is set, runs Linear's full-text search and
|
|
9
|
+
* post-filters the results with the structured filters below.
|
|
10
|
+
* - When `query` is unset, runs a structured filter directly.
|
|
11
|
+
*/
|
|
12
|
+
export interface SearchIssueArgs {
|
|
13
|
+
/** Free-text search term. When set, `searchIssues` uses Linear's
|
|
14
|
+
* native full-text search. */
|
|
15
|
+
query?: string;
|
|
16
|
+
/** Team key, name, or UUID. */
|
|
17
|
+
teamId?: string;
|
|
18
|
+
/** Project name or UUID. */
|
|
19
|
+
projectId?: string;
|
|
20
|
+
/** Set true to match only issues with NO project. Mutually
|
|
21
|
+
* exclusive with `projectId`. */
|
|
22
|
+
noProject?: boolean;
|
|
23
|
+
/** Assignee name, email, alias, or UUID. */
|
|
24
|
+
assigneeId?: string;
|
|
25
|
+
/** Issue states to include (e.g. `["Todo", "In Progress"]`). */
|
|
26
|
+
status?: string[];
|
|
27
|
+
/** Label names to require (intersection). */
|
|
28
|
+
labelNames?: string[];
|
|
29
|
+
/** Priority values (0-4) to include. */
|
|
30
|
+
priority?: number[];
|
|
31
|
+
/** Result cap; defaults to 10 when not set. */
|
|
32
|
+
limit?: number;
|
|
33
|
+
/** Linear orderBy enum (`createdAt` / `updatedAt`). */
|
|
34
|
+
orderBy?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Arguments accepted by `GraphQLIssuesService.updateIssue`. Same
|
|
38
|
+
* field shapes as `CreateIssueArgs` (UUID-or-name where applicable),
|
|
39
|
+
* but with `id` required (the issue to update) and `subscriberIds` /
|
|
40
|
+
* `templateId` omitted (not valid on update).
|
|
41
|
+
*/
|
|
42
|
+
export interface UpdateIssueArgs {
|
|
43
|
+
/** Issue identifier (e.g. `DEV-3592`) or UUID. Required. */
|
|
44
|
+
id: string;
|
|
45
|
+
title?: string;
|
|
46
|
+
description?: string;
|
|
47
|
+
/** Assignee name, email, alias, or UUID. */
|
|
48
|
+
assigneeId?: string;
|
|
49
|
+
priority?: number;
|
|
50
|
+
projectId?: string;
|
|
51
|
+
statusId?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Hint for the team-aware label resolver when the issue is being
|
|
54
|
+
* moved between teams.
|
|
55
|
+
*/
|
|
56
|
+
teamId?: string;
|
|
57
|
+
labelIds?: string[];
|
|
58
|
+
parentId?: string;
|
|
59
|
+
milestoneId?: string;
|
|
60
|
+
cycleId?: string | null;
|
|
61
|
+
dueDate?: string;
|
|
62
|
+
estimate?: number;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Arguments accepted by `GraphQLIssuesService.createIssue`. Most fields
|
|
66
|
+
* may be passed as a Linear UUID OR a name/identifier — the service
|
|
67
|
+
* resolves names to UUIDs against the workspace before issuing the
|
|
68
|
+
* mutation. The few fields that must already be UUIDs are noted on
|
|
69
|
+
* the property docstring.
|
|
70
|
+
*
|
|
71
|
+
* Pre-fix this was `Record<string, unknown>` and every command-side
|
|
72
|
+
* caller built up a free-form object. A typo in `assigeeId` vs
|
|
73
|
+
* `assigneeId` compiled cleanly and silently dropped the field. With
|
|
74
|
+
* the typed shape, `tsc` catches the typo.
|
|
75
|
+
*/
|
|
76
|
+
export interface CreateIssueArgs {
|
|
77
|
+
title?: string;
|
|
78
|
+
/** Team key, name, or UUID. Required unless `templateId` is set. */
|
|
79
|
+
teamId?: string;
|
|
80
|
+
/** Original team token (key or name) — used in label resolution error messages. */
|
|
81
|
+
teamInput?: string;
|
|
82
|
+
description?: string;
|
|
83
|
+
/** Assignee name, email, alias, or UUID. */
|
|
84
|
+
assigneeId?: string;
|
|
85
|
+
/** Linear priority: 0 (none), 1 (urgent), 2 (high), 3 (medium), 4 (low). */
|
|
86
|
+
priority?: number;
|
|
87
|
+
/** Project name or UUID. */
|
|
88
|
+
projectId?: string;
|
|
89
|
+
/** Status name or UUID — resolved per team. */
|
|
90
|
+
statusId?: string;
|
|
91
|
+
/** Label names or UUIDs — auto-created on the team if missing. */
|
|
92
|
+
labelIds?: string[];
|
|
93
|
+
/** Parent issue identifier or UUID. */
|
|
94
|
+
parentId?: string;
|
|
95
|
+
/** Project milestone name or UUID — resolved within the project. */
|
|
96
|
+
milestoneId?: string;
|
|
97
|
+
/** Cycle number, name, or UUID — resolved per team. */
|
|
98
|
+
cycleId?: string;
|
|
99
|
+
/** Subscriber names, emails, aliases, or UUIDs. */
|
|
100
|
+
subscriberIds?: string[];
|
|
101
|
+
/** Due date, ISO 8601. */
|
|
102
|
+
dueDate?: string;
|
|
103
|
+
/** Story-points / estimate. */
|
|
104
|
+
estimate?: number;
|
|
105
|
+
/** Linear server-side template UUID for `--from-template`. */
|
|
106
|
+
templateId?: string;
|
|
107
|
+
}
|
|
108
|
+
export interface IssueArchiveOperationResult {
|
|
109
|
+
id: string;
|
|
110
|
+
entity?: IssueArchiveEntity;
|
|
111
|
+
lastSyncId: number;
|
|
112
|
+
}
|
|
4
113
|
export declare class GraphQLIssuesService {
|
|
5
114
|
private readonly graphQLService;
|
|
6
115
|
private readonly linearService;
|
|
7
116
|
constructor(graphQLService: GraphQLService, linearService: LinearService);
|
|
8
117
|
getIssues(limit?: number): Promise<LinearIssue[]>;
|
|
9
118
|
getIssueById(issueId: string): Promise<LinearIssue>;
|
|
10
|
-
updateIssue(args:
|
|
119
|
+
updateIssue(args: UpdateIssueArgs, labelMode?: string): Promise<LinearIssue>;
|
|
120
|
+
archiveIssue(issueId: string): Promise<IssueArchiveOperationResult>;
|
|
121
|
+
deleteIssue(issueId: string, options?: {
|
|
122
|
+
permanentlyDelete?: boolean;
|
|
123
|
+
}): Promise<IssueArchiveOperationResult>;
|
|
11
124
|
private extractMilestoneNodes;
|
|
12
125
|
private executeUpdateMutation;
|
|
13
|
-
createIssue(args:
|
|
126
|
+
createIssue(args: CreateIssueArgs): Promise<LinearIssue>;
|
|
14
127
|
private resolveCreateFields;
|
|
15
128
|
private executeCreateMutation;
|
|
16
|
-
searchIssues(args:
|
|
129
|
+
searchIssues(args: SearchIssueArgs): Promise<LinearIssue[]>;
|
|
17
130
|
private resolveTeamId;
|
|
18
131
|
private resolveProjectId;
|
|
19
132
|
/**
|
|
@@ -41,7 +154,7 @@ export declare class GraphQLIssuesService {
|
|
|
41
154
|
private resolveStatusIdForUpdate;
|
|
42
155
|
private buildCreateResolveVariables;
|
|
43
156
|
private resolveParentId;
|
|
44
|
-
transformIssueData(issue:
|
|
157
|
+
transformIssueData(issue: IssueNode | IssueWithCommentsNode): LinearIssue;
|
|
45
158
|
private transformIssueCoreFields;
|
|
46
159
|
private transformIssueRelations;
|
|
47
160
|
private transformIssueHierarchy;
|