@alasano/pi-linear 0.1.1 → 0.3.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.
Files changed (38) hide show
  1. package/README.md +16 -2
  2. package/assets/linear_list_issues.png +0 -0
  3. package/assets/screenshot.png +0 -0
  4. package/extensions/params.ts +40 -1
  5. package/extensions/renderers/comments.ts +323 -0
  6. package/extensions/renderers/common.ts +305 -0
  7. package/extensions/renderers/documents.ts +326 -0
  8. package/extensions/renderers/initiatives.ts +344 -0
  9. package/extensions/renderers/issue-labels.ts +294 -0
  10. package/extensions/renderers/issue-relations.ts +318 -0
  11. package/extensions/renderers/issue-statuses.ts +199 -0
  12. package/extensions/renderers/issues.ts +373 -0
  13. package/extensions/renderers/milestones.ts +294 -0
  14. package/extensions/renderers/project-labels.ts +279 -0
  15. package/extensions/renderers/project-relations.ts +344 -0
  16. package/extensions/renderers/projects.ts +437 -0
  17. package/extensions/renderers/state.ts +35 -0
  18. package/extensions/renderers/teams.ts +246 -0
  19. package/extensions/renderers/users.ts +242 -0
  20. package/extensions/renderers/workspaces.ts +44 -0
  21. package/extensions/selections.ts +10 -3
  22. package/extensions/settings.ts +40 -7
  23. package/extensions/tools/comments.ts +30 -11
  24. package/extensions/tools/documents.ts +42 -11
  25. package/extensions/tools/initiatives.ts +43 -11
  26. package/extensions/tools/issue-labels.ts +36 -11
  27. package/extensions/tools/issue-relations.ts +32 -13
  28. package/extensions/tools/issue-statuses.ts +19 -11
  29. package/extensions/tools/issues.ts +53 -19
  30. package/extensions/tools/milestones.ts +31 -11
  31. package/extensions/tools/project-labels.ts +30 -11
  32. package/extensions/tools/project-relations.ts +32 -13
  33. package/extensions/tools/projects.ts +48 -16
  34. package/extensions/tools/teams.ts +23 -11
  35. package/extensions/tools/users.ts +23 -11
  36. package/extensions/tools/workspaces.ts +6 -0
  37. package/extensions/types.ts +12 -0
  38. package/package.json +1 -1
@@ -1,10 +1,28 @@
1
1
  import { defineTool } from '@mariozechner/pi-coding-agent';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { withLinearAuth, linearGraphQL } from '../client';
4
- import { PaginationParams, FilterParam, SortParam, RawInputParam } from '../params';
5
- import { PROJECT_SELECTION } from '../selections';
6
- import type { JsonObject } from '../types';
4
+ import {
5
+ PaginationParams,
6
+ paginationVariables,
7
+ FilterParam,
8
+ SortParam,
9
+ RawInputParam,
10
+ } from '../params';
11
+ import { PROJECT_DETAIL_SELECTION, PROJECT_LIST_SELECTION } from '../selections';
12
+ import type { JsonObject, LinearConnection } from '../types';
7
13
  import { compactObject, asObject, asObjectArray, asString } from '../util';
14
+ import {
15
+ renderLinearArchiveProjectCall,
16
+ renderLinearDeleteProjectCall,
17
+ renderLinearGetProjectCall,
18
+ renderLinearProjectListCall,
19
+ renderLinearProjectListResult,
20
+ renderLinearProjectResult,
21
+ renderLinearProjectSuccessResult,
22
+ renderLinearSaveProjectCall,
23
+ renderLinearSaveProjectResult,
24
+ renderLinearUnarchiveProjectCall,
25
+ } from '../renderers/projects';
8
26
 
9
27
  export function projectTools() {
10
28
  return [
@@ -17,21 +35,17 @@ export function projectTools() {
17
35
  ...FilterParam,
18
36
  ...SortParam,
19
37
  }),
38
+ renderCall: renderLinearProjectListCall,
20
39
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
21
40
  return withLinearAuth(ctx, signal, async (apiKey) => {
22
41
  const variables = compactObject({
23
- after: params.after,
24
- before: params.before,
42
+ ...paginationVariables(params, 20),
25
43
  filter: asObject(params.filter),
26
- first: params.first ?? 20,
27
- includeArchived: params.includeArchived,
28
- last: params.last,
29
- orderBy: params.orderBy,
30
44
  sort: asObjectArray(params.sort),
31
45
  });
32
46
 
33
47
  const data = await linearGraphQL<{
34
- projects: { nodes: Array<JsonObject> };
48
+ projects: LinearConnection<JsonObject>;
35
49
  }>(
36
50
  apiKey,
37
51
  `query ListProjects(
@@ -55,7 +69,13 @@ export function projectTools() {
55
69
  sort: $sort
56
70
  ) {
57
71
  nodes {
58
- ${PROJECT_SELECTION}
72
+ ${PROJECT_LIST_SELECTION}
73
+ }
74
+ pageInfo {
75
+ hasNextPage
76
+ hasPreviousPage
77
+ startCursor
78
+ endCursor
59
79
  }
60
80
  }
61
81
  }`,
@@ -64,12 +84,14 @@ export function projectTools() {
64
84
  );
65
85
 
66
86
  const projects = data.projects.nodes;
87
+ const pageInfo = data.projects.pageInfo;
67
88
  return {
68
- content: [{ type: 'text', text: JSON.stringify({ projects }, null, 2) }],
69
- details: { projects },
89
+ content: [{ type: 'text', text: JSON.stringify({ projects, pageInfo }, null, 2) }],
90
+ details: { projects, pageInfo },
70
91
  };
71
92
  });
72
93
  },
94
+ renderResult: renderLinearProjectListResult,
73
95
  }),
74
96
  defineTool({
75
97
  name: 'linear_get_project',
@@ -78,13 +100,14 @@ export function projectTools() {
78
100
  parameters: Type.Object({
79
101
  projectId: Type.String({ description: 'Project id.' }),
80
102
  }),
103
+ renderCall: renderLinearGetProjectCall,
81
104
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
82
105
  return withLinearAuth(ctx, signal, async (apiKey) => {
83
106
  const data = await linearGraphQL<{ project: JsonObject | null }>(
84
107
  apiKey,
85
108
  `query GetProject($id: String!) {
86
109
  project(id: $id) {
87
- ${PROJECT_SELECTION}
110
+ ${PROJECT_DETAIL_SELECTION}
88
111
  }
89
112
  }`,
90
113
  { id: params.projectId },
@@ -100,6 +123,7 @@ export function projectTools() {
100
123
  };
101
124
  });
102
125
  },
126
+ renderResult: renderLinearProjectResult('Project'),
103
127
  }),
104
128
  defineTool({
105
129
  name: 'linear_save_project',
@@ -145,6 +169,7 @@ export function projectTools() {
145
169
  slackChannelName: Type.Optional(Type.String()),
146
170
  ...RawInputParam,
147
171
  }),
172
+ renderCall: renderLinearSaveProjectCall,
148
173
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
149
174
  return withLinearAuth(ctx, signal, async (apiKey) => {
150
175
  const rawInput = asObject(params.input) || {};
@@ -203,7 +228,7 @@ export function projectTools() {
203
228
  projectUpdate(id: $id, input: $input) {
204
229
  success
205
230
  project {
206
- ${PROJECT_SELECTION}
231
+ ${PROJECT_DETAIL_SELECTION}
207
232
  }
208
233
  }
209
234
  }`,
@@ -238,7 +263,7 @@ export function projectTools() {
238
263
  projectCreate(input: $input, slackChannelName: $slackChannelName) {
239
264
  success
240
265
  project {
241
- ${PROJECT_SELECTION}
266
+ ${PROJECT_DETAIL_SELECTION}
242
267
  }
243
268
  }
244
269
  }`,
@@ -260,6 +285,7 @@ export function projectTools() {
260
285
  };
261
286
  });
262
287
  },
288
+ renderResult: renderLinearSaveProjectResult,
263
289
  }),
264
290
  defineTool({
265
291
  name: 'linear_delete_project',
@@ -268,6 +294,7 @@ export function projectTools() {
268
294
  parameters: Type.Object({
269
295
  projectId: Type.String(),
270
296
  }),
297
+ renderCall: renderLinearDeleteProjectCall,
271
298
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
272
299
  return withLinearAuth(ctx, signal, async (apiKey) => {
273
300
  const data = await linearGraphQL<{
@@ -293,6 +320,7 @@ export function projectTools() {
293
320
  };
294
321
  });
295
322
  },
323
+ renderResult: renderLinearProjectSuccessResult('Deleted'),
296
324
  }),
297
325
  defineTool({
298
326
  name: 'linear_archive_project',
@@ -302,6 +330,7 @@ export function projectTools() {
302
330
  projectId: Type.String(),
303
331
  trash: Type.Optional(Type.Boolean()),
304
332
  }),
333
+ renderCall: renderLinearArchiveProjectCall,
305
334
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
306
335
  return withLinearAuth(ctx, signal, async (apiKey) => {
307
336
  const data = await linearGraphQL<{
@@ -327,6 +356,7 @@ export function projectTools() {
327
356
  };
328
357
  });
329
358
  },
359
+ renderResult: renderLinearProjectSuccessResult('Archived'),
330
360
  }),
331
361
  defineTool({
332
362
  name: 'linear_unarchive_project',
@@ -335,6 +365,7 @@ export function projectTools() {
335
365
  parameters: Type.Object({
336
366
  projectId: Type.String(),
337
367
  }),
368
+ renderCall: renderLinearUnarchiveProjectCall,
338
369
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
339
370
  return withLinearAuth(ctx, signal, async (apiKey) => {
340
371
  const data = await linearGraphQL<{
@@ -360,6 +391,7 @@ export function projectTools() {
360
391
  };
361
392
  });
362
393
  },
394
+ renderResult: renderLinearProjectSuccessResult('Unarchived'),
363
395
  }),
364
396
  ];
365
397
  }
@@ -1,10 +1,16 @@
1
1
  import { defineTool } from '@mariozechner/pi-coding-agent';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { withLinearAuth, linearGraphQL } from '../client';
4
- import { PaginationParams, FilterParam } from '../params';
4
+ import { PaginationParams, paginationVariables, FilterParam } from '../params';
5
5
  import { TEAM_SELECTION } from '../selections';
6
- import type { LinearTeam, JsonObject } from '../types';
6
+ import type { LinearTeam, JsonObject, LinearConnection } from '../types';
7
7
  import { compactObject, asObject } from '../util';
8
+ import {
9
+ renderLinearGetTeamCall,
10
+ renderLinearTeamListCall,
11
+ renderLinearTeamListResult,
12
+ renderLinearTeamResult,
13
+ } from '../renderers/teams';
8
14
 
9
15
  export function teamTools() {
10
16
  return [
@@ -17,19 +23,15 @@ export function teamTools() {
17
23
  ...PaginationParams,
18
24
  ...FilterParam,
19
25
  }),
26
+ renderCall: renderLinearTeamListCall,
20
27
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
21
28
  return withLinearAuth(ctx, signal, async (apiKey) => {
22
29
  const variables = compactObject({
23
- after: params.after,
24
- before: params.before,
30
+ ...paginationVariables(params, 50),
25
31
  filter: asObject(params.filter),
26
- first: params.first,
27
- includeArchived: params.includeArchived,
28
- last: params.last,
29
- orderBy: params.orderBy,
30
32
  });
31
33
 
32
- const data = await linearGraphQL<{ teams: { nodes: LinearTeam[] } }>(
34
+ const data = await linearGraphQL<{ teams: LinearConnection<LinearTeam> }>(
33
35
  apiKey,
34
36
  `query ListTeams(
35
37
  $after: String
@@ -59,6 +61,12 @@ export function teamTools() {
59
61
  }
60
62
  }
61
63
  }
64
+ pageInfo {
65
+ hasNextPage
66
+ hasPreviousPage
67
+ startCursor
68
+ endCursor
69
+ }
62
70
  }
63
71
  }`,
64
72
  variables,
@@ -66,12 +74,14 @@ export function teamTools() {
66
74
  );
67
75
 
68
76
  const teams = data.teams.nodes;
77
+ const pageInfo = data.teams.pageInfo;
69
78
  return {
70
- content: [{ type: 'text', text: JSON.stringify({ teams }, null, 2) }],
71
- details: { teams },
79
+ content: [{ type: 'text', text: JSON.stringify({ teams, pageInfo }, null, 2) }],
80
+ details: { teams, pageInfo },
72
81
  };
73
82
  });
74
83
  },
84
+ renderResult: renderLinearTeamListResult,
75
85
  }),
76
86
  defineTool({
77
87
  name: 'linear_get_team',
@@ -80,6 +90,7 @@ export function teamTools() {
80
90
  parameters: Type.Object({
81
91
  teamId: Type.String(),
82
92
  }),
93
+ renderCall: renderLinearGetTeamCall,
83
94
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
84
95
  return withLinearAuth(ctx, signal, async (apiKey) => {
85
96
  const data = await linearGraphQL<{ team: JsonObject | null }>(
@@ -100,6 +111,7 @@ export function teamTools() {
100
111
  };
101
112
  });
102
113
  },
114
+ renderResult: renderLinearTeamResult('Team'),
103
115
  }),
104
116
  ];
105
117
  }
@@ -1,10 +1,16 @@
1
1
  import { defineTool } from '@mariozechner/pi-coding-agent';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { withLinearAuth, linearGraphQL } from '../client';
4
- import { PaginationParams, FilterParam, SortParam } from '../params';
4
+ import { PaginationParams, paginationVariables, FilterParam, SortParam } from '../params';
5
5
  import { USER_SELECTION } from '../selections';
6
- import type { JsonObject } from '../types';
6
+ import type { JsonObject, LinearConnection } from '../types';
7
7
  import { compactObject, asObject, asObjectArray } from '../util';
8
+ import {
9
+ renderLinearGetUserCall,
10
+ renderLinearUserListCall,
11
+ renderLinearUserListResult,
12
+ renderLinearUserResult,
13
+ } from '../renderers/users';
8
14
 
9
15
  export function userTools() {
10
16
  return [
@@ -18,22 +24,18 @@ export function userTools() {
18
24
  ...SortParam,
19
25
  includeDisabled: Type.Optional(Type.Boolean()),
20
26
  }),
27
+ renderCall: renderLinearUserListCall,
21
28
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
22
29
  return withLinearAuth(ctx, signal, async (apiKey) => {
23
30
  const variables = compactObject({
24
- after: params.after,
25
- before: params.before,
31
+ ...paginationVariables(params, 50),
26
32
  filter: asObject(params.filter),
27
- first: params.first ?? 50,
28
- includeArchived: params.includeArchived,
29
33
  includeDisabled: params.includeDisabled,
30
- last: params.last,
31
- orderBy: params.orderBy,
32
34
  sort: asObjectArray(params.sort),
33
35
  });
34
36
 
35
37
  const data = await linearGraphQL<{
36
- users: { nodes: Array<JsonObject> };
38
+ users: LinearConnection<JsonObject>;
37
39
  }>(
38
40
  apiKey,
39
41
  `query ListUsers(
@@ -61,6 +63,12 @@ export function userTools() {
61
63
  nodes {
62
64
  ${USER_SELECTION}
63
65
  }
66
+ pageInfo {
67
+ hasNextPage
68
+ hasPreviousPage
69
+ startCursor
70
+ endCursor
71
+ }
64
72
  }
65
73
  }`,
66
74
  variables,
@@ -68,12 +76,14 @@ export function userTools() {
68
76
  );
69
77
 
70
78
  const users = data.users.nodes;
79
+ const pageInfo = data.users.pageInfo;
71
80
  return {
72
- content: [{ type: 'text', text: JSON.stringify({ users }, null, 2) }],
73
- details: { users },
81
+ content: [{ type: 'text', text: JSON.stringify({ users, pageInfo }, null, 2) }],
82
+ details: { users, pageInfo },
74
83
  };
75
84
  });
76
85
  },
86
+ renderResult: renderLinearUserListResult,
77
87
  }),
78
88
  defineTool({
79
89
  name: 'linear_get_user',
@@ -82,6 +92,7 @@ export function userTools() {
82
92
  parameters: Type.Object({
83
93
  userId: Type.String(),
84
94
  }),
95
+ renderCall: renderLinearGetUserCall,
85
96
  async execute(_toolCallId, params, signal, _onUpdate, ctx) {
86
97
  return withLinearAuth(ctx, signal, async (apiKey) => {
87
98
  const data = await linearGraphQL<{ user: JsonObject | null }>(
@@ -102,6 +113,7 @@ export function userTools() {
102
113
  };
103
114
  });
104
115
  },
116
+ renderResult: renderLinearUserResult,
105
117
  }),
106
118
  ];
107
119
  }
@@ -1,6 +1,10 @@
1
1
  import { defineTool } from '@mariozechner/pi-coding-agent';
2
2
  import { Type } from '@sinclair/typebox';
3
3
  import { switchWorkspace, type WorkspaceCredentials } from '../client';
4
+ import {
5
+ renderLinearSwitchWorkspaceCall,
6
+ renderLinearSwitchWorkspaceResult,
7
+ } from '../renderers/workspaces';
4
8
 
5
9
  export function workspaceTools(creds: WorkspaceCredentials) {
6
10
  const names = Object.keys(creds.workspaces);
@@ -16,6 +20,7 @@ export function workspaceTools(creds: WorkspaceCredentials) {
16
20
  description: `Workspace name to switch to. One of: ${names.join(', ')}`,
17
21
  }),
18
22
  }),
23
+ renderCall: renderLinearSwitchWorkspaceCall,
19
24
  async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
20
25
  const updated = await switchWorkspace(params.name);
21
26
  return {
@@ -28,6 +33,7 @@ export function workspaceTools(creds: WorkspaceCredentials) {
28
33
  details: { active: updated.activeWorkspace },
29
34
  };
30
35
  },
36
+ renderResult: renderLinearSwitchWorkspaceResult,
31
37
  }),
32
38
  ];
33
39
  }
@@ -4,6 +4,18 @@ export type LinearGraphQLError = {
4
4
  message: string;
5
5
  };
6
6
 
7
+ export type LinearPageInfo = {
8
+ hasNextPage: boolean;
9
+ hasPreviousPage: boolean;
10
+ startCursor?: string | null;
11
+ endCursor?: string | null;
12
+ };
13
+
14
+ export type LinearConnection<T> = {
15
+ nodes: T[];
16
+ pageInfo: LinearPageInfo;
17
+ };
18
+
7
19
  export type LinearIssue = {
8
20
  id: string;
9
21
  identifier: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alasano/pi-linear",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "Linear integration for pi with 55+ tools, multi-workspace auth, and per-tool settings",
5
5
  "keywords": [
6
6
  "pi-package"