@fink-andreas/pi-linear-tools 0.4.2 → 0.5.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/CHANGELOG.md +33 -0
- package/README.md +131 -3
- package/extensions/pi-linear-tools.js +227 -89
- package/index.js +1 -1019
- package/package.json +2 -2
- package/src/cli.js +700 -6
- package/src/handlers.js +466 -3
- package/src/linear.js +2792 -782
- package/src/sync-doc.js +1208 -0
|
@@ -48,12 +48,25 @@ try {
|
|
|
48
48
|
import {
|
|
49
49
|
executeIssueList,
|
|
50
50
|
executeIssueView,
|
|
51
|
+
executeIssueActivity,
|
|
51
52
|
executeIssueCreate,
|
|
52
53
|
executeIssueUpdate,
|
|
53
54
|
executeIssueComment,
|
|
54
55
|
executeIssueStart,
|
|
55
56
|
executeIssueDelete,
|
|
56
57
|
executeProjectList,
|
|
58
|
+
executeProjectView,
|
|
59
|
+
executeProjectCreate,
|
|
60
|
+
executeProjectUpdate,
|
|
61
|
+
executeProjectDelete,
|
|
62
|
+
executeProjectArchive,
|
|
63
|
+
executeProjectUnarchive,
|
|
64
|
+
executeProjectUpdateList,
|
|
65
|
+
executeProjectUpdateView,
|
|
66
|
+
executeProjectUpdateCreate,
|
|
67
|
+
executeProjectUpdateUpdate,
|
|
68
|
+
executeProjectUpdateArchive,
|
|
69
|
+
executeProjectUpdateUnarchive,
|
|
57
70
|
executeTeamList,
|
|
58
71
|
executeMilestoneList,
|
|
59
72
|
executeMilestoneView,
|
|
@@ -439,6 +452,51 @@ async function shouldExposeMilestoneTool() {
|
|
|
439
452
|
/**
|
|
440
453
|
* Render tool result as markdown
|
|
441
454
|
*/
|
|
455
|
+
function toToolTextResult(text, details = {}) {
|
|
456
|
+
return {
|
|
457
|
+
content: [{ type: 'text', text }],
|
|
458
|
+
details,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function buildRateLimitToolResult(error, options = {}) {
|
|
463
|
+
const { cached = false } = options;
|
|
464
|
+
const resetTimestamp = error?.requestsResetAt || Date.now() + 3600000;
|
|
465
|
+
const resetTime = new Date(resetTimestamp).toLocaleTimeString();
|
|
466
|
+
|
|
467
|
+
markRateLimited(resetTimestamp);
|
|
468
|
+
|
|
469
|
+
return toToolTextResult(
|
|
470
|
+
cached
|
|
471
|
+
? `Linear API rate limit exceeded (cached).\n\nThe rate limit resets at: ${resetTime}\n\nPlease wait before making more requests.`
|
|
472
|
+
: `Linear API rate limit exceeded.\n\nThe rate limit resets at: ${resetTime}\n\nPlease wait before making more requests, or reduce the frequency of API calls.`,
|
|
473
|
+
{
|
|
474
|
+
error: true,
|
|
475
|
+
errorType: 'Ratelimited',
|
|
476
|
+
rateLimited: true,
|
|
477
|
+
cached,
|
|
478
|
+
requestsResetAt: resetTimestamp,
|
|
479
|
+
resetTime,
|
|
480
|
+
}
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function handleToolExecutionError(error, operationLabel, options = {}) {
|
|
485
|
+
const transformedError = options.transformError ? options.transformError(error) : error;
|
|
486
|
+
const errorType = error?.type || transformedError?.type || '';
|
|
487
|
+
const errorMessage = String(transformedError?.message || transformedError || 'Unknown error');
|
|
488
|
+
|
|
489
|
+
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
490
|
+
return buildRateLimitToolResult(error);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
if (errorMessage.includes('Linear API error:')) {
|
|
494
|
+
throw transformedError;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
throw new Error(`${operationLabel}: ${errorMessage}`);
|
|
498
|
+
}
|
|
499
|
+
|
|
442
500
|
function renderMarkdownResult(result, _options, _theme) {
|
|
443
501
|
const text = result.content?.[0]?.text || '';
|
|
444
502
|
|
|
@@ -478,18 +536,19 @@ async function registerLinearTools(pi) {
|
|
|
478
536
|
pi.registerTool({
|
|
479
537
|
name: 'linear_issue',
|
|
480
538
|
label: 'Linear Issue',
|
|
481
|
-
description: 'Interact with Linear issues.
|
|
539
|
+
description: 'Interact with Linear issues.',
|
|
540
|
+
promptSnippet: 'Interact with Linear issues (list, view, activity, create, update, comment, start, delete)',
|
|
482
541
|
parameters: {
|
|
483
542
|
type: 'object',
|
|
484
543
|
properties: {
|
|
485
544
|
action: {
|
|
486
545
|
type: 'string',
|
|
487
|
-
enum: ['list', 'view', 'create', 'update', 'comment', 'start', 'delete'],
|
|
546
|
+
enum: ['list', 'view', 'activity', 'create', 'update', 'comment', 'start', 'delete'],
|
|
488
547
|
description: 'Action to perform on issue(s)',
|
|
489
548
|
},
|
|
490
549
|
issue: {
|
|
491
550
|
type: 'string',
|
|
492
|
-
description: 'Issue key (ABC-123) or Linear issue ID (for view, update, comment, start, delete)',
|
|
551
|
+
description: 'Issue key (ABC-123) or Linear issue ID (for view, activity, update, comment, start, delete)',
|
|
493
552
|
},
|
|
494
553
|
project: {
|
|
495
554
|
type: 'string',
|
|
@@ -509,8 +568,8 @@ async function registerLinearTools(pi) {
|
|
|
509
568
|
description: 'Optional explicit assignee ID alias for update/create debugging/compatibility.',
|
|
510
569
|
},
|
|
511
570
|
limit: {
|
|
512
|
-
type: '
|
|
513
|
-
description: 'Maximum number of issues to list
|
|
571
|
+
type: 'integer',
|
|
572
|
+
description: 'Maximum number of issues or activity entries to list',
|
|
514
573
|
},
|
|
515
574
|
includeComments: {
|
|
516
575
|
type: 'boolean',
|
|
@@ -525,9 +584,13 @@ async function registerLinearTools(pi) {
|
|
|
525
584
|
description: 'Issue description in markdown (for create, update)',
|
|
526
585
|
},
|
|
527
586
|
priority: {
|
|
528
|
-
type: '
|
|
587
|
+
type: 'integer',
|
|
529
588
|
description: 'Priority 0..4 (for create, update)',
|
|
530
589
|
},
|
|
590
|
+
includeArchived: {
|
|
591
|
+
type: 'boolean',
|
|
592
|
+
description: 'Include archived resources when listing activity or project updates',
|
|
593
|
+
},
|
|
531
594
|
state: {
|
|
532
595
|
type: 'string',
|
|
533
596
|
description: 'Target state name or ID (for create, update)',
|
|
@@ -568,6 +631,10 @@ async function registerLinearTools(pi) {
|
|
|
568
631
|
type: 'string',
|
|
569
632
|
description: 'For update: mark this issue as duplicate of the given issue key/ID.',
|
|
570
633
|
},
|
|
634
|
+
estimate: {
|
|
635
|
+
type: 'integer',
|
|
636
|
+
description: 'Estimate/story points for the issue (non-negative integer, for create/update)',
|
|
637
|
+
},
|
|
571
638
|
team: {
|
|
572
639
|
type: 'string',
|
|
573
640
|
description: 'Team key (e.g. ENG) or name (optional if default team configured)',
|
|
@@ -599,17 +666,13 @@ async function registerLinearTools(pi) {
|
|
|
599
666
|
},
|
|
600
667
|
renderResult: renderMarkdownResult,
|
|
601
668
|
async execute(_toolCallId, params) {
|
|
602
|
-
// Pre-check: skip API calls if we know we're rate limited
|
|
603
|
-
const { isRateLimited, resetAt } = checkAndClearRateLimit();
|
|
604
|
-
if (isRateLimited) {
|
|
605
|
-
throw new Error(
|
|
606
|
-
`Linear API rate limit exceeded (cached).\n\n` +
|
|
607
|
-
`The rate limit resets at: ${resetAt.toLocaleTimeString()}\n\n` +
|
|
608
|
-
`Please wait before making more requests.`
|
|
609
|
-
);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
669
|
try {
|
|
670
|
+
// Pre-check: skip API calls if we know we're rate limited
|
|
671
|
+
const { isRateLimited, resetAt } = checkAndClearRateLimit();
|
|
672
|
+
if (isRateLimited) {
|
|
673
|
+
return buildRateLimitToolResult({ requestsResetAt: resetAt.getTime(), type: 'Ratelimited' }, { cached: true });
|
|
674
|
+
}
|
|
675
|
+
|
|
613
676
|
const client = await createAuthenticatedClient();
|
|
614
677
|
|
|
615
678
|
return await withRequestUsageLogging(client, 'linear_issue', params.action, async () => {
|
|
@@ -618,6 +681,8 @@ async function registerLinearTools(pi) {
|
|
|
618
681
|
return await executeIssueList(client, params);
|
|
619
682
|
case 'view':
|
|
620
683
|
return await executeIssueView(client, params);
|
|
684
|
+
case 'activity':
|
|
685
|
+
return await executeIssueActivity(client, params);
|
|
621
686
|
case 'create':
|
|
622
687
|
return await executeIssueCreate(client, params, { resolveDefaultTeam });
|
|
623
688
|
case 'update':
|
|
@@ -641,18 +706,6 @@ async function registerLinearTools(pi) {
|
|
|
641
706
|
const errorType = error?.type || '';
|
|
642
707
|
const errorMessage = String(error?.message || error || 'Unknown error');
|
|
643
708
|
|
|
644
|
-
// Rate limit error - provide clear reset time and mark globally
|
|
645
|
-
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
646
|
-
const resetTimestamp = error?.requestsResetAt || (Date.now() + 3600000);
|
|
647
|
-
const resetTime = new Date(resetTimestamp).toLocaleTimeString();
|
|
648
|
-
markRateLimited(resetTimestamp);
|
|
649
|
-
throw new Error(
|
|
650
|
-
`Linear API rate limit exceeded.\n\n` +
|
|
651
|
-
`The rate limit resets at: ${resetTime}\n\n` +
|
|
652
|
-
`Please wait before making more requests, or reduce the frequency of API calls.`
|
|
653
|
-
);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
709
|
// Authentication/Forbidden errors (handles SDK's ForbiddenLinearError)
|
|
657
710
|
if (errorType === 'Forbidden' || errorType === 'AuthenticationError' ||
|
|
658
711
|
errorMessage.toLowerCase().includes('forbidden') || errorMessage.toLowerCase().includes('unauthorized')) {
|
|
@@ -678,13 +731,7 @@ async function registerLinearTools(pi) {
|
|
|
678
731
|
);
|
|
679
732
|
}
|
|
680
733
|
|
|
681
|
-
|
|
682
|
-
if (errorMessage.includes('Linear API error:')) {
|
|
683
|
-
throw error;
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// Wrap unexpected errors with context - NEVER let raw errors propagate
|
|
687
|
-
throw new Error(`Linear issue operation failed: ${errorMessage}`);
|
|
734
|
+
return handleToolExecutionError(error, 'Linear issue operation failed');
|
|
688
735
|
}
|
|
689
736
|
},
|
|
690
737
|
});
|
|
@@ -692,15 +739,59 @@ async function registerLinearTools(pi) {
|
|
|
692
739
|
pi.registerTool({
|
|
693
740
|
name: 'linear_project',
|
|
694
741
|
label: 'Linear Project',
|
|
695
|
-
description: 'Interact with Linear projects.
|
|
742
|
+
description: 'Interact with Linear projects.',
|
|
743
|
+
promptSnippet: 'Interact with Linear projects (list, view, create, update, delete, archive, unarchive)',
|
|
696
744
|
parameters: {
|
|
697
745
|
type: 'object',
|
|
698
746
|
properties: {
|
|
699
747
|
action: {
|
|
700
748
|
type: 'string',
|
|
701
|
-
enum: ['list'],
|
|
749
|
+
enum: ['list', 'view', 'create', 'update', 'delete', 'archive', 'unarchive'],
|
|
702
750
|
description: 'Action to perform on project(s)',
|
|
703
751
|
},
|
|
752
|
+
project: {
|
|
753
|
+
type: 'string',
|
|
754
|
+
description: 'Project name or ID (for view, update, delete)',
|
|
755
|
+
},
|
|
756
|
+
name: {
|
|
757
|
+
type: 'string',
|
|
758
|
+
description: 'Project name (required for create, optional for update)',
|
|
759
|
+
},
|
|
760
|
+
teams: {
|
|
761
|
+
type: 'string',
|
|
762
|
+
description: 'Comma-separated team keys or IDs (required for create, optional for update)',
|
|
763
|
+
},
|
|
764
|
+
description: {
|
|
765
|
+
type: 'string',
|
|
766
|
+
description: 'Project description in markdown',
|
|
767
|
+
},
|
|
768
|
+
lead: {
|
|
769
|
+
type: 'string',
|
|
770
|
+
description: 'Project lead user ID, "me", or "none" when updating',
|
|
771
|
+
},
|
|
772
|
+
priority: {
|
|
773
|
+
type: 'integer',
|
|
774
|
+
description: 'Priority 0-4',
|
|
775
|
+
minimum: 0,
|
|
776
|
+
maximum: 4,
|
|
777
|
+
multipleOf: 1,
|
|
778
|
+
},
|
|
779
|
+
color: {
|
|
780
|
+
type: 'string',
|
|
781
|
+
description: 'Project color (hex)',
|
|
782
|
+
},
|
|
783
|
+
icon: {
|
|
784
|
+
type: 'string',
|
|
785
|
+
description: 'Project icon',
|
|
786
|
+
},
|
|
787
|
+
startDate: {
|
|
788
|
+
type: 'string',
|
|
789
|
+
description: 'Planned start date (YYYY-MM-DD)',
|
|
790
|
+
},
|
|
791
|
+
targetDate: {
|
|
792
|
+
type: 'string',
|
|
793
|
+
description: 'Planned target date (YYYY-MM-DD)',
|
|
794
|
+
},
|
|
704
795
|
},
|
|
705
796
|
required: ['action'],
|
|
706
797
|
additionalProperties: false,
|
|
@@ -714,27 +805,101 @@ async function registerLinearTools(pi) {
|
|
|
714
805
|
switch (params.action) {
|
|
715
806
|
case 'list':
|
|
716
807
|
return await executeProjectList(client);
|
|
808
|
+
case 'view':
|
|
809
|
+
return await executeProjectView(client, params);
|
|
810
|
+
case 'create':
|
|
811
|
+
return await executeProjectCreate(client, params);
|
|
812
|
+
case 'update':
|
|
813
|
+
return await executeProjectUpdate(client, params);
|
|
814
|
+
case 'delete':
|
|
815
|
+
return await executeProjectDelete(client, params);
|
|
816
|
+
case 'archive':
|
|
817
|
+
return await executeProjectArchive(client, params);
|
|
818
|
+
case 'unarchive':
|
|
819
|
+
return await executeProjectUnarchive(client, params);
|
|
717
820
|
default:
|
|
718
821
|
throw new Error(`Unknown action: ${params.action}`);
|
|
719
822
|
}
|
|
720
823
|
});
|
|
721
824
|
} catch (error) {
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
727
|
-
const resetAt = error?.requestsResetAt
|
|
728
|
-
? new Date(error.requestsResetAt).toLocaleTimeString()
|
|
729
|
-
: 'approximately 1 hour from now';
|
|
730
|
-
throw new Error(`Linear API rate limit exceeded. Resets at: ${resetAt}. Please wait before retrying.`);
|
|
731
|
-
}
|
|
825
|
+
return handleToolExecutionError(error, 'Linear project operation failed');
|
|
826
|
+
}
|
|
827
|
+
},
|
|
828
|
+
});
|
|
732
829
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
830
|
+
pi.registerTool({
|
|
831
|
+
name: 'linear_project_update',
|
|
832
|
+
label: 'Linear Project Update',
|
|
833
|
+
description: 'Interact with Linear project updates.',
|
|
834
|
+
promptSnippet: 'Interact with Linear project updates (list, view, create, update, archive, unarchive)',
|
|
835
|
+
parameters: {
|
|
836
|
+
type: 'object',
|
|
837
|
+
properties: {
|
|
838
|
+
action: {
|
|
839
|
+
type: 'string',
|
|
840
|
+
enum: ['list', 'view', 'create', 'update', 'archive', 'unarchive'],
|
|
841
|
+
description: 'Action to perform on project update(s)',
|
|
842
|
+
},
|
|
843
|
+
project: {
|
|
844
|
+
type: 'string',
|
|
845
|
+
description: 'Project name or ID (for list, create)',
|
|
846
|
+
},
|
|
847
|
+
projectUpdate: {
|
|
848
|
+
type: 'string',
|
|
849
|
+
description: 'Project update ID (for view, update, archive, unarchive)',
|
|
850
|
+
},
|
|
851
|
+
body: {
|
|
852
|
+
type: 'string',
|
|
853
|
+
description: 'Project update body in markdown',
|
|
854
|
+
},
|
|
855
|
+
health: {
|
|
856
|
+
type: 'string',
|
|
857
|
+
description: 'Project update health: onTrack, atRisk, or offTrack',
|
|
858
|
+
enum: ['onTrack', 'atRisk', 'offTrack'],
|
|
859
|
+
},
|
|
860
|
+
isDiffHidden: {
|
|
861
|
+
type: 'boolean',
|
|
862
|
+
description: 'Whether to hide the diff on the update',
|
|
863
|
+
},
|
|
864
|
+
limit: {
|
|
865
|
+
type: 'integer',
|
|
866
|
+
description: 'Max updates to list',
|
|
867
|
+
minimum: 1,
|
|
868
|
+
multipleOf: 1,
|
|
869
|
+
},
|
|
870
|
+
includeArchived: {
|
|
871
|
+
type: 'boolean',
|
|
872
|
+
description: 'Whether archived updates should be included when listing',
|
|
873
|
+
},
|
|
874
|
+
},
|
|
875
|
+
required: ['action'],
|
|
876
|
+
additionalProperties: false,
|
|
877
|
+
},
|
|
878
|
+
renderResult: renderMarkdownResult,
|
|
879
|
+
async execute(_toolCallId, params) {
|
|
880
|
+
try {
|
|
881
|
+
const client = await createAuthenticatedClient();
|
|
736
882
|
|
|
737
|
-
|
|
883
|
+
return await withRequestUsageLogging(client, 'linear_project_update', params.action, async () => {
|
|
884
|
+
switch (params.action) {
|
|
885
|
+
case 'list':
|
|
886
|
+
return await executeProjectUpdateList(client, params);
|
|
887
|
+
case 'view':
|
|
888
|
+
return await executeProjectUpdateView(client, params);
|
|
889
|
+
case 'create':
|
|
890
|
+
return await executeProjectUpdateCreate(client, params);
|
|
891
|
+
case 'update':
|
|
892
|
+
return await executeProjectUpdateUpdate(client, params);
|
|
893
|
+
case 'archive':
|
|
894
|
+
return await executeProjectUpdateArchive(client, params);
|
|
895
|
+
case 'unarchive':
|
|
896
|
+
return await executeProjectUpdateUnarchive(client, params);
|
|
897
|
+
default:
|
|
898
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
} catch (error) {
|
|
902
|
+
return handleToolExecutionError(error, 'Linear project update operation failed');
|
|
738
903
|
}
|
|
739
904
|
},
|
|
740
905
|
});
|
|
@@ -742,7 +907,8 @@ async function registerLinearTools(pi) {
|
|
|
742
907
|
pi.registerTool({
|
|
743
908
|
name: 'linear_team',
|
|
744
909
|
label: 'Linear Team',
|
|
745
|
-
description: 'Interact with Linear teams.
|
|
910
|
+
description: 'Interact with Linear teams.',
|
|
911
|
+
promptSnippet: 'Interact with Linear teams (list)',
|
|
746
912
|
parameters: {
|
|
747
913
|
type: 'object',
|
|
748
914
|
properties: {
|
|
@@ -769,22 +935,7 @@ async function registerLinearTools(pi) {
|
|
|
769
935
|
}
|
|
770
936
|
});
|
|
771
937
|
} catch (error) {
|
|
772
|
-
|
|
773
|
-
const errorType = error?.type || '';
|
|
774
|
-
const errorMessage = String(error?.message || error || 'Unknown error');
|
|
775
|
-
|
|
776
|
-
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
777
|
-
const resetAt = error?.requestsResetAt
|
|
778
|
-
? new Date(error.requestsResetAt).toLocaleTimeString()
|
|
779
|
-
: 'approximately 1 hour from now';
|
|
780
|
-
throw new Error(`Linear API rate limit exceeded. Resets at: ${resetAt}. Please wait before retrying.`);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
if (errorMessage.includes('Linear API error:')) {
|
|
784
|
-
throw error;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
throw new Error(`Linear team operation failed: ${errorMessage}`);
|
|
938
|
+
return handleToolExecutionError(error, 'Linear team operation failed');
|
|
788
939
|
}
|
|
789
940
|
},
|
|
790
941
|
});
|
|
@@ -793,7 +944,8 @@ async function registerLinearTools(pi) {
|
|
|
793
944
|
pi.registerTool({
|
|
794
945
|
name: 'linear_milestone',
|
|
795
946
|
label: 'Linear Milestone',
|
|
796
|
-
description: 'Interact with Linear project milestones.
|
|
947
|
+
description: 'Interact with Linear project milestones.',
|
|
948
|
+
promptSnippet: 'Interact with Linear milestones (list, view, create, update, delete)',
|
|
797
949
|
parameters: {
|
|
798
950
|
type: 'object',
|
|
799
951
|
properties: {
|
|
@@ -848,24 +1000,9 @@ async function registerLinearTools(pi) {
|
|
|
848
1000
|
}
|
|
849
1001
|
});
|
|
850
1002
|
} catch (error) {
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const errorType = error?.type || '';
|
|
855
|
-
const errorMessage = String(hintError?.message || hintError || 'Unknown error');
|
|
856
|
-
|
|
857
|
-
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
858
|
-
const resetAt = error?.requestsResetAt
|
|
859
|
-
? new Date(error.requestsResetAt).toLocaleTimeString()
|
|
860
|
-
: 'approximately 1 hour from now';
|
|
861
|
-
throw new Error(`Linear API rate limit exceeded. Resets at: ${resetAt}. Please wait before retrying.`);
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
if (errorMessage.includes('Linear API error:')) {
|
|
865
|
-
throw hintError;
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
throw new Error(`Linear milestone operation failed: ${errorMessage}`);
|
|
1003
|
+
return handleToolExecutionError(error, 'Linear milestone operation failed', {
|
|
1004
|
+
transformError: withMilestoneScopeHint,
|
|
1005
|
+
});
|
|
869
1006
|
}
|
|
870
1007
|
},
|
|
871
1008
|
});
|
|
@@ -983,8 +1120,9 @@ export default async function piLinearToolsExtension(pi) {
|
|
|
983
1120
|
const showMilestoneTool = await shouldExposeMilestoneTool();
|
|
984
1121
|
const toolLines = [
|
|
985
1122
|
'LLM-callable tools:',
|
|
986
|
-
' linear_issue (list/view/create/update/comment/start/delete)',
|
|
987
|
-
' linear_project (list)',
|
|
1123
|
+
' linear_issue (list/view/activity/create/update/comment/start/delete)',
|
|
1124
|
+
' linear_project (list/view/create/update/delete/archive/unarchive)',
|
|
1125
|
+
' linear_project_update (list/view/create/update/archive/unarchive)',
|
|
988
1126
|
' linear_team (list)',
|
|
989
1127
|
];
|
|
990
1128
|
|