@enrichlayer/el-linear 1.10.0 → 1.15.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 +126 -10
- package/claude-skills/linear-operations/SKILL.md +41 -1
- package/dist/auth/linear-credential.d.ts +27 -0
- package/dist/auth/linear-credential.js +1 -0
- package/dist/auth/oauth-app-config.d.ts +4 -3
- package/dist/auth/oauth-app-config.js +13 -2
- package/dist/auth/oauth-callback.d.ts +2 -3
- package/dist/auth/oauth-callback.js +2 -2
- package/dist/auth/oauth-client.d.ts +8 -2
- package/dist/auth/oauth-client.js +26 -0
- package/dist/auth/oauth-fs.d.ts +2 -1
- package/dist/auth/oauth-headless.d.ts +2 -1
- package/dist/auth/oauth-storage.d.ts +5 -1
- package/dist/auth/oauth-storage.js +1 -1
- package/dist/auth/oauth-token.d.ts +4 -3
- package/dist/auth/oauth-token.js +16 -4
- package/dist/auth/token-resolver.d.ts +14 -5
- package/dist/auth/token-resolver.js +6 -1
- package/dist/commands/batch.js +18 -21
- package/dist/commands/comments.js +5 -5
- package/dist/commands/config.js +178 -5
- package/dist/commands/init/aliases.js +1 -1
- package/dist/commands/init/defaults.d.ts +2 -1
- package/dist/commands/init/index.js +45 -35
- package/dist/commands/init/oauth.d.ts +4 -1
- package/dist/commands/init/oauth.js +22 -4
- package/dist/commands/init/shared.d.ts +24 -2
- package/dist/commands/init/shared.js +35 -4
- package/dist/commands/init/token.d.ts +3 -3
- package/dist/commands/init/token.js +5 -24
- package/dist/commands/init/workspace.d.ts +2 -1
- package/dist/commands/init/workspace.js +1 -1
- package/dist/commands/introspect.d.ts +27 -0
- package/dist/commands/introspect.js +178 -0
- package/dist/commands/issues/branch.js +9 -1
- package/dist/commands/issues/relations.d.ts +3 -14
- package/dist/commands/issues/relations.js +3 -3
- package/dist/commands/issues.js +222 -43
- package/dist/commands/labels.js +2 -1
- package/dist/commands/profile.js +1 -0
- package/dist/commands/projects.d.ts +2 -0
- package/dist/commands/projects.js +91 -7
- package/dist/commands/read-shortcut.d.ts +1 -1
- package/dist/commands/read-shortcut.js +28 -8
- package/dist/commands/refs.js +67 -8
- package/dist/commands/search.js +30 -5
- package/dist/commands/users.js +4 -2
- package/dist/config/config.d.ts +99 -1
- package/dist/config/config.js +264 -52
- package/dist/config/error-enrichment.d.ts +62 -0
- package/dist/config/error-enrichment.js +417 -0
- package/dist/config/issue-validation.d.ts +37 -0
- package/dist/config/issue-validation.js +63 -1
- package/dist/config/paths.d.ts +2 -8
- package/dist/config/paths.js +4 -2
- package/dist/config/resolver.d.ts +8 -1
- package/dist/config/resolver.js +9 -2
- package/dist/main.js +13 -1
- package/dist/queries/comments-types.d.ts +15 -9
- package/dist/queries/common.d.ts +2 -2
- package/dist/queries/common.js +8 -0
- package/dist/queries/documents-types.d.ts +4 -3
- package/dist/queries/introspect-types.d.ts +8 -7
- package/dist/queries/issues-types.d.ts +92 -27
- package/dist/queries/issues.d.ts +49 -10
- package/dist/queries/issues.js +125 -5
- package/dist/queries/labels-types.d.ts +7 -6
- package/dist/queries/project-milestones-types.d.ts +5 -4
- package/dist/queries/project-milestones.d.ts +1 -1
- package/dist/queries/projects-types.d.ts +8 -7
- package/dist/queries/releases-types.d.ts +5 -4
- package/dist/queries/search-types.d.ts +28 -12
- package/dist/queries/templates-types.d.ts +3 -2
- package/dist/types/linear.d.ts +13 -1
- package/dist/utils/auto-link-references.d.ts +3 -3
- package/dist/utils/auto-link-references.js +1 -10
- package/dist/utils/extract-field.d.ts +19 -0
- package/dist/utils/extract-field.js +99 -0
- package/dist/utils/file-service.d.ts +6 -13
- package/dist/utils/file-service.js +0 -2
- package/dist/utils/formatters/summary.js +6 -1
- package/dist/utils/graphql-issues-service.d.ts +101 -45
- package/dist/utils/graphql-issues-service.js +252 -39
- package/dist/utils/graphql-service.d.ts +10 -12
- package/dist/utils/graphql-service.js +0 -3
- package/dist/utils/issue-reference-extractor.d.ts +7 -0
- package/dist/utils/issue-reference-extractor.js +5 -3
- package/dist/utils/issues-service-bootstrap.d.ts +28 -0
- package/dist/utils/issues-service-bootstrap.js +27 -0
- package/dist/utils/linear-service.d.ts +21 -14
- package/dist/utils/linear-service.js +73 -11
- package/dist/utils/markdown-prosemirror.js +12 -12
- package/dist/utils/mention-resolver.js +1 -1
- package/dist/utils/output.d.ts +81 -3
- package/dist/utils/output.js +61 -6
- package/dist/utils/project-slug.d.ts +21 -0
- package/dist/utils/project-slug.js +45 -0
- package/dist/utils/protected-ranges.d.ts +14 -0
- package/dist/utils/protected-ranges.js +88 -2
- package/dist/utils/sanitize-for-log.d.ts +24 -0
- package/dist/utils/sanitize-for-log.js +38 -0
- package/dist/utils/table-formatter.js +24 -0
- package/dist/utils/validators.d.ts +7 -2
- package/dist/utils/validators.js +6 -0
- package/dist/utils/workspace-url.js +20 -4
- package/package.json +2 -2
package/dist/queries/issues.js
CHANGED
|
@@ -41,12 +41,23 @@ export const FILTERED_SEARCH_ISSUES_QUERY = `
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
`;
|
|
44
|
+
/**
|
|
45
|
+
* Batch-resolves a search's team/project/assignee/delegate filter inputs.
|
|
46
|
+
*
|
|
47
|
+
* The `projects` block is `@include`-gated: Linear treats a null filter
|
|
48
|
+
* comparator as "no filter", so an always-on block with an unset
|
|
49
|
+
* `$projectName` would fetch an arbitrary project. (Search resolves a UUID
|
|
50
|
+
* `--project` directly without consulting this block, so only the
|
|
51
|
+
* name-resolution arm is needed here.)
|
|
52
|
+
*/
|
|
44
53
|
export const BATCH_RESOLVE_FOR_SEARCH_QUERY = `
|
|
45
54
|
query BatchResolveForSearch(
|
|
46
55
|
$teamKey: String
|
|
47
56
|
$teamName: String
|
|
48
57
|
$projectName: String
|
|
58
|
+
$hasProjectName: Boolean = false
|
|
49
59
|
$assigneeEmail: String
|
|
60
|
+
$delegateEmail: String
|
|
50
61
|
) {
|
|
51
62
|
teams(
|
|
52
63
|
filter: {
|
|
@@ -64,7 +75,10 @@ export const BATCH_RESOLVE_FOR_SEARCH_QUERY = `
|
|
|
64
75
|
}
|
|
65
76
|
}
|
|
66
77
|
|
|
67
|
-
projects(
|
|
78
|
+
projects(
|
|
79
|
+
filter: { name: { eqIgnoreCase: $projectName } }
|
|
80
|
+
first: 1
|
|
81
|
+
) @include(if: $hasProjectName) {
|
|
68
82
|
nodes {
|
|
69
83
|
id
|
|
70
84
|
name
|
|
@@ -78,6 +92,14 @@ export const BATCH_RESOLVE_FOR_SEARCH_QUERY = `
|
|
|
78
92
|
email
|
|
79
93
|
}
|
|
80
94
|
}
|
|
95
|
+
|
|
96
|
+
delegates: users(filter: { email: { eq: $delegateEmail } }, first: 1) {
|
|
97
|
+
nodes {
|
|
98
|
+
id
|
|
99
|
+
name
|
|
100
|
+
email
|
|
101
|
+
}
|
|
102
|
+
}
|
|
81
103
|
}
|
|
82
104
|
`;
|
|
83
105
|
export const GET_ISSUE_BY_ID_QUERY = `
|
|
@@ -102,14 +124,46 @@ export const GET_ISSUE_BY_IDENTIFIER_QUERY = `
|
|
|
102
124
|
}
|
|
103
125
|
}
|
|
104
126
|
`;
|
|
127
|
+
/**
|
|
128
|
+
* Batch-resolves an update's project/milestone/issue inputs.
|
|
129
|
+
*
|
|
130
|
+
* The project and milestone blocks are `@include`-gated for the same
|
|
131
|
+
* reason as `BATCH_RESOLVE_FOR_CREATE_QUERY`: a null filter comparator is
|
|
132
|
+
* a no-op that returns an arbitrary record. A UUID `--project` is resolved
|
|
133
|
+
* by `id` (`projectsById`) so its milestones are still fetched for
|
|
134
|
+
* `--project-milestone` name resolution; a name uses `projectsByName`.
|
|
135
|
+
*/
|
|
105
136
|
export const BATCH_RESOLVE_FOR_UPDATE_QUERY = `
|
|
106
137
|
query BatchResolveForUpdate(
|
|
107
138
|
$projectName: String
|
|
139
|
+
$projectId: ID
|
|
140
|
+
$hasProjectName: Boolean = false
|
|
141
|
+
$hasProjectId: Boolean = false
|
|
108
142
|
$teamKey: String
|
|
109
143
|
$issueNumber: Float
|
|
110
144
|
$milestoneName: String
|
|
145
|
+
$hasMilestoneName: Boolean = false
|
|
111
146
|
) {
|
|
112
|
-
projects(
|
|
147
|
+
projectsByName: projects(
|
|
148
|
+
filter: { name: { eqIgnoreCase: $projectName } }
|
|
149
|
+
first: 1
|
|
150
|
+
) @include(if: $hasProjectName) {
|
|
151
|
+
nodes {
|
|
152
|
+
id
|
|
153
|
+
name
|
|
154
|
+
projectMilestones {
|
|
155
|
+
nodes {
|
|
156
|
+
id
|
|
157
|
+
name
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
projectsById: projects(
|
|
164
|
+
filter: { id: { eq: $projectId } }
|
|
165
|
+
first: 1
|
|
166
|
+
) @include(if: $hasProjectId) {
|
|
113
167
|
nodes {
|
|
114
168
|
id
|
|
115
169
|
name
|
|
@@ -125,7 +179,7 @@ export const BATCH_RESOLVE_FOR_UPDATE_QUERY = `
|
|
|
125
179
|
milestones: projectMilestones(
|
|
126
180
|
filter: { name: { eq: $milestoneName } }
|
|
127
181
|
first: 1
|
|
128
|
-
) {
|
|
182
|
+
) @include(if: $hasMilestoneName) {
|
|
129
183
|
nodes {
|
|
130
184
|
id
|
|
131
185
|
name
|
|
@@ -209,14 +263,37 @@ export const DELETE_ISSUE_MUTATION = `
|
|
|
209
263
|
}
|
|
210
264
|
}
|
|
211
265
|
`;
|
|
266
|
+
/**
|
|
267
|
+
* Batch-resolves a create's team/project/milestone/parent inputs in one
|
|
268
|
+
* round-trip.
|
|
269
|
+
*
|
|
270
|
+
* The project and milestone blocks are gated behind `@include` directives
|
|
271
|
+
* rather than left always-on. Linear treats a null filter comparator
|
|
272
|
+
* (`{ name: { eqIgnoreCase: null } }`) as "no filter" — so an always-on
|
|
273
|
+
* `projects` block with an unset `$projectName` returns an *arbitrary*
|
|
274
|
+
* project, which the caller would then mistake for the user's project
|
|
275
|
+
* (e.g. auto-switching the team to that unrelated project's team). The
|
|
276
|
+
* `has*` booleans ensure a block is fetched only when its input exists.
|
|
277
|
+
*
|
|
278
|
+
* A UUID `--project` is resolved by `id` (`projectsById`) so its team
|
|
279
|
+
* associations are still fetched for team-project validation; a name is
|
|
280
|
+
* resolved by `name` (`projectsByName`). The two are mutually exclusive,
|
|
281
|
+
* but GraphQL forbids two same-aliased fields with differing arguments,
|
|
282
|
+
* so they carry distinct aliases and the service folds whichever ran
|
|
283
|
+
* into `resolveResult.projects`.
|
|
284
|
+
*/
|
|
212
285
|
export const BATCH_RESOLVE_FOR_CREATE_QUERY = `
|
|
213
286
|
query BatchResolveForCreate(
|
|
214
287
|
$teamKey: String
|
|
215
288
|
$teamName: String
|
|
216
289
|
$projectName: String
|
|
290
|
+
$projectId: ID
|
|
291
|
+
$hasProjectName: Boolean = false
|
|
292
|
+
$hasProjectId: Boolean = false
|
|
217
293
|
$parentTeamKey: String
|
|
218
294
|
$parentIssueNumber: Float
|
|
219
295
|
$milestoneName: String
|
|
296
|
+
$hasMilestoneName: Boolean = false
|
|
220
297
|
) {
|
|
221
298
|
teams(
|
|
222
299
|
filter: {
|
|
@@ -234,7 +311,26 @@ export const BATCH_RESOLVE_FOR_CREATE_QUERY = `
|
|
|
234
311
|
}
|
|
235
312
|
}
|
|
236
313
|
|
|
237
|
-
projects(
|
|
314
|
+
projectsByName: projects(
|
|
315
|
+
filter: { name: { eqIgnoreCase: $projectName } }
|
|
316
|
+
first: 1
|
|
317
|
+
) @include(if: $hasProjectName) {
|
|
318
|
+
nodes {
|
|
319
|
+
id
|
|
320
|
+
name
|
|
321
|
+
teams {
|
|
322
|
+
nodes { id key }
|
|
323
|
+
}
|
|
324
|
+
projectMilestones {
|
|
325
|
+
nodes { id name }
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
projectsById: projects(
|
|
331
|
+
filter: { id: { eq: $projectId } }
|
|
332
|
+
first: 1
|
|
333
|
+
) @include(if: $hasProjectId) {
|
|
238
334
|
nodes {
|
|
239
335
|
id
|
|
240
336
|
name
|
|
@@ -250,7 +346,7 @@ export const BATCH_RESOLVE_FOR_CREATE_QUERY = `
|
|
|
250
346
|
milestones: projectMilestones(
|
|
251
347
|
filter: { name: { eq: $milestoneName } }
|
|
252
348
|
first: 1
|
|
253
|
-
) {
|
|
349
|
+
) @include(if: $hasMilestoneName) {
|
|
254
350
|
nodes {
|
|
255
351
|
id
|
|
256
352
|
name
|
|
@@ -332,6 +428,30 @@ export const GET_ISSUE_TEAM_QUERY = `
|
|
|
332
428
|
}
|
|
333
429
|
}
|
|
334
430
|
`;
|
|
431
|
+
export const GET_ISSUE_START_CONTEXT_QUERY = `
|
|
432
|
+
query GetIssueStartContext($id: String!) {
|
|
433
|
+
issue(id: $id) {
|
|
434
|
+
id
|
|
435
|
+
identifier
|
|
436
|
+
state { id name type }
|
|
437
|
+
team { id key name }
|
|
438
|
+
delegate { id name url }
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
`;
|
|
442
|
+
export const TEAM_STARTED_STATUSES_QUERY = `
|
|
443
|
+
query TeamStartedStatuses($teamId: String!) {
|
|
444
|
+
team(id: $teamId) {
|
|
445
|
+
states(filter: { type: { eq: "started" } }) {
|
|
446
|
+
nodes {
|
|
447
|
+
id
|
|
448
|
+
name
|
|
449
|
+
position
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
`;
|
|
335
455
|
export const ISSUE_RELATION_CREATE_MUTATION = `
|
|
336
456
|
mutation IssueRelationCreate($input: IssueRelationCreateInput!) {
|
|
337
457
|
issueRelationCreate(input: $input) {
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* Typed response shapes for the queries in `./labels.ts`.
|
|
3
3
|
* See `./issues-types.ts` for the rationale (ALL-937).
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
interface LabelTeamRef {
|
|
6
6
|
id: string;
|
|
7
7
|
key: string;
|
|
8
8
|
name: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
interface LabelParentRef {
|
|
11
11
|
id: string;
|
|
12
12
|
name: string;
|
|
13
13
|
}
|
|
14
14
|
/** Mirrors the issueLabel selection set on `CREATE_LABEL_MUTATION`. */
|
|
15
|
-
|
|
15
|
+
interface CreatedLabelNode {
|
|
16
16
|
id: string;
|
|
17
17
|
name: string;
|
|
18
18
|
color: string;
|
|
@@ -20,7 +20,7 @@ export interface CreatedLabelNode {
|
|
|
20
20
|
parent: LabelParentRef | null;
|
|
21
21
|
}
|
|
22
22
|
/** Mirrors the issueLabel selection set on `RETIRE_LABEL_MUTATION`. */
|
|
23
|
-
|
|
23
|
+
interface RetiredLabelNode {
|
|
24
24
|
id: string;
|
|
25
25
|
name: string;
|
|
26
26
|
color: string;
|
|
@@ -28,13 +28,13 @@ export interface RetiredLabelNode {
|
|
|
28
28
|
team: LabelTeamRef | null;
|
|
29
29
|
}
|
|
30
30
|
/** Mirrors the issueLabel selection set on `RESTORE_LABEL_MUTATION`. */
|
|
31
|
-
|
|
31
|
+
interface RestoredLabelNode {
|
|
32
32
|
id: string;
|
|
33
33
|
name: string;
|
|
34
34
|
color: string;
|
|
35
35
|
team: LabelTeamRef | null;
|
|
36
36
|
}
|
|
37
|
-
|
|
37
|
+
interface ParentLabelNode {
|
|
38
38
|
id: string;
|
|
39
39
|
name: string;
|
|
40
40
|
isGroup: boolean;
|
|
@@ -62,3 +62,4 @@ export interface RestoreLabelResponse {
|
|
|
62
62
|
issueLabel: RestoredLabelNode | null;
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
+
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* consumer reads only what was actually selected.
|
|
9
9
|
*/
|
|
10
10
|
import type { IssueNode } from "./issues-types.js";
|
|
11
|
-
|
|
11
|
+
interface MilestoneProjectRef {
|
|
12
12
|
id: string;
|
|
13
13
|
name: string;
|
|
14
14
|
}
|
|
@@ -16,7 +16,7 @@ export interface MilestoneProjectRef {
|
|
|
16
16
|
* Mirrors the milestone selection set in `LIST_PROJECT_MILESTONES_QUERY`
|
|
17
17
|
* — full milestone fields without the project-back-reference.
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
interface MilestoneListNode {
|
|
20
20
|
id: string;
|
|
21
21
|
name: string;
|
|
22
22
|
description: string | null;
|
|
@@ -29,7 +29,7 @@ export interface MilestoneListNode {
|
|
|
29
29
|
* Mirrors the milestone selection set in `GET_PROJECT_MILESTONE_BY_ID_QUERY`
|
|
30
30
|
* — list shape + project + issues connection.
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
interface MilestoneDetailNode extends MilestoneListNode {
|
|
33
33
|
project: MilestoneProjectRef;
|
|
34
34
|
issues: {
|
|
35
35
|
nodes: IssueNode[];
|
|
@@ -50,7 +50,7 @@ export interface MilestoneLookupNode {
|
|
|
50
50
|
* Mirrors the milestone selection set on the create / update mutations —
|
|
51
51
|
* list shape + project (no issues connection).
|
|
52
52
|
*/
|
|
53
|
-
|
|
53
|
+
interface MutatedMilestoneNode extends MilestoneListNode {
|
|
54
54
|
project: MilestoneProjectRef;
|
|
55
55
|
}
|
|
56
56
|
export interface ListProjectMilestonesResponse {
|
|
@@ -89,3 +89,4 @@ export interface UpdateProjectMilestoneResponse {
|
|
|
89
89
|
projectMilestone: MutatedMilestoneNode | null;
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const LIST_PROJECT_MILESTONES_QUERY = "\n query ListProjectMilestones($projectId: String!, $first: Int!) {\n project(id: $projectId) {\n id\n name\n projectMilestones(first: $first) {\n nodes {\n id\n name\n description\n targetDate\n sortOrder\n createdAt\n updatedAt\n }\n }\n }\n }\n";
|
|
2
|
-
export declare const GET_PROJECT_MILESTONE_BY_ID_QUERY = "\n query GetProjectMilestone($id: String!, $issuesFirst: Int) {\n projectMilestone(id: $id) {\n id\n name\n description\n targetDate\n sortOrder\n createdAt\n updatedAt\n project {\n id\n name\n }\n issues(first: $issuesFirst) {\n nodes {\n \n \n id\n identifier\n title\n description\n summary { content generationStatus }\n branchName\n priority\n estimate\n dueDate\n url\n createdAt\n updatedAt\n\n \n state {\n id\n name\n }\n\n \n assignee {\n id\n name\n url\n }\n\n \n team {\n id\n key\n name\n }\n\n \n project {\n id\n name\n }\n\n \n labels {\n nodes {\n id\n name\n }\n }\n\n \n cycle {\n id\n name\n number\n }\n\n \n projectMilestone {\n id\n name\n targetDate\n }\n\n \n parent {\n id\n identifier\n title\n }\n\n \n children {\n nodes {\n id\n identifier\n title\n }\n }\n\n\n }\n }\n }\n }\n";
|
|
2
|
+
export declare const GET_PROJECT_MILESTONE_BY_ID_QUERY = "\n query GetProjectMilestone($id: String!, $issuesFirst: Int) {\n projectMilestone(id: $id) {\n id\n name\n description\n targetDate\n sortOrder\n createdAt\n updatedAt\n project {\n id\n name\n }\n issues(first: $issuesFirst) {\n nodes {\n \n \n id\n identifier\n title\n description\n summary { content generationStatus }\n branchName\n priority\n estimate\n dueDate\n url\n createdAt\n updatedAt\n\n \n state {\n id\n name\n }\n\n \n assignee {\n id\n name\n url\n }\n\n \n delegate {\n id\n name\n url\n }\n\n \n team {\n id\n key\n name\n }\n\n \n project {\n id\n name\n }\n\n \n labels {\n nodes {\n id\n name\n }\n }\n\n \n cycle {\n id\n name\n number\n }\n\n \n projectMilestone {\n id\n name\n targetDate\n }\n\n \n parent {\n id\n identifier\n title\n }\n\n \n children {\n nodes {\n id\n identifier\n title\n }\n }\n\n\n }\n }\n }\n }\n";
|
|
3
3
|
export declare const FIND_PROJECT_MILESTONE_BY_NAME_SCOPED = "\n query FindProjectMilestoneScoped($name: String!, $projectId: String!) {\n project(id: $projectId) {\n projectMilestones(filter: { name: { eq: $name } }, first: 10) {\n nodes {\n id\n name\n targetDate\n sortOrder\n project {\n id\n name\n }\n }\n }\n }\n }\n";
|
|
4
4
|
export declare const FIND_PROJECT_MILESTONE_BY_NAME_GLOBAL = "\n query FindProjectMilestoneGlobal($name: String!) {\n projectMilestones(filter: { name: { eq: $name } }, first: 10) {\n nodes {\n id\n name\n targetDate\n sortOrder\n project {\n id\n name\n }\n }\n }\n }\n";
|
|
5
5
|
export declare const CREATE_PROJECT_MILESTONE_MUTATION = "\n mutation CreateProjectMilestone($projectId: String!, $name: String!, $description: String, $targetDate: TimelessDate) {\n projectMilestoneCreate(input: {\n projectId: $projectId\n name: $name\n description: $description\n targetDate: $targetDate\n }) {\n success\n projectMilestone {\n id\n name\n description\n targetDate\n sortOrder\n createdAt\n updatedAt\n project {\n id\n name\n }\n }\n }\n }\n";
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* Typed response shapes for the queries in `./projects.ts`.
|
|
3
3
|
* See `./issues-types.ts` for the rationale (ALL-937).
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
interface ProjectTeamRef {
|
|
6
6
|
id: string;
|
|
7
7
|
key: string;
|
|
8
8
|
name: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
interface ProjectBaseNode {
|
|
11
11
|
id: string;
|
|
12
12
|
name: string;
|
|
13
13
|
teams: {
|
|
@@ -18,15 +18,15 @@ export interface ProjectBaseNode {
|
|
|
18
18
|
* Mirrors the project selection set used by `SEARCH_PROJECTS_BY_NAME_QUERY`
|
|
19
19
|
* and `CREATE_PROJECT_MUTATION` — base fields + state.
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
interface ProjectWithStateNode extends ProjectBaseNode {
|
|
22
22
|
state: string;
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
interface ProjectIssueRef {
|
|
25
25
|
id: string;
|
|
26
26
|
identifier: string;
|
|
27
27
|
title: string;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
interface ProjectWithIssuesNode extends ProjectBaseNode {
|
|
30
30
|
issues: {
|
|
31
31
|
nodes: ProjectIssueRef[];
|
|
32
32
|
};
|
|
@@ -59,10 +59,10 @@ export interface UpdateProjectResponse {
|
|
|
59
59
|
project: ProjectBaseNode | null;
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
interface ProjectArchiveEntity {
|
|
63
63
|
id: string;
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
interface ProjectArchivePayload {
|
|
66
66
|
success: boolean;
|
|
67
67
|
lastSyncId: number;
|
|
68
68
|
entity: ProjectArchiveEntity | null;
|
|
@@ -73,3 +73,4 @@ export interface ArchiveProjectResponse {
|
|
|
73
73
|
export interface DeleteProjectResponse {
|
|
74
74
|
projectDelete: ProjectArchivePayload;
|
|
75
75
|
}
|
|
76
|
+
export {};
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* Typed response shapes for the queries in `./releases.ts`.
|
|
3
3
|
* See `./issues-types.ts` for the rationale (ALL-937).
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
interface ReleaseStageRef {
|
|
6
6
|
id: string;
|
|
7
7
|
name: string;
|
|
8
8
|
type: string;
|
|
9
9
|
color: string | null;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
interface ReleasePipelineRef {
|
|
12
12
|
id: string;
|
|
13
13
|
name: string;
|
|
14
14
|
}
|
|
15
|
-
|
|
15
|
+
interface ReleaseDocumentRef {
|
|
16
16
|
id: string;
|
|
17
17
|
title: string;
|
|
18
18
|
slugId: string;
|
|
@@ -56,7 +56,7 @@ export interface CreatedReleaseNode {
|
|
|
56
56
|
createdAt: string;
|
|
57
57
|
updatedAt: string;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
interface ReleasePipelineNode {
|
|
60
60
|
id: string;
|
|
61
61
|
name: string;
|
|
62
62
|
stages: {
|
|
@@ -82,3 +82,4 @@ export interface GetReleasePipelinesResponse {
|
|
|
82
82
|
nodes: ReleasePipelineNode[];
|
|
83
83
|
};
|
|
84
84
|
}
|
|
85
|
+
export {};
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* templates listing in `commands/search.ts`. See `./issues-types.ts`
|
|
4
4
|
* for the rationale (ALL-937).
|
|
5
5
|
*/
|
|
6
|
-
|
|
6
|
+
import type { LinearPriority } from "../types/linear.js";
|
|
7
|
+
interface SearchIssueRef {
|
|
7
8
|
id: string;
|
|
8
9
|
identifier: string;
|
|
9
10
|
title: string;
|
|
10
|
-
priority:
|
|
11
|
+
priority: LinearPriority | null;
|
|
11
12
|
state: {
|
|
12
13
|
id: string;
|
|
13
14
|
name: string;
|
|
@@ -27,17 +28,17 @@ export interface SearchIssueRef {
|
|
|
27
28
|
name: string;
|
|
28
29
|
} | null;
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
+
interface SearchProjectRef {
|
|
31
32
|
id: string;
|
|
32
33
|
name: string;
|
|
33
34
|
state: string;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
interface SearchInitiativeRef {
|
|
36
37
|
id: string;
|
|
37
38
|
name: string;
|
|
38
39
|
status: string | null;
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
+
interface SearchDocumentRef {
|
|
41
42
|
id: string;
|
|
42
43
|
title: string;
|
|
43
44
|
slugId: string | null;
|
|
@@ -47,18 +48,32 @@ export interface SearchDocumentRef {
|
|
|
47
48
|
} | null;
|
|
48
49
|
}
|
|
49
50
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
51
|
+
* A single semanticSearch result. Discriminated union on `type` — given
|
|
52
|
+
* a row, only the field named by `type` is meaningful (the other three
|
|
53
|
+
* are absent / null on the wire). Consumers `switch (r.type)` and access
|
|
54
|
+
* the corresponding payload directly; the compiler statically rejects
|
|
55
|
+
* cross-arm access like `r.project` in a `case "issue"` branch.
|
|
56
|
+
*
|
|
57
|
+
* The payload itself is `| null` because Linear can return null when
|
|
58
|
+
* the underlying entity was deleted between indexing and query time —
|
|
59
|
+
* that's an orthogonal concern from the discriminant.
|
|
60
|
+
*
|
|
61
|
+
* The four `type` literals match Linear's `semanticSearch.results.type`
|
|
62
|
+
* enum verbatim — keep in lock-step with the GraphQL schema's enum.
|
|
54
63
|
*/
|
|
55
|
-
export
|
|
56
|
-
type:
|
|
64
|
+
export type SemanticSearchResult = {
|
|
65
|
+
type: "issue";
|
|
57
66
|
issue: SearchIssueRef | null;
|
|
67
|
+
} | {
|
|
68
|
+
type: "project";
|
|
58
69
|
project: SearchProjectRef | null;
|
|
70
|
+
} | {
|
|
71
|
+
type: "initiative";
|
|
59
72
|
initiative: SearchInitiativeRef | null;
|
|
73
|
+
} | {
|
|
74
|
+
type: "document";
|
|
60
75
|
document: SearchDocumentRef | null;
|
|
61
|
-
}
|
|
76
|
+
};
|
|
62
77
|
export interface SemanticSearchResponse {
|
|
63
78
|
semanticSearch: {
|
|
64
79
|
results: SemanticSearchResult[];
|
|
@@ -84,3 +99,4 @@ export interface SearchTemplateNode {
|
|
|
84
99
|
export interface SearchTemplatesResponse {
|
|
85
100
|
templates: SearchTemplateNode[];
|
|
86
101
|
}
|
|
102
|
+
export {};
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
* than wrapped in `{ nodes: ... }`. The response type below mirrors
|
|
7
7
|
* what the API actually returns, not the connection convention.
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
interface TemplateTeamRef {
|
|
10
10
|
id: string;
|
|
11
11
|
key: string;
|
|
12
12
|
name: string;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
interface TemplateCreatorRef {
|
|
15
15
|
id: string;
|
|
16
16
|
name: string;
|
|
17
17
|
}
|
|
@@ -59,3 +59,4 @@ export interface DeleteTemplateResponse {
|
|
|
59
59
|
lastSyncId?: number;
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
export {};
|
package/dist/types/linear.d.ts
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
* These represent the public API surface — GraphQL responses are
|
|
4
4
|
* transformed into these shapes at the service boundary.
|
|
5
5
|
*/
|
|
6
|
+
/**
|
|
7
|
+
* Linear priority levels — `0` = no priority, `1` = urgent, `2` = high,
|
|
8
|
+
* `3` = medium (alias: normal), `4` = low. Sourced from Linear's
|
|
9
|
+
* `Issue.priority` enum; the GraphQL API returns a number in this range.
|
|
10
|
+
* Use this instead of `number` at every API boundary so an out-of-range
|
|
11
|
+
* value (`9`) fails to compile.
|
|
12
|
+
*
|
|
13
|
+
* The runtime parser is `validatePriority` in `src/utils/validators.ts`
|
|
14
|
+
* — it narrows arbitrary `string` input to this union.
|
|
15
|
+
*/
|
|
16
|
+
export type LinearPriority = 0 | 1 | 2 | 3 | 4;
|
|
6
17
|
interface TeamRef {
|
|
7
18
|
id: string;
|
|
8
19
|
key: string;
|
|
@@ -87,6 +98,7 @@ export interface LinearIssue {
|
|
|
87
98
|
comments?: LinearComment[];
|
|
88
99
|
createdAt: string;
|
|
89
100
|
cycle?: CycleRef;
|
|
101
|
+
delegate?: UserRef;
|
|
90
102
|
description?: string;
|
|
91
103
|
dueDate?: string;
|
|
92
104
|
embeds?: import("../utils/embed-parser.js").Embed[];
|
|
@@ -95,7 +107,7 @@ export interface LinearIssue {
|
|
|
95
107
|
identifier: string;
|
|
96
108
|
labels: LabelRef[];
|
|
97
109
|
parentIssue?: IssueRef;
|
|
98
|
-
priority:
|
|
110
|
+
priority: LinearPriority;
|
|
99
111
|
project?: ProjectRef;
|
|
100
112
|
projectMilestone?: MilestoneRef;
|
|
101
113
|
state?: StateRef;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import type { GraphQLService } from "./graphql-service.js";
|
|
2
2
|
import { type IssueRelationType } from "./issue-reference-extractor.js";
|
|
3
3
|
import type { LinearService } from "./linear-service.js";
|
|
4
|
-
|
|
4
|
+
interface AutoLinkLinked {
|
|
5
5
|
identifier: string;
|
|
6
6
|
/** True when source/target were swapped on the create (e.g. "blocked by X" → X→source) */
|
|
7
7
|
reverse: boolean;
|
|
8
8
|
title: string;
|
|
9
9
|
type: IssueRelationType;
|
|
10
10
|
}
|
|
11
|
-
|
|
11
|
+
interface AutoLinkSkipped {
|
|
12
12
|
existingType: string;
|
|
13
13
|
identifier: string;
|
|
14
14
|
/** Type that would have been created had the reference been new */
|
|
15
15
|
inferredType: IssueRelationType;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
interface AutoLinkFailed {
|
|
18
18
|
identifier: string;
|
|
19
19
|
reason: string;
|
|
20
20
|
}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { GET_ISSUE_RELATIONS_QUERY, ISSUE_RELATION_CREATE_MUTATION, } from "../queries/issues.js";
|
|
2
|
-
import { extractIssueReferences, } from "./issue-reference-extractor.js";
|
|
3
|
-
function specificity(ref) {
|
|
4
|
-
if (ref.type === "duplicate") {
|
|
5
|
-
return 3;
|
|
6
|
-
}
|
|
7
|
-
if (ref.type === "blocks") {
|
|
8
|
-
return 2;
|
|
9
|
-
}
|
|
10
|
-
return 1;
|
|
11
|
-
}
|
|
2
|
+
import { extractIssueReferences, specificity, } from "./issue-reference-extractor.js";
|
|
12
3
|
/**
|
|
13
4
|
* Merge candidates from multiple sources (description, comments) into one list,
|
|
14
5
|
* keeping the strongest (most-specific) inference per identifier. The first source
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a named section from a Linear issue's markdown description.
|
|
3
|
+
*
|
|
4
|
+
* Linear issue bodies follow a small set of repeated structures —
|
|
5
|
+
* "Why we need this", "Done when", "Scope", "Out of scope", etc. —
|
|
6
|
+
* usually as `##` or `###` headers, sometimes as bold pseudo-headers
|
|
7
|
+
* (`**Done when**`). Agents end up repeatedly piping
|
|
8
|
+
* `el-linear issues read X | python -c '...desc.find("Done when")...'`
|
|
9
|
+
* to pull one section out. This helper centralizes that.
|
|
10
|
+
*
|
|
11
|
+
* Matching is case-insensitive on the header text. The first matching
|
|
12
|
+
* header wins. Content is everything between that header and the next
|
|
13
|
+
* header line (any `#{1,6}` or bold pseudo-header at line start) or EOF,
|
|
14
|
+
* trimmed of surrounding whitespace.
|
|
15
|
+
*
|
|
16
|
+
* Returns `null` when the field isn't found, so callers can distinguish
|
|
17
|
+
* "missing" from "empty body".
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractField(body: string, fieldName: string): string | null;
|