From 7e39e35757da0c0cdaac194a52cb255a920dd73d Mon Sep 17 00:00:00 2001 From: Jeffrey Holm Date: Wed, 25 Mar 2026 11:32:34 -0400 Subject: [PATCH 1/3] feat: add --json flag to issue list command Allow machine-readable output from `linear issue list` by adding a `-j`/`--json` flag that prints the raw issues array as JSON instead of rendering the formatted table. Skips pager and spinner when JSON output is requested, matching the existing pattern in `issue view`. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/commands/issue/issue-list.ts | 10 ++- .../__snapshots__/issue-list.test.ts.snap | 52 ++++++++++++++ test/commands/issue/issue-list.test.ts | 69 +++++++++++++++++++ 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/src/commands/issue/issue-list.ts b/src/commands/issue/issue-list.ts index 841bfcc5..5500fd36 100644 --- a/src/commands/issue/issue-list.ts +++ b/src/commands/issue/issue-list.ts @@ -99,6 +99,7 @@ export const listCommand = new Command() ) .option("-w, --web", "Open in web browser") .option("-a, --app", "Open in Linear.app") + .option("-j, --json", "Output issues as JSON") .option("--no-pager", "Disable automatic paging for long output") .action( async ( @@ -110,6 +111,7 @@ export const listCommand = new Command() unassigned, web, app, + json, allStates, team, project, @@ -206,7 +208,7 @@ export const listCommand = new Command() } const { Spinner } = await import("@std/cli/unstable-spinner") - const showSpinner = shouldShowSpinner() + const showSpinner = shouldShowSpinner() && !json const spinner = showSpinner ? new Spinner() : null spinner?.start() @@ -230,6 +232,12 @@ export const listCommand = new Command() return } + // Handle JSON output + if (json) { + console.log(JSON.stringify(issues, null, 2)) + return + } + const { columns } = Deno.stdout.isTerminal() ? Deno.consoleSize() : { columns: 120 } diff --git a/test/commands/issue/__snapshots__/issue-list.test.ts.snap b/test/commands/issue/__snapshots__/issue-list.test.ts.snap index 68b208a7..b86d6a46 100644 --- a/test/commands/issue/__snapshots__/issue-list.test.ts.snap +++ b/test/commands/issue/__snapshots__/issue-list.test.ts.snap @@ -26,9 +26,61 @@ Options: --limit - Maximum number of issues to fetch (default: 50, use 0 for unlimited) (Default: \\x1b[33m50\\x1b[39m) -w, --web - Open in web browser -a, --app - Open in Linear.app + -j, --json - Output issues as JSON --no-pager - Disable automatic paging for long output \` stderr: "" `; + +snapshot[`Issue List Command - JSON Output 1`] = ` +stdout: +'[ + { + "id": "issue-1", + "identifier": "TEST-101", + "title": "First issue", + "priority": 2, + "estimate": 3, + "assignee": { + "initials": "JD" + }, + "state": { + "id": "state-1", + "name": "In Progress", + "color": "#f87462" + }, + "labels": { + "nodes": [] + }, + "updatedAt": "2024-01-15T10:00:00Z" + }, + { + "id": "issue-2", + "identifier": "TEST-102", + "title": "Second issue", + "priority": 1, + "estimate": null, + "assignee": null, + "state": { + "id": "state-2", + "name": "Todo", + "color": "#e2e2e2" + }, + "labels": { + "nodes": [ + { + "id": "label-1", + "name": "bug", + "color": "#eb5757" + } + ] + }, + "updatedAt": "2024-01-14T08:00:00Z" + } +] +' +stderr: +"" +`; diff --git a/test/commands/issue/issue-list.test.ts b/test/commands/issue/issue-list.test.ts index 277bae42..ce0de472 100644 --- a/test/commands/issue/issue-list.test.ts +++ b/test/commands/issue/issue-list.test.ts @@ -1,6 +1,7 @@ import { snapshotTest } from "@cliffy/testing" import { listCommand } from "../../../src/commands/issue/issue-list.ts" import { commonDenoArgs } from "../../utils/test-helpers.ts" +import { MockLinearServer } from "../../utils/mock_linear_server.ts" // Test help output await snapshotTest({ @@ -13,3 +14,71 @@ await snapshotTest({ await listCommand.parse() }, }) + +// Test JSON output +await snapshotTest({ + name: "Issue List Command - JSON Output", + meta: import.meta, + colors: false, + args: ["--json", "--sort", "priority"], + denoArgs: commonDenoArgs, + async fn() { + const server = new MockLinearServer([ + { + queryName: "GetIssuesForState", + response: { + data: { + issues: { + nodes: [ + { + id: "issue-1", + identifier: "TEST-101", + title: "First issue", + priority: 2, + estimate: 3, + assignee: { initials: "JD" }, + state: { id: "state-1", name: "In Progress", color: "#f87462" }, + labels: { nodes: [] }, + updatedAt: "2024-01-15T10:00:00Z", + }, + { + id: "issue-2", + identifier: "TEST-102", + title: "Second issue", + priority: 1, + estimate: null, + assignee: null, + state: { id: "state-2", name: "Todo", color: "#e2e2e2" }, + labels: { + nodes: [ + { id: "label-1", name: "bug", color: "#eb5757" }, + ], + }, + updatedAt: "2024-01-14T08:00:00Z", + }, + ], + pageInfo: { + hasNextPage: false, + endCursor: null, + }, + }, + }, + }, + }, + ]) + + try { + await server.start() + Deno.env.set("LINEAR_GRAPHQL_ENDPOINT", server.getEndpoint()) + Deno.env.set("LINEAR_API_KEY", "Bearer test-token") + Deno.env.set("LINEAR_TEAM_ID", "TEST") + + await listCommand.parse() + } finally { + await server.stop() + Deno.env.delete("LINEAR_GRAPHQL_ENDPOINT") + Deno.env.delete("LINEAR_API_KEY") + Deno.env.delete("LINEAR_TEAM_ID") + } + }, +}) From fe87695d90b3bf9f1b7de464d460f1c32f7c2916 Mon Sep 17 00:00:00 2001 From: Jeffrey Holm Date: Wed, 25 Mar 2026 18:53:30 -0400 Subject: [PATCH 2/3] fix: run deno fmt, update docs for --json flag on issue list Apply deno fmt formatting to test file, add --json flag to README command examples, and regenerate skill reference docs to include the new flag. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 1 + skills/linear-cli/references/issue.md | 1 + test/commands/issue/issue-list.test.ts | 6 +++++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dbda35c1..f1186993 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ linear issue url # prints the Linear.app URL for the issue linear issue pr # creates a GitHub PR with issue details via `gh pr create` linear issue list # list your issues in a table view (supports -s/--state and --sort) linear issue list --project "My Project" --milestone "Phase 1" # filter by milestone +linear issue list -j # output issues as JSON linear issue list -w # open issue list in web browser linear issue list -a # open issue list in Linear.app linear issue start # create/switch to issue branch and mark as started diff --git a/skills/linear-cli/references/issue.md b/skills/linear-cli/references/issue.md index 16f8bc03..26cffbf2 100644 --- a/skills/linear-cli/references/issue.md +++ b/skills/linear-cli/references/issue.md @@ -84,6 +84,7 @@ Options: --limit - Maximum number of issues to fetch (default: 50, use 0 for unlimited) (Default: 50) -w, --web - Open in web browser -a, --app - Open in Linear.app + -j, --json - Output issues as JSON --no-pager - Disable automatic paging for long output ``` diff --git a/test/commands/issue/issue-list.test.ts b/test/commands/issue/issue-list.test.ts index ce0de472..5530d61f 100644 --- a/test/commands/issue/issue-list.test.ts +++ b/test/commands/issue/issue-list.test.ts @@ -37,7 +37,11 @@ await snapshotTest({ priority: 2, estimate: 3, assignee: { initials: "JD" }, - state: { id: "state-1", name: "In Progress", color: "#f87462" }, + state: { + id: "state-1", + name: "In Progress", + color: "#f87462", + }, labels: { nodes: [] }, updatedAt: "2024-01-15T10:00:00Z", }, From 0707e969e30bdb531b793bed59e521a81a819f0e Mon Sep 17 00:00:00 2001 From: Jeffrey Holm Date: Wed, 25 Mar 2026 19:51:32 -0400 Subject: [PATCH 3/3] style: format SVGs with deno 2.7.8 --- docs/cast-issue-create.svg | 6052 ++++++++++++++++++++++++++---------- docs/cast-issue-start.svg | 1467 ++++++--- 2 files changed, 5500 insertions(+), 2019 deletions(-) diff --git a/docs/cast-issue-create.svg b/docs/cast-issue-create.svg index 9ff98288..1ccc142e 100644 --- a/docs/cast-issue-create.svg +++ b/docs/cast-issue-create.svg @@ -4,15 +4,15 @@ width="1300" height="607.88" > - + - + + diff --git a/docs/cast-issue-start.svg b/docs/cast-issue-start.svg index 0c9d81a5..edc08372 100644 --- a/docs/cast-issue-start.svg +++ b/docs/cast-issue-start.svg @@ -4,15 +4,15 @@ width="1300" height="607.88" > - + - + +