@fink-andreas/pi-linear-tools 0.5.0 → 0.5.1

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.5.1 (2026-04-17)
4
+
5
+ ### Bug Fixes
6
+ - **Prevent pi crashes from Linear tool errors**: Added `executeToolSafely` wrapper that catches errors and returns them as safe tool results instead of throwing, preventing pi from crashing on Linear API errors
7
+
3
8
  ## v0.5.0 (2026-04-17)
4
9
 
5
10
  Linear document sync, project lifecycle management, and estimate/story points support.
@@ -497,6 +497,40 @@ function handleToolExecutionError(error, operationLabel, options = {}) {
497
497
  throw new Error(`${operationLabel}: ${errorMessage}`);
498
498
  }
499
499
 
500
+ function buildGenericToolErrorResult(error, operationLabel) {
501
+ const errorType = error?.type || error?.name || 'Error';
502
+ const errorMessage = String(error?.message || error || 'Unknown error');
503
+
504
+ return toToolTextResult(`${operationLabel}: ${errorMessage}`, {
505
+ error: true,
506
+ errorType,
507
+ rateLimited: false,
508
+ });
509
+ }
510
+
511
+ async function executeToolSafely(operationLabel, operation, options = {}) {
512
+ try {
513
+ return await operation();
514
+ } catch (error) {
515
+ debug('[pi-linear-tools] tool execution failed', {
516
+ operationLabel,
517
+ errorType: error?.type || error?.name || null,
518
+ error: String(error?.message || error || 'unknown'),
519
+ });
520
+
521
+ try {
522
+ return handleToolExecutionError(error, operationLabel, options);
523
+ } catch (handledError) {
524
+ debug('[pi-linear-tools] returning generic safe tool error result', {
525
+ operationLabel,
526
+ errorType: handledError?.type || handledError?.name || null,
527
+ error: String(handledError?.message || handledError || 'unknown'),
528
+ });
529
+ return buildGenericToolErrorResult(handledError, operationLabel);
530
+ }
531
+ }
532
+ }
533
+
500
534
  function renderMarkdownResult(result, _options, _theme) {
501
535
  const text = result.content?.[0]?.text || '';
502
536
 
@@ -666,7 +700,7 @@ async function registerLinearTools(pi) {
666
700
  },
667
701
  renderResult: renderMarkdownResult,
668
702
  async execute(_toolCallId, params) {
669
- try {
703
+ return executeToolSafely('Linear issue operation failed', async () => {
670
704
  // Pre-check: skip API calls if we know we're rate limited
671
705
  const { isRateLimited, resetAt } = checkAndClearRateLimit();
672
706
  if (isRateLimited) {
@@ -701,38 +735,7 @@ async function registerLinearTools(pi) {
701
735
  throw new Error(`Unknown action: ${params.action}`);
702
736
  }
703
737
  });
704
- } catch (error) {
705
- // Comprehensive error handling - catch ALL errors including SDK's RatelimitedLinearError
706
- const errorType = error?.type || '';
707
- const errorMessage = String(error?.message || error || 'Unknown error');
708
-
709
- // Authentication/Forbidden errors (handles SDK's ForbiddenLinearError)
710
- if (errorType === 'Forbidden' || errorType === 'AuthenticationError' ||
711
- errorMessage.toLowerCase().includes('forbidden') || errorMessage.toLowerCase().includes('unauthorized')) {
712
- throw new Error(
713
- `Linear API authentication failed: ${errorMessage}\n\n` +
714
- `Please check your API key or OAuth token permissions.`
715
- );
716
- }
717
-
718
- // Network errors (handles SDK's NetworkError)
719
- if (errorType === 'NetworkError' || errorMessage.toLowerCase().includes('network')) {
720
- throw new Error(
721
- `Network error communicating with Linear API.\n\n` +
722
- `Please check your internet connection and try again.`
723
- );
724
- }
725
-
726
- // Internal server errors (handles SDK's InternalError)
727
- if (errorType === 'InternalError' || (error?.status >= 500 && error?.status < 600)) {
728
- throw new Error(
729
- `Linear API server error (${error?.status || 'unknown'}).\n\n` +
730
- `Linear may be experiencing issues. Please try again later.`
731
- );
732
- }
733
-
734
- return handleToolExecutionError(error, 'Linear issue operation failed');
735
- }
738
+ });
736
739
  },
737
740
  });
738
741
 
@@ -798,7 +801,7 @@ async function registerLinearTools(pi) {
798
801
  },
799
802
  renderResult: renderMarkdownResult,
800
803
  async execute(_toolCallId, params) {
801
- try {
804
+ return executeToolSafely('Linear project operation failed', async () => {
802
805
  const client = await createAuthenticatedClient();
803
806
 
804
807
  return await withRequestUsageLogging(client, 'linear_project', params.action, async () => {
@@ -821,9 +824,7 @@ async function registerLinearTools(pi) {
821
824
  throw new Error(`Unknown action: ${params.action}`);
822
825
  }
823
826
  });
824
- } catch (error) {
825
- return handleToolExecutionError(error, 'Linear project operation failed');
826
- }
827
+ });
827
828
  },
828
829
  });
829
830
 
@@ -877,7 +878,7 @@ async function registerLinearTools(pi) {
877
878
  },
878
879
  renderResult: renderMarkdownResult,
879
880
  async execute(_toolCallId, params) {
880
- try {
881
+ return executeToolSafely('Linear project update operation failed', async () => {
881
882
  const client = await createAuthenticatedClient();
882
883
 
883
884
  return await withRequestUsageLogging(client, 'linear_project_update', params.action, async () => {
@@ -898,9 +899,7 @@ async function registerLinearTools(pi) {
898
899
  throw new Error(`Unknown action: ${params.action}`);
899
900
  }
900
901
  });
901
- } catch (error) {
902
- return handleToolExecutionError(error, 'Linear project update operation failed');
903
- }
902
+ });
904
903
  },
905
904
  });
906
905
 
@@ -923,7 +922,7 @@ async function registerLinearTools(pi) {
923
922
  },
924
923
  renderResult: renderMarkdownResult,
925
924
  async execute(_toolCallId, params) {
926
- try {
925
+ return executeToolSafely('Linear team operation failed', async () => {
927
926
  const client = await createAuthenticatedClient();
928
927
 
929
928
  return await withRequestUsageLogging(client, 'linear_team', params.action, async () => {
@@ -934,9 +933,7 @@ async function registerLinearTools(pi) {
934
933
  throw new Error(`Unknown action: ${params.action}`);
935
934
  }
936
935
  });
937
- } catch (error) {
938
- return handleToolExecutionError(error, 'Linear team operation failed');
939
- }
936
+ });
940
937
  },
941
938
  });
942
939
 
@@ -980,7 +977,7 @@ async function registerLinearTools(pi) {
980
977
  },
981
978
  renderResult: renderMarkdownResult,
982
979
  async execute(_toolCallId, params) {
983
- try {
980
+ return executeToolSafely('Linear milestone operation failed', async () => {
984
981
  const client = await createAuthenticatedClient();
985
982
 
986
983
  return await withRequestUsageLogging(client, 'linear_milestone', params.action, async () => {
@@ -999,11 +996,9 @@ async function registerLinearTools(pi) {
999
996
  throw new Error(`Unknown action: ${params.action}`);
1000
997
  }
1001
998
  });
1002
- } catch (error) {
1003
- return handleToolExecutionError(error, 'Linear milestone operation failed', {
1004
- transformError: withMilestoneScopeHint,
1005
- });
1006
- }
999
+ }, {
1000
+ transformError: withMilestoneScopeHint,
1001
+ });
1007
1002
  },
1008
1003
  });
1009
1004
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fink-andreas/pi-linear-tools",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Pi extension with Linear SDK tools and configuration commands",
5
5
  "type": "module",
6
6
  "engines": {