@fink-andreas/pi-linear-tools 0.4.1 → 0.4.3
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 +37 -0
- package/README.md +139 -13
- package/extensions/pi-linear-tools.js +298 -60
- package/index.js +1 -951
- package/package.json +6 -2
- package/src/cli.js +703 -7
- package/src/handlers.js +429 -4
- package/src/linear-client.js +7 -2
- package/src/linear.js +1502 -152
- package/src/sync-doc.js +1208 -0
- package/FUNCTIONALITY.md +0 -57
- package/POST_RELEASE_CHECKLIST.md +0 -30
- package/RELEASE.md +0 -50
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loadSettings, saveSettings } from '../src/settings.js';
|
|
2
|
-
import { createLinearClient, checkAndClearRateLimit, markRateLimited } from '../src/linear-client.js';
|
|
3
|
-
import { setQuietMode } from '../src/logger.js';
|
|
2
|
+
import { createLinearClient, checkAndClearRateLimit, markRateLimited, getClientRequestMetrics } from '../src/linear-client.js';
|
|
3
|
+
import { setQuietMode, debug } from '../src/logger.js';
|
|
4
4
|
import {
|
|
5
5
|
resolveProjectRef,
|
|
6
6
|
fetchTeams,
|
|
@@ -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,
|
|
@@ -65,6 +78,7 @@ import { authenticate, getAccessToken, logout } from '../src/auth/index.js';
|
|
|
65
78
|
import { withMilestoneScopeHint } from '../src/error-hints.js';
|
|
66
79
|
|
|
67
80
|
let cachedApiKey = null;
|
|
81
|
+
const INCLUDE_USAGE_SUMMARY = String(process.env.PI_LINEAR_TOOLS_USAGE_SUMMARY || '').toLowerCase() === 'true';
|
|
68
82
|
|
|
69
83
|
async function getLinearAuth() {
|
|
70
84
|
const envKey = process.env.LINEAR_API_KEY;
|
|
@@ -106,6 +120,65 @@ async function createAuthenticatedClient() {
|
|
|
106
120
|
return createLinearClient(await getLinearAuth());
|
|
107
121
|
}
|
|
108
122
|
|
|
123
|
+
async function withRequestUsageLogging(client, toolName, action, operation) {
|
|
124
|
+
const before = getClientRequestMetrics(client);
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
const result = await operation();
|
|
128
|
+
const after = getClientRequestMetrics(client);
|
|
129
|
+
|
|
130
|
+
const usageDelta = {
|
|
131
|
+
tool: toolName,
|
|
132
|
+
action,
|
|
133
|
+
requestsDelta: after.total - before.total,
|
|
134
|
+
successDelta: after.success - before.success,
|
|
135
|
+
failedDelta: after.failed - before.failed,
|
|
136
|
+
rateLimitedDelta: after.rateLimited - before.rateLimited,
|
|
137
|
+
summary: `Linear API usage: ${after.total - before.total} req (${after.success - before.success} ok, ${after.failed - before.failed} failed, ${after.rateLimited - before.rateLimited} rate-limited)`,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
debug('[pi-linear-tools] API usage per command', usageDelta);
|
|
141
|
+
|
|
142
|
+
if (!INCLUDE_USAGE_SUMMARY || !result || typeof result !== 'object') {
|
|
143
|
+
return result;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const details = (result.details && typeof result.details === 'object') ? result.details : {};
|
|
147
|
+
const content = Array.isArray(result.content)
|
|
148
|
+
? result.content.map((item, idx) => {
|
|
149
|
+
if (idx !== 0 || item?.type !== 'text' || typeof item.text !== 'string') return item;
|
|
150
|
+
return {
|
|
151
|
+
...item,
|
|
152
|
+
text: `${item.text}\n\n_${usageDelta.summary}_`,
|
|
153
|
+
};
|
|
154
|
+
})
|
|
155
|
+
: result.content;
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
...result,
|
|
159
|
+
content,
|
|
160
|
+
details: {
|
|
161
|
+
...details,
|
|
162
|
+
apiUsage: usageDelta,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
const after = getClientRequestMetrics(client);
|
|
167
|
+
|
|
168
|
+
debug('[pi-linear-tools] API usage per command (error)', {
|
|
169
|
+
tool: toolName,
|
|
170
|
+
action,
|
|
171
|
+
requestsDelta: after.total - before.total,
|
|
172
|
+
successDelta: after.success - before.success,
|
|
173
|
+
failedDelta: after.failed - before.failed,
|
|
174
|
+
rateLimitedDelta: after.rateLimited - before.rateLimited,
|
|
175
|
+
error: String(error?.message || error || 'unknown'),
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
109
182
|
async function resolveDefaultTeam(projectId) {
|
|
110
183
|
const settings = await loadSettings();
|
|
111
184
|
|
|
@@ -418,18 +491,19 @@ async function registerLinearTools(pi) {
|
|
|
418
491
|
pi.registerTool({
|
|
419
492
|
name: 'linear_issue',
|
|
420
493
|
label: 'Linear Issue',
|
|
421
|
-
description: 'Interact with Linear issues. Actions: list, view, create, update, comment, start, delete',
|
|
494
|
+
description: 'Interact with Linear issues. Actions: list, view, activity, create, update, comment, start, delete',
|
|
495
|
+
promptSnippet: 'Interact with Linear issues (list, view, activity, create, update, comment, start, delete)',
|
|
422
496
|
parameters: {
|
|
423
497
|
type: 'object',
|
|
424
498
|
properties: {
|
|
425
499
|
action: {
|
|
426
500
|
type: 'string',
|
|
427
|
-
enum: ['list', 'view', 'create', 'update', 'comment', 'start', 'delete'],
|
|
501
|
+
enum: ['list', 'view', 'activity', 'create', 'update', 'comment', 'start', 'delete'],
|
|
428
502
|
description: 'Action to perform on issue(s)',
|
|
429
503
|
},
|
|
430
504
|
issue: {
|
|
431
505
|
type: 'string',
|
|
432
|
-
description: 'Issue key (ABC-123) or Linear issue ID (for view, update, comment, start, delete)',
|
|
506
|
+
description: 'Issue key (ABC-123) or Linear issue ID (for view, activity, update, comment, start, delete)',
|
|
433
507
|
},
|
|
434
508
|
project: {
|
|
435
509
|
type: 'string',
|
|
@@ -449,8 +523,8 @@ async function registerLinearTools(pi) {
|
|
|
449
523
|
description: 'Optional explicit assignee ID alias for update/create debugging/compatibility.',
|
|
450
524
|
},
|
|
451
525
|
limit: {
|
|
452
|
-
type: '
|
|
453
|
-
description: 'Maximum number of issues to list
|
|
526
|
+
type: 'integer',
|
|
527
|
+
description: 'Maximum number of issues or activity entries to list',
|
|
454
528
|
},
|
|
455
529
|
includeComments: {
|
|
456
530
|
type: 'boolean',
|
|
@@ -465,9 +539,13 @@ async function registerLinearTools(pi) {
|
|
|
465
539
|
description: 'Issue description in markdown (for create, update)',
|
|
466
540
|
},
|
|
467
541
|
priority: {
|
|
468
|
-
type: '
|
|
542
|
+
type: 'integer',
|
|
469
543
|
description: 'Priority 0..4 (for create, update)',
|
|
470
544
|
},
|
|
545
|
+
includeArchived: {
|
|
546
|
+
type: 'boolean',
|
|
547
|
+
description: 'Include archived resources when listing activity or project updates',
|
|
548
|
+
},
|
|
471
549
|
state: {
|
|
472
550
|
type: 'string',
|
|
473
551
|
description: 'Target state name or ID (for create, update)',
|
|
@@ -552,28 +630,32 @@ async function registerLinearTools(pi) {
|
|
|
552
630
|
try {
|
|
553
631
|
const client = await createAuthenticatedClient();
|
|
554
632
|
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
633
|
+
return await withRequestUsageLogging(client, 'linear_issue', params.action, async () => {
|
|
634
|
+
switch (params.action) {
|
|
635
|
+
case 'list':
|
|
636
|
+
return await executeIssueList(client, params);
|
|
637
|
+
case 'view':
|
|
638
|
+
return await executeIssueView(client, params);
|
|
639
|
+
case 'activity':
|
|
640
|
+
return await executeIssueActivity(client, params);
|
|
641
|
+
case 'create':
|
|
642
|
+
return await executeIssueCreate(client, params, { resolveDefaultTeam });
|
|
643
|
+
case 'update':
|
|
644
|
+
return await executeIssueUpdate(client, params);
|
|
645
|
+
case 'comment':
|
|
646
|
+
return await executeIssueComment(client, params);
|
|
647
|
+
case 'start':
|
|
648
|
+
return await executeIssueStart(client, params, {
|
|
649
|
+
gitExecutor: async (branchName, fromRef, onBranchExists) => {
|
|
650
|
+
return startGitBranchForIssue(pi, branchName, fromRef, onBranchExists);
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
case 'delete':
|
|
654
|
+
return await executeIssueDelete(client, params);
|
|
655
|
+
default:
|
|
656
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
657
|
+
}
|
|
658
|
+
});
|
|
577
659
|
} catch (error) {
|
|
578
660
|
// Comprehensive error handling - catch ALL errors including SDK's RatelimitedLinearError
|
|
579
661
|
const errorType = error?.type || '';
|
|
@@ -630,15 +712,59 @@ async function registerLinearTools(pi) {
|
|
|
630
712
|
pi.registerTool({
|
|
631
713
|
name: 'linear_project',
|
|
632
714
|
label: 'Linear Project',
|
|
633
|
-
description: 'Interact with Linear projects. Actions: list',
|
|
715
|
+
description: 'Interact with Linear projects. Actions: list, view, create, update, delete, archive, unarchive',
|
|
716
|
+
promptSnippet: 'Interact with Linear projects (list, view, create, update, delete, archive, unarchive)',
|
|
634
717
|
parameters: {
|
|
635
718
|
type: 'object',
|
|
636
719
|
properties: {
|
|
637
720
|
action: {
|
|
638
721
|
type: 'string',
|
|
639
|
-
enum: ['list'],
|
|
722
|
+
enum: ['list', 'view', 'create', 'update', 'delete', 'archive', 'unarchive'],
|
|
640
723
|
description: 'Action to perform on project(s)',
|
|
641
724
|
},
|
|
725
|
+
project: {
|
|
726
|
+
type: 'string',
|
|
727
|
+
description: 'Project name or ID (for view, update, delete)',
|
|
728
|
+
},
|
|
729
|
+
name: {
|
|
730
|
+
type: 'string',
|
|
731
|
+
description: 'Project name (required for create, optional for update)',
|
|
732
|
+
},
|
|
733
|
+
teams: {
|
|
734
|
+
type: 'string',
|
|
735
|
+
description: 'Comma-separated team keys or IDs (required for create, optional for update)',
|
|
736
|
+
},
|
|
737
|
+
description: {
|
|
738
|
+
type: 'string',
|
|
739
|
+
description: 'Project description in markdown',
|
|
740
|
+
},
|
|
741
|
+
lead: {
|
|
742
|
+
type: 'string',
|
|
743
|
+
description: 'Project lead user ID, "me", or "none" when updating',
|
|
744
|
+
},
|
|
745
|
+
priority: {
|
|
746
|
+
type: 'integer',
|
|
747
|
+
description: 'Priority 0-4',
|
|
748
|
+
minimum: 0,
|
|
749
|
+
maximum: 4,
|
|
750
|
+
multipleOf: 1,
|
|
751
|
+
},
|
|
752
|
+
color: {
|
|
753
|
+
type: 'string',
|
|
754
|
+
description: 'Project color (hex)',
|
|
755
|
+
},
|
|
756
|
+
icon: {
|
|
757
|
+
type: 'string',
|
|
758
|
+
description: 'Project icon',
|
|
759
|
+
},
|
|
760
|
+
startDate: {
|
|
761
|
+
type: 'string',
|
|
762
|
+
description: 'Planned start date (YYYY-MM-DD)',
|
|
763
|
+
},
|
|
764
|
+
targetDate: {
|
|
765
|
+
type: 'string',
|
|
766
|
+
description: 'Planned target date (YYYY-MM-DD)',
|
|
767
|
+
},
|
|
642
768
|
},
|
|
643
769
|
required: ['action'],
|
|
644
770
|
additionalProperties: false,
|
|
@@ -648,12 +774,26 @@ async function registerLinearTools(pi) {
|
|
|
648
774
|
try {
|
|
649
775
|
const client = await createAuthenticatedClient();
|
|
650
776
|
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
777
|
+
return await withRequestUsageLogging(client, 'linear_project', params.action, async () => {
|
|
778
|
+
switch (params.action) {
|
|
779
|
+
case 'list':
|
|
780
|
+
return await executeProjectList(client);
|
|
781
|
+
case 'view':
|
|
782
|
+
return await executeProjectView(client, params);
|
|
783
|
+
case 'create':
|
|
784
|
+
return await executeProjectCreate(client, params);
|
|
785
|
+
case 'update':
|
|
786
|
+
return await executeProjectUpdate(client, params);
|
|
787
|
+
case 'delete':
|
|
788
|
+
return await executeProjectDelete(client, params);
|
|
789
|
+
case 'archive':
|
|
790
|
+
return await executeProjectArchive(client, params);
|
|
791
|
+
case 'unarchive':
|
|
792
|
+
return await executeProjectUnarchive(client, params);
|
|
793
|
+
default:
|
|
794
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
795
|
+
}
|
|
796
|
+
});
|
|
657
797
|
} catch (error) {
|
|
658
798
|
// Comprehensive error handling - catch ALL errors
|
|
659
799
|
const errorType = error?.type || '';
|
|
@@ -675,10 +815,102 @@ async function registerLinearTools(pi) {
|
|
|
675
815
|
},
|
|
676
816
|
});
|
|
677
817
|
|
|
818
|
+
pi.registerTool({
|
|
819
|
+
name: 'linear_project_update',
|
|
820
|
+
label: 'Linear Project Update',
|
|
821
|
+
description: 'Interact with Linear project updates. Actions: list, view, create, update, archive, unarchive',
|
|
822
|
+
promptSnippet: 'Interact with Linear project updates (list, view, create, update, archive, unarchive)',
|
|
823
|
+
parameters: {
|
|
824
|
+
type: 'object',
|
|
825
|
+
properties: {
|
|
826
|
+
action: {
|
|
827
|
+
type: 'string',
|
|
828
|
+
enum: ['list', 'view', 'create', 'update', 'archive', 'unarchive'],
|
|
829
|
+
description: 'Action to perform on project update(s)',
|
|
830
|
+
},
|
|
831
|
+
project: {
|
|
832
|
+
type: 'string',
|
|
833
|
+
description: 'Project name or ID (for list, create)',
|
|
834
|
+
},
|
|
835
|
+
projectUpdate: {
|
|
836
|
+
type: 'string',
|
|
837
|
+
description: 'Project update ID (for view, update, archive, unarchive)',
|
|
838
|
+
},
|
|
839
|
+
body: {
|
|
840
|
+
type: 'string',
|
|
841
|
+
description: 'Project update body in markdown',
|
|
842
|
+
},
|
|
843
|
+
health: {
|
|
844
|
+
type: 'string',
|
|
845
|
+
description: 'Project update health: onTrack, atRisk, or offTrack',
|
|
846
|
+
enum: ['onTrack', 'atRisk', 'offTrack'],
|
|
847
|
+
},
|
|
848
|
+
isDiffHidden: {
|
|
849
|
+
type: 'boolean',
|
|
850
|
+
description: 'Whether to hide the diff on the update',
|
|
851
|
+
},
|
|
852
|
+
limit: {
|
|
853
|
+
type: 'integer',
|
|
854
|
+
description: 'Max updates to list',
|
|
855
|
+
minimum: 1,
|
|
856
|
+
multipleOf: 1,
|
|
857
|
+
},
|
|
858
|
+
includeArchived: {
|
|
859
|
+
type: 'boolean',
|
|
860
|
+
description: 'Whether archived updates should be included when listing',
|
|
861
|
+
},
|
|
862
|
+
},
|
|
863
|
+
required: ['action'],
|
|
864
|
+
additionalProperties: false,
|
|
865
|
+
},
|
|
866
|
+
renderResult: renderMarkdownResult,
|
|
867
|
+
async execute(_toolCallId, params) {
|
|
868
|
+
try {
|
|
869
|
+
const client = await createAuthenticatedClient();
|
|
870
|
+
|
|
871
|
+
return await withRequestUsageLogging(client, 'linear_project_update', params.action, async () => {
|
|
872
|
+
switch (params.action) {
|
|
873
|
+
case 'list':
|
|
874
|
+
return await executeProjectUpdateList(client, params);
|
|
875
|
+
case 'view':
|
|
876
|
+
return await executeProjectUpdateView(client, params);
|
|
877
|
+
case 'create':
|
|
878
|
+
return await executeProjectUpdateCreate(client, params);
|
|
879
|
+
case 'update':
|
|
880
|
+
return await executeProjectUpdateUpdate(client, params);
|
|
881
|
+
case 'archive':
|
|
882
|
+
return await executeProjectUpdateArchive(client, params);
|
|
883
|
+
case 'unarchive':
|
|
884
|
+
return await executeProjectUpdateUnarchive(client, params);
|
|
885
|
+
default:
|
|
886
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
} catch (error) {
|
|
890
|
+
const errorType = error?.type || '';
|
|
891
|
+
const errorMessage = String(error?.message || error || 'Unknown error');
|
|
892
|
+
|
|
893
|
+
if (errorType === 'Ratelimited' || errorMessage.toLowerCase().includes('rate limit')) {
|
|
894
|
+
const resetAt = error?.requestsResetAt
|
|
895
|
+
? new Date(error.requestsResetAt).toLocaleTimeString()
|
|
896
|
+
: 'approximately 1 hour from now';
|
|
897
|
+
throw new Error(`Linear API rate limit exceeded. Resets at: ${resetAt}. Please wait before retrying.`);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
if (errorMessage.includes('Linear API error:')) {
|
|
901
|
+
throw error;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
throw new Error(`Linear project update operation failed: ${errorMessage}`);
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
});
|
|
908
|
+
|
|
678
909
|
pi.registerTool({
|
|
679
910
|
name: 'linear_team',
|
|
680
911
|
label: 'Linear Team',
|
|
681
912
|
description: 'Interact with Linear teams. Actions: list',
|
|
913
|
+
promptSnippet: 'Interact with Linear teams (list)',
|
|
682
914
|
parameters: {
|
|
683
915
|
type: 'object',
|
|
684
916
|
properties: {
|
|
@@ -696,12 +928,14 @@ async function registerLinearTools(pi) {
|
|
|
696
928
|
try {
|
|
697
929
|
const client = await createAuthenticatedClient();
|
|
698
930
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
931
|
+
return await withRequestUsageLogging(client, 'linear_team', params.action, async () => {
|
|
932
|
+
switch (params.action) {
|
|
933
|
+
case 'list':
|
|
934
|
+
return await executeTeamList(client);
|
|
935
|
+
default:
|
|
936
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
937
|
+
}
|
|
938
|
+
});
|
|
705
939
|
} catch (error) {
|
|
706
940
|
// Comprehensive error handling - catch ALL errors
|
|
707
941
|
const errorType = error?.type || '';
|
|
@@ -728,6 +962,7 @@ async function registerLinearTools(pi) {
|
|
|
728
962
|
name: 'linear_milestone',
|
|
729
963
|
label: 'Linear Milestone',
|
|
730
964
|
description: 'Interact with Linear project milestones. Actions: list, view, create, update, delete',
|
|
965
|
+
promptSnippet: 'Interact with Linear milestones (list, view, create, update, delete)',
|
|
731
966
|
parameters: {
|
|
732
967
|
type: 'object',
|
|
733
968
|
properties: {
|
|
@@ -765,20 +1000,22 @@ async function registerLinearTools(pi) {
|
|
|
765
1000
|
try {
|
|
766
1001
|
const client = await createAuthenticatedClient();
|
|
767
1002
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
1003
|
+
return await withRequestUsageLogging(client, 'linear_milestone', params.action, async () => {
|
|
1004
|
+
switch (params.action) {
|
|
1005
|
+
case 'list':
|
|
1006
|
+
return await executeMilestoneList(client, params);
|
|
1007
|
+
case 'view':
|
|
1008
|
+
return await executeMilestoneView(client, params);
|
|
1009
|
+
case 'create':
|
|
1010
|
+
return await executeMilestoneCreate(client, params);
|
|
1011
|
+
case 'update':
|
|
1012
|
+
return await executeMilestoneUpdate(client, params);
|
|
1013
|
+
case 'delete':
|
|
1014
|
+
return await executeMilestoneDelete(client, params);
|
|
1015
|
+
default:
|
|
1016
|
+
throw new Error(`Unknown action: ${params.action}`);
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
782
1019
|
} catch (error) {
|
|
783
1020
|
// Apply milestone-specific hint, then wrap with operation context
|
|
784
1021
|
const hintError = withMilestoneScopeHint(error);
|
|
@@ -915,8 +1152,9 @@ export default async function piLinearToolsExtension(pi) {
|
|
|
915
1152
|
const showMilestoneTool = await shouldExposeMilestoneTool();
|
|
916
1153
|
const toolLines = [
|
|
917
1154
|
'LLM-callable tools:',
|
|
918
|
-
' linear_issue (list/view/create/update/comment/start/delete)',
|
|
919
|
-
' linear_project (list)',
|
|
1155
|
+
' linear_issue (list/view/activity/create/update/comment/start/delete)',
|
|
1156
|
+
' linear_project (list/view/create/update/delete/archive/unarchive)',
|
|
1157
|
+
' linear_project_update (list/view/create/update/archive/unarchive)',
|
|
920
1158
|
' linear_team (list)',
|
|
921
1159
|
];
|
|
922
1160
|
|