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/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"
>
-
+
-
+ ❯
+
+ ❯
+ ❯linearissue
+ ❯
+ linear
+ issue
+ start?Selectstart
+
+
+ ?
+ Select
+ anissuean
+ issue
+ tostart:❯---to
+ start:
+
+
+ ❯
+ ---
+ CLI-14:AllowCLI-14:
+ Allow
+ assigningpeopleassigning
+ people
+ otherthanother
+ than
+ yourselfwhenyourself
+ when
+ creatingissuescreating
+ issues
+
+
+ ---CLI-20:---
+ CLI-20:
+ AllowskippingAllow
+ skipping
+ confirmationwhendeletingconfirmation
+ when
+ deleting
+ issuesissues
+
+
+ ---CLI-16:---
+ CLI-16:
+ SupportlistingSupport
+ listing
+ projectsprojects
+
+
+ ---CLI-14:---
+ CLI-14:
+ AllowassigningAllow
+ assigning
+ peopleotherpeople
+ other
+ thanyourselfthan
+ yourself
+ whencreatingwhen
+ creating
+ issues❯---issues
+
+
+ ❯
+ ---
+ CLI-20:AllowCLI-20:
+ Allow
+ skippingconfirmationwhendeletingskipping
+ confirmation
+ when
+ deleting
+ issues❯---issues
+
+
+ ❯
+ ---
+ CLI-16:SupportCLI-16:
+ Support
+ listingprojects?Selectlisting
+ projects
+
+
+ ?
+ Select
+ anissuean
+ issue
+ tostart:to
+ start:
+ ›---›
+ ---
+ CLI-20:AllowCLI-20:
+ Allow
+ skippingconfirmationwhendeletingskipping
+ confirmation
+ when
+ deleting
+ issues⠋?Branchissues
+
+ ⠋
+
+ ?
+ Branch
+ cli-20-allow-skipping-confirmation-when-deleting-issuescli-20-allow-skipping-confirmation-when-deleting-issues
+ alreadyexists.already
+ exists.
+ WhatwouldWhat
+ would
+ youlikeyou
+ like
+ todo?Switchtoto
+ do?
+
+
+ Switch
+ to
+ existingbranch❯Createexisting
+ branch
+
+
+ ❯
+ Create
+ newbranchnew
+ branch
+ withsuffix?Branchwith
+ suffix
+
+
+ ?
+ Branch
+ cli-20-allow-skipping-confirmation-when-deleting-issuescli-20-allow-skipping-confirmation-when-deleting-issues
+ alreadyexists.already
+ exists.
+ WhatwouldWhat
+ would
+ youlikeyou
+ like
+ todo?to
+ do?
+ ›Create›
+ Create
+ newbranchnew
+ branch
+ withsuffix✓Createdwi
+
+
+ th
+ suffix
+
+
+ ✓
+ Created
+ andswitchedand
+ switched
+ tobranchto
+ branch
+ 'cli-20-allow-skipping-confirmation-when-deleting-issues-1''cli-20-allow-skipping-confirmation-when-deleting-issues-1'
+
+ ✓Issuestate
+ ✓
+ Issue
+ state
+ updatedtoupdated
+ to
+ 'InProgress''In
+ Progress'
+
+
+ ❯git❯
+ git
+ branch--show-currentbranch
+ --show-current
+
+
+ ❯git❯
+ git
+ branch--show-currentbranch
+ --show-current
+
+
+ cli-20-allow-skipping-confirmation-when-deleting-issues-1cli-20-allow-skipping-confirmation-when-deleting-issues-1
+
+
+
+
+
+
+
+
+
+
+ >
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+ ❯❯
+ l
-
-
+
+
+
+ ❯l
-
- ❯
+ l
+
+
+
+
+ ❯l❯
+ l
+ lmcmdlm
+ cmd
+ "gitshow"git
+ show
+ currentbranch"
-
- current
+ branch"
+
+
+
+
+ ❯linear
-
- ❯
+ linear
+
+
+
+
+ ❯linear
-
- ❯
+ linear
+
+
+
+
+ ❯linear❯
+ linear
+ issuelistissue
+ list
+ -a
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuei
+ ssue
+ list-a
-
- list
+ -a
+
+
+
+
+ ❯linear❯
+ linear
+ issuei
+ ssue
+ list-a
-
- list
+ -a
+
+
+
+
+ ❯linear❯
+ linear
+ i
-
-
+
+
+
+ ❯linear❯
+ linear
+ issue
-
-
+
+
+
+ ❯linear❯
+ linear
+ issue
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuelistissue
+ list
+ -a
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuesissue
+ s
+ tart
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuestissue
+ st
+ art
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuestaissue
+ sta
+ rt
-
-
+
+
+
+ ❯linear❯
+ linear
+ issuestarissue
+ star
+ t
-
-
+
+
+
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/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..5530d61f 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,75 @@ 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")
+ }
+ },
+})