agentsclimarketplace

Linear upgrade migration

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/saas-packs/linear-pack/skills/linear-upgrade-migration

'Upgrade Linear SDK versions and handle breaking changes safely.From its SKILL.md

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill linear-upgrade-migration

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

6.9 KB, ~1.6k tokens by cl100k_base, as published. Nobody here has run it

Linear Upgrade Migration

Overview

Safely upgrade @linear/sdk versions with zero downtime. The SDK is auto-generated from Linear's GraphQL schema -- major versions can rename fields, change return types, add required parameters, or remove deprecated methods. This skill covers version checking, upgrade procedure, compatibility layers, and rollback.

Prerequisites

  • Existing Linear integration with version control (Git)
  • Test suite covering Linear SDK operations
  • Understanding of semantic versioning

Instructions

Step 1: Check Current vs Latest Version

set -euo pipefail
# Current installed version
npm list @linear/sdk 2>/dev/null || echo "Not installed"

# Latest available
npm view @linear/sdk version

# All recent versions
npm view @linear/sdk versions --json | jq '.[-10:]'

Step 2: Review Changelog for Breaking Changes

set -euo pipefail
# View SDK changelog on GitHub
npm view @linear/sdk repository.url
# Then check: https://github.com/linear/linear/blob/master/packages/sdk/CHANGELOG.md

# Also review Linear's API changelog:
# https://linear.app/changelog (filter for API/developer updates)

Common breaking changes between major versions:

  • Renamed fields: e.g., issue.state property vs lazy relation
  • Changed return types: direct value to paginated connection
  • New required parameters: mutations gaining mandatory fields
  • Removed methods: deprecated methods dropped
  • ESM/CJS: module system changes

Step 3: Create Upgrade Branch and Install

set -euo pipefail
git checkout -b upgrade/linear-sdk-$(npm view @linear/sdk version)
npm install @linear/sdk@latest

# Immediately check for type errors
npx tsc --noEmit 2>&1 | head -50

Step 4: Fix Type Errors with Compatibility Layer

// src/linear-compat.ts
// Bridge pattern for gradual migration across SDK versions

import { LinearClient } from "@linear/sdk";

/**
 * Normalize issue state access across SDK versions.
 * SDK v2: issue.state was a direct string property
 * SDK v3+: issue.state is a lazy-loaded WorkflowState relation
 */
export async function getIssueStateName(issue: any): Promise<string> {
  if (typeof issue.state === "string") return issue.state;
  const state = await issue.state;
  return state?.name ?? "unknown";
}

export async function getIssueStateType(issue: any): Promise<string> {
  if (typeof issue.stateType === "string") return issue.stateType;
  const state = await issue.state;
  return state?.type ?? "unknown";
}

/**
 * Normalize team access — some versions changed from direct to paginated.
 */
export async function getTeamByKey(client: LinearClient, key: string) {
  const teams = await client.teams({ filter: { key: { eq: key } } });
  return teams.nodes[0];
}

/**
 * Normalize issue creation return — handle both success shapes.
 */
export async function createIssue(
  client: LinearClient,
  input: { teamId: string; title: string; [key: string]: any }
) {
  const result = await client.createIssue(input);
  // Some versions return { success, issue } others return directly
  if ("success" in result) {
    return { success: result.success, issue: await result.issue };
  }
  return { success: true, issue: result };
}

Step 5: Run Tests and Fix Failures

set -euo pipefail
# Type-check
npx tsc --noEmit

# Run unit tests
npm test

# Run integration tests (if API key available)
npm run test:integration 2>&1 || true

# Lint
npm run lint 2>&1 || true

Common fixes:

// Fix: Property 'x' does not exist
// Old: issue.statusName
// New: (await issue.state)?.name

// Fix: Type 'X' is not assignable to type 'Y'
// Old: const states: string[] = team.states
// New: const states = await team.states()

// Fix: Expected 2 arguments but got 1
// Check if mutation added required parameter
// Old: client.updateIssue(id, { title: "new" })
// New: client.updateIssue(id, { title: "new" })  // usually same

Step 6: Test in Staging Before Production

set -euo pipefail
# Deploy to staging
npm run build
npm run deploy:staging

# Run integration tests against staging
LINEAR_API_KEY=$STAGING_LINEAR_API_KEY npm run test:integration

# Check health endpoint
curl -s https://staging.yourapp.com/health/linear | jq .

Step 7: Deploy with Rollback Plan

set -euo pipefail
# Commit upgrade
git add package.json package-lock.json src/linear-compat.ts
git commit -m "chore: upgrade @linear/sdk to $(npm list @linear/sdk --json | jq -r '.dependencies["@linear/sdk"].version')"
git push origin upgrade/linear-sdk-*

# If something breaks in production:
git revert HEAD
npm install  # Restores previous version
npm run deploy

Version Compatibility

SDK RangeNode.jsTypeScriptNotable Changes
1.x14+4.5+Initial release, callback-style
2.x-16.x16+4.7+ESM support, typed models
17.x-28.x18+5.0+Strict types, new entity models
Latest18+5.0+Refresh tokens, initiatives, agents

Error Handling

ErrorCauseSolution
Property does not existRenamed fieldCheck changelog, update field name
Type is not assignableChanged return typeUpdate type annotations
Module not foundESM/CJS mismatchUpdate import syntax or tsconfig
Cannot find nameRemoved exportReplace with new API equivalent
Tests pass, prod failsSDK version mismatch in lockfileDelete node_modules, npm ci

Examples

Pre-Upgrade Audit Script

// scripts/audit-linear-usage.ts
// Run before upgrading to find all SDK touchpoints

import { readFileSync } from "fs";
import { globSync } from "glob";

const files = globSync("src/**/*.ts");
const patterns = [
  /LinearClient/g,
  /client\.issues/g,
  /client\.createIssue/g,
  /client\.updateIssue/g,
  /\.state\b/g,
  /\.assignee\b/g,
  /rawRequest/g,
];

for (const file of files) {
  const content = readFileSync(file, "utf-8");
  for (const pattern of patterns) {
    const matches = content.match(pattern);
    if (matches) {
      console.log(`${file}: ${pattern.source} (${matches.length} occurrences)`);
    }
  }
}

Resources

What ships with it: 1 file

2.7 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,144. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.