linear-sdk-cli 0.1.3 → 0.2.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.
Files changed (79) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +96 -58
  4. package/COVERAGE.md +5 -5
  5. package/MIGRATING.md +71 -69
  6. package/README.md +115 -90
  7. package/package.json +6 -7
  8. package/skills/README.md +15 -0
  9. package/skills/linear-sdk-cli/SKILL.md +27 -3
  10. package/skills/linear-sdk-cli/references/api.md +9 -9
  11. package/skills/linear-sdk-cli/references/auth.md +18 -0
  12. package/skills/linear-sdk-cli/references/commands.md +2 -2
  13. package/skills/linear-sdk-cli/references/comment.md +9 -6
  14. package/skills/linear-sdk-cli/references/config.md +9 -11
  15. package/skills/linear-sdk-cli/references/issue.md +72 -18
  16. package/skills/linear-sdk-cli/references/open.md +29 -0
  17. package/skills/linear-sdk-cli/references/team.md +16 -0
  18. package/skills/linear-sdk-cli/scripts/generate-docs.ts +6 -2
  19. package/skills/linear-sdk-cli-maintenance/SKILL.md +97 -0
  20. package/src/bin/linear.ts +16 -6
  21. package/src/cli.ts +3 -1
  22. package/src/commands/agent-session.ts +13 -5
  23. package/src/commands/api.ts +15 -9
  24. package/src/commands/attach.ts +15 -4
  25. package/src/commands/comment.ts +50 -11
  26. package/src/commands/completion.ts +2 -6
  27. package/src/commands/cycle.ts +6 -1
  28. package/src/commands/discover.ts +6 -2
  29. package/src/commands/document.ts +4 -1
  30. package/src/commands/initiative.ts +5 -1
  31. package/src/commands/issue.ts +392 -91
  32. package/src/commands/meta.ts +139 -31
  33. package/src/commands/milestone.ts +4 -1
  34. package/src/commands/notification.ts +15 -6
  35. package/src/commands/open.ts +84 -0
  36. package/src/commands/project.ts +17 -4
  37. package/src/commands/team.ts +13 -0
  38. package/src/commands/user.ts +2 -2
  39. package/src/commands/webhook.ts +12 -2
  40. package/src/config.ts +501 -184
  41. package/src/context.ts +13 -4
  42. package/src/git.ts +28 -3
  43. package/src/lib/body.ts +26 -2
  44. package/src/lib/errors.ts +33 -8
  45. package/src/lib/introspect.ts +76 -7
  46. package/src/lib/keyring.ts +51 -9
  47. package/src/lib/mentions.ts +49 -0
  48. package/src/lib/open.ts +32 -0
  49. package/src/lib/options.ts +108 -12
  50. package/src/lib/output-shapes.ts +81 -9
  51. package/src/lib/pagination.ts +50 -17
  52. package/src/lib/resolve.ts +40 -7
  53. package/src/lib/shape.ts +16 -12
  54. package/src/lib/upload.ts +3 -1
  55. package/src/output/color.ts +52 -0
  56. package/src/output/format.ts +96 -18
  57. package/src/output/markdown.ts +133 -0
  58. package/src/output/pager.ts +131 -0
  59. package/src/output/sanitize.ts +1 -1
  60. package/src/output/table.ts +7 -7
  61. package/src/services/agent-session.ts +11 -3
  62. package/src/services/attachment.ts +14 -5
  63. package/src/services/comment.ts +37 -9
  64. package/src/services/cycle.ts +11 -4
  65. package/src/services/document.ts +29 -10
  66. package/src/services/favorite.ts +15 -9
  67. package/src/services/initiative-update.ts +16 -15
  68. package/src/services/initiative.ts +15 -10
  69. package/src/services/issue.ts +263 -19
  70. package/src/services/label.ts +12 -2
  71. package/src/services/milestone.ts +8 -5
  72. package/src/services/notification.ts +16 -2
  73. package/src/services/organization.ts +23 -18
  74. package/src/services/project.ts +55 -34
  75. package/src/services/roadmap.ts +7 -6
  76. package/src/services/state.ts +9 -3
  77. package/src/services/team.ts +67 -24
  78. package/src/services/user.ts +2 -2
  79. package/src/services/webhook.ts +28 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linear-sdk-cli",
3
- "version": "0.1.3",
3
+ "version": "0.2.3",
4
4
  "description": "Ergonomic command-line interface for Linear, built on @linear/sdk",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -53,14 +53,15 @@
53
53
  "dev": "bun run src/bin/linear.ts",
54
54
  "lin": "bun run src/bin/linear.ts",
55
55
  "typecheck": "tsc --noEmit",
56
- "lint": "eslint .",
56
+ "lint": "oxlint .",
57
57
  "format": "prettier --write .",
58
+ "format:check": "prettier --check .",
58
59
  "test": "bun test test/unit test/contract",
59
60
  "test:unit": "bun test test/unit",
60
61
  "test:contract": "bun test test/contract",
61
62
  "test:live": "LINEAR_CLI_LIVE=1 bun test --timeout 60000 test/integration",
62
63
  "test:live:admin": "LINEAR_CLI_LIVE=1 LINEAR_CLI_LIVE_ADMIN=1 bun test --timeout 60000 test/integration",
63
- "verify": "bun run typecheck && bun run lint && bun run test",
64
+ "verify": "bun run typecheck && bun run lint && bun run audit:coverage && bun run format:check && bun run test",
64
65
  "skill:docs": "bun run skills/linear-sdk-cli/scripts/generate-docs.ts",
65
66
  "audit:coverage": "bun run scripts/coverage-audit.ts",
66
67
  "janitor": "bun run test/janitor.ts"
@@ -75,12 +76,10 @@
75
76
  },
76
77
  "packageManager": "bun@1.4.0",
77
78
  "devDependencies": {
78
- "@eslint/js": "^10.0.1",
79
79
  "@types/bun": "^1.4.0",
80
80
  "@types/node": "^26.2.0",
81
- "eslint": "^10.9.0",
81
+ "oxlint": "^1.80.0",
82
82
  "prettier": "^3.9.6",
83
- "typescript": "^6.0.3",
84
- "typescript-eslint": "^8.67.0"
83
+ "typescript": "^7.0.2"
85
84
  }
86
85
  }
@@ -0,0 +1,15 @@
1
+ # Agent skills
2
+
3
+ The `skills/` directory contains the portable, canonical skill sources for this
4
+ repository. Each skill uses the open `SKILL.md` convention and must remain usable
5
+ by both Codex and Claude Code without agent-specific instructions.
6
+
7
+ Claude Code receives the listed skills through `.claude-plugin/plugin.json` when
8
+ this repository is installed as its plugin. A Codex user can add or install the
9
+ same skill directory in their Codex skills location; scheduled Codex tasks can
10
+ also invoke a repository skill explicitly by path.
11
+
12
+ The cloud maintenance routine reads
13
+ `skills/linear-sdk-cli-maintenance/SKILL.md` before it acts. Keep routine-specific
14
+ schedule and notification settings in the routine; keep maintenance procedure and
15
+ guardrails in the skill.
@@ -24,8 +24,8 @@ If that fails, or prints `2.x` (that is `schpet/linear-cli`, a different tool th
24
24
  `linear` name), install this one — it needs Bun ≥ 1.1:
25
25
 
26
26
  ```bash
27
- bun add -g linear-sdk-cli # installs `linear` and `lin`
28
- lin --version # `lin` never collides with the other CLI
27
+ bun add --global linear-sdk-cli # installs `linear` and collision-free `lin`
28
+ lin --version
29
29
  ```
30
30
 
31
31
  `lin` is the safe spelling when both might be present. If the user is coming from
@@ -195,7 +195,26 @@ EOF
195
195
 
196
196
  For short, single-line content, use inline `-d/--description` (issues/initiatives),
197
197
  the positional `[body]` arg (comments: `linear comment add TES-42 "lgtm"`), or
198
- `--body` (status updates). There is no `-b` short flag.
198
+ `--body` (status updates). There is no `-b` short flag. The CLI rejects an inline
199
+ body containing literal `\n` sequences and points back to stdin; never encode a
200
+ multiline body by inserting `\n` inside an ordinary quoted argument.
201
+
202
+ ### Mentions require explicit intent
203
+
204
+ Never assume that `@name` in comment text should notify somebody: the CLI keeps it as literal
205
+ Markdown. Add the repeatable `--mention <name|email|me|id>` option only when the user explicitly
206
+ asks for a real mention. It resolves each workspace user and prepends the notification-capable
207
+ mention before the supplied body:
208
+
209
+ ```bash
210
+ linear comment add TES-42 "Please review." --mention ada --json
211
+ linear issue comment TES-42 --body-file - --mention me --json <<'EOF'
212
+ This deliberately mentions me; the @example in this sentence remains literal.
213
+ EOF
214
+ ```
215
+
216
+ `--mention` is available on `issue comment`, `comment add`, `comment reply`, and `comment update`
217
+ (including the `issue comment add/update` mounts). It is repeatable and deduplicates users.
199
218
 
200
219
  ### Discovery — learn the surface without scraping help
201
220
 
@@ -235,6 +254,7 @@ linear attachment delete
235
254
  linear attachment list
236
255
 
237
256
  linear auth
257
+ linear auth adopt
238
258
  linear auth default
239
259
  linear auth list
240
260
  linear auth login
@@ -351,6 +371,8 @@ linear notification read-all
351
371
  linear notification snooze
352
372
  linear notification unread
353
373
 
374
+ linear open
375
+
354
376
  linear organization
355
377
  linear organization invites
356
378
  linear organization members
@@ -386,6 +408,7 @@ linear team
386
408
  linear team create
387
409
  linear team cycles
388
410
  linear team delete
411
+ linear team id
389
412
  linear team labels
390
413
  linear team list
391
414
  linear team members
@@ -432,6 +455,7 @@ prints the same). These are supplementary — `--help` on any command is authori
432
455
  - [label](references/label.md) — Work with issue labels
433
456
  - [milestone](references/milestone.md) — Work with project milestones
434
457
  - [notification](references/notification.md) — Work with your notifications
458
+ - [open](references/open.md) — Open the workspace, an issue, team, project, or URL
435
459
  - [organization](references/organization.md) — Inspect the current workspace
436
460
  - [project](references/project.md) — Work with projects
437
461
  - [project-update](references/project-update.md) — Post and list project status updates
@@ -14,14 +14,14 @@ Run a raw GraphQL query or mutation against the Linear API
14
14
  linear api [options] [query]
15
15
  ```
16
16
 
17
- | Option | Description |
18
- | --------------------- | ----------------------------------------------------------------- |
19
- | `--query-file <path>` | read the query from a file ('-' for stdin) |
20
- | `--var <k=v...>` | set a variable (repeatable; string value) |
21
- | `--vars <json>` | variables as a JSON object |
22
- | `--vars-file <path>` | read variables from a JSON file ('-' for stdin) |
23
- | `--operation <name>` | run this operation of a multi-operation document |
24
- | `--paginate` | auto-follow the first connection's pageInfo cursor (queries only) |
25
- | `--raw` | print the full GraphQL response (data + extensions) |
17
+ | Option | Description |
18
+ | --------------------- | ------------------------------------------------------------------------------ |
19
+ | `--query-file <path>` | read the query from a file ('-' for stdin) |
20
+ | `--var <k=v...>` | set a variable (repeatable; JSON literals are typed, other values are strings) |
21
+ | `--vars <json>` | variables as a JSON object |
22
+ | `--vars-file <path>` | read variables from a JSON file ('-' for stdin) |
23
+ | `--operation <name>` | run this operation of a multi-operation document |
24
+ | `--paginate` | auto-follow the first connection's pageInfo cursor (queries only) |
25
+ | `--raw` | print the full GraphQL response (data + extensions) |
26
26
 
27
27
  **Output (`--json`)**: raw JSON (keys depend on the request) — the response `data` as the API returned it (`--raw`: {data, extensions}); `--paginate` prints one array of every page's nodes
@@ -14,6 +14,24 @@ Manage authentication
14
14
  linear auth [options]
15
15
  ```
16
16
 
17
+ ### `linear auth adopt`
18
+
19
+ Adopt an existing named credential from the shared OS keyring
20
+
21
+ ```
22
+ linear auth adopt [options] <slug>
23
+ ```
24
+
25
+ **Output (`--json`)**: a receipt object
26
+
27
+ ```text
28
+ success: boolean
29
+ workspace: string
30
+ user: {id: string, name: string, email: string}
31
+ storage: string
32
+ path: string
33
+ ```
34
+
17
35
  ### `linear auth default`
18
36
 
19
37
  Set the default workspace credential
@@ -21,7 +21,7 @@ path: string
21
21
  description: string
22
22
  aliases: string[]
23
23
  arguments: Array<{name: string, required: boolean, variadic: boolean}>
24
- options: Array<{flags: string, description: string}>
24
+ options: Array<{flags: string, description: string, attribute: string, valueRequired: boolean, valueOptional: boolean, variadic: boolean, choices?: string[], defaultValue?: unknown, global: boolean, applicable: boolean}>
25
25
  output?: {kind: string, fields?: object, note?: string, variants?: object}
26
26
  ```
27
27
 
@@ -32,6 +32,6 @@ path: string
32
32
  description: string
33
33
  aliases: string[]
34
34
  arguments: Array<{name: string, required: boolean, variadic: boolean}>
35
- options: Array<{flags: string, description: string}>
35
+ options: Array<{flags: string, description: string, attribute: string, valueRequired: boolean, valueOptional: boolean, variadic: boolean, choices?: string[], defaultValue?: unknown, global: boolean, applicable: boolean}>
36
36
  output?: {kind: string, fields?: object, note?: string, variants?: object}
37
37
  ```
@@ -29,6 +29,7 @@ linear comment add [options] <issue> [body]
29
29
  | Option | Description |
30
30
  | -------------------- | ----------------------------------------------------------------------------------------- |
31
31
  | `--body-file <path>` | read comment body from a file ('-' = stdin) |
32
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
32
33
  | `--attach <file>` | upload a file and embed it in the comment (images inline; repeatable; private by default) |
33
34
  | `--public` | upload the attachments to public, world-readable URLs (raster images only) |
34
35
 
@@ -89,9 +90,10 @@ Reply to a comment (nested under it)
89
90
  linear comment reply [options] <commentId> [body]
90
91
  ```
91
92
 
92
- | Option | Description |
93
- | -------------------- | ----------------------------------------- |
94
- | `--body-file <path>` | read reply body from a file ('-' = stdin) |
93
+ | Option | Description |
94
+ | -------------------- | ------------------------------------------------------------------ |
95
+ | `--body-file <path>` | read reply body from a file ('-' = stdin) |
96
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
95
97
 
96
98
  **Output (`--json`)**: a receipt object
97
99
 
@@ -142,9 +144,10 @@ Aliases: `edit`
142
144
  linear comment update [options] <commentId> [body]
143
145
  ```
144
146
 
145
- | Option | Description |
146
- | -------------------- | --------------------------------------- |
147
- | `--body-file <path>` | read new body from a file ('-' = stdin) |
147
+ | Option | Description |
148
+ | -------------------- | ------------------------------------------------------------------ |
149
+ | `--body-file <path>` | read new body from a file ('-' = stdin) |
150
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
148
151
 
149
152
  **Output (`--json`)**: a receipt object
150
153
 
@@ -23,8 +23,7 @@ credentialWorkspace: string | null
23
23
  team: string | null
24
24
  workspace: string | null
25
25
  sort: string
26
- vcs: string
27
- origins: {team: {source: string, path?: string}, workspace: {source: string, path?: string}, sort: {source: string, path?: string}, vcs: {source: string, path?: string}}
26
+ origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: string}}
28
27
  userConfigPath: string
29
28
  projectConfigPath: string | null
30
29
  globalConfigPath: string | null
@@ -38,12 +37,12 @@ Write a project .linear.toml (at the git root, or here outside a repository)
38
37
  linear config init [options]
39
38
  ```
40
39
 
41
- | Option | Description |
42
- | ---------------- | -------------------------------------------------------- |
43
- | `--team <key>` | default team key (otherwise chosen from a list) |
44
- | `--sort <order>` | default issue-list sort (priority \| updated \| created) |
45
- | `--path <file>` | write this file instead of <git root>/.linear.toml |
46
- | `--force` | overwrite an existing file |
40
+ | Option | Description |
41
+ | ---------------- | ------------------------------------------------------------------ |
42
+ | `--team <key>` | default team key (otherwise chosen from a list) |
43
+ | `--sort <order>` | default issue-list sort (priority \| manual \| updated \| created) |
44
+ | `--path <file>` | write this file instead of <git root>/.linear.toml |
45
+ | `--force` | overwrite an existing file |
47
46
 
48
47
  **Output (`--json`)**: a receipt object
49
48
 
@@ -56,7 +55,7 @@ sort?: string
56
55
 
57
56
  ### `linear config set`
58
57
 
59
- Set one project setting (team, workspace, sort, vcs) in the project config
58
+ Set one project setting (team, workspace, sort) in the project config
60
59
 
61
60
  ```
62
61
  linear config set [options] <key> <value>
@@ -93,8 +92,7 @@ credentialWorkspace: string | null
93
92
  team: string | null
94
93
  workspace: string | null
95
94
  sort: string
96
- vcs: string
97
- origins: {team: {source: string, path?: string}, workspace: {source: string, path?: string}, sort: {source: string, path?: string}, vcs: {source: string, path?: string}}
95
+ origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: string}}
98
96
  userConfigPath: string
99
97
  projectConfigPath: string | null
100
98
  globalConfigPath: string | null
@@ -44,18 +44,27 @@ team: {id: string, key: string, name: string} | null
44
44
  project: {id: string, name: string} | null
45
45
  milestone: {id: string, name: string} | null
46
46
  cycle: {id: string, number: number, name: string | null} | null
47
- parent: {id: string, identifier: string} | null
47
+ parent: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null} | null
48
+ children: Array<{id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}>
48
49
  labels: Array<{id: string, name: string}>
49
50
  subscribers: Array<{id: string, displayName: string}>
51
+ attachments: Array<{id: string, title: string, url: string, subtitle: string | null, sourceType: string | null, createdAt: string}>
52
+ documents: Array<{id: string, title: string, slugId: string, url: string, createdAt: string, updatedAt: string}>
53
+ relations: Array<{id: string, type: string, issue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}, relatedIssue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}}>
54
+ inverseRelations: Array<{id: string, type: string, issue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}, relatedIssue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}}>
55
+ comments: Array<{id: string, body: string, url: string, createdAt: string, editedAt: string | null, resolvedAt: string | null, parent: {id: string} | null, user: {id: string, displayName: string} | null, externalUser: {id: string, displayName: string} | null, resolvingCommentId: string | null, resolvingUser: {id: string, displayName: string} | null}>
50
56
  ```
51
57
 
52
- With `--comments`: the same, plus:
58
+ With `--web`: a receipt object
53
59
 
54
60
  ```text
55
- comments: Array<{id: string, body: string, user: {id: string, displayName: string} | null, createdAt: string, editedAt: string | null, resolvedAt: string | null, parent: {id: string} | null, url: string}>
61
+ id: string
62
+ identifier: string
63
+ url: string
64
+ opened: boolean
56
65
  ```
57
66
 
58
- With `--web`: a receipt object
67
+ With `--app`: a receipt object
59
68
 
60
69
  ```text
61
70
  id: string
@@ -143,6 +152,12 @@ Archive an issue
143
152
  linear issue archive [options] [id]
144
153
  ```
145
154
 
155
+ | Option | Description |
156
+ | -------------------- | ------------------------------------------------ |
157
+ | `--bulk <ids>` | archive comma-separated issue ids (repeatable) |
158
+ | `--bulk-file <path>` | archive issue ids from a file (one per line) |
159
+ | `--bulk-stdin` | archive issue ids read from stdin (one per line) |
160
+
146
161
  **Output (`--json`)**: a receipt object
147
162
 
148
163
  ```text
@@ -151,6 +166,15 @@ identifier: string
151
166
  archived: boolean
152
167
  ```
153
168
 
169
+ With `--bulk`: a receipt object
170
+
171
+ ```text
172
+ action: string
173
+ results: Array<{input: string, id?: string, identifier?: string, archived?: boolean, deleted?: boolean, error?: {message: string, code: string}}>
174
+ succeeded: number
175
+ failed: number
176
+ ```
177
+
154
178
  ### `linear issue assign`
155
179
 
156
180
  Assign an issue (use 'me', email, name, or id). Issue defaults to the branch.
@@ -214,9 +238,10 @@ Add a comment to an issue; on a matching branch, `issue comment "<body>"` is eno
214
238
  linear issue comment [options] [id] [body]
215
239
  ```
216
240
 
217
- | Option | Description |
218
- | -------------------- | ------------------------------------------- |
219
- | `--body-file <path>` | read comment body from a file ('-' = stdin) |
241
+ | Option | Description |
242
+ | -------------------- | ------------------------------------------------------------------ |
243
+ | `--body-file <path>` | read comment body from a file ('-' = stdin) |
244
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
220
245
 
221
246
  **Output (`--json`)**: a receipt object — the bare form adds a comment; add/list/update/delete are subcommands
222
247
 
@@ -236,6 +261,7 @@ linear issue comment add [options] <issue> [body]
236
261
  | Option | Description |
237
262
  | -------------------- | ----------------------------------------------------------------------------------------- |
238
263
  | `--body-file <path>` | read comment body from a file ('-' = stdin) |
264
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
239
265
  | `--attach <file>` | upload a file and embed it in the comment (images inline; repeatable; private by default) |
240
266
  | `--public` | upload the attachments to public, world-readable URLs (raster images only) |
241
267
 
@@ -292,9 +318,10 @@ Update a comment's body
292
318
  linear issue comment update [options] <commentId> [body]
293
319
  ```
294
320
 
295
- | Option | Description |
296
- | -------------------- | --------------------------------------- |
297
- | `--body-file <path>` | read new body from a file ('-' = stdin) |
321
+ | Option | Description |
322
+ | -------------------- | ------------------------------------------------------------------ |
323
+ | `--body-file <path>` | read new body from a file ('-' = stdin) |
324
+ | `--mention <user>` | prepend a real Linear mention (name, email, me, or id; repeatable) |
298
325
 
299
326
  **Output (`--json`)**: a receipt object
300
327
 
@@ -380,6 +407,12 @@ Aliases: `rm`
380
407
  linear issue delete [options] [id]
381
408
  ```
382
409
 
410
+ | Option | Description |
411
+ | -------------------- | ----------------------------------------------- |
412
+ | `--bulk <ids>` | delete comma-separated issue ids (repeatable) |
413
+ | `--bulk-file <path>` | delete issue ids from a file (one per line) |
414
+ | `--bulk-stdin` | delete issue ids read from stdin (one per line) |
415
+
383
416
  **Output (`--json`)**: a receipt object
384
417
 
385
418
  ```text
@@ -388,6 +421,15 @@ identifier: string
388
421
  deleted: boolean
389
422
  ```
390
423
 
424
+ With `--bulk`: a receipt object
425
+
426
+ ```text
427
+ action: string
428
+ results: Array<{input: string, id?: string, identifier?: string, archived?: boolean, deleted?: boolean, error?: {message: string, code: string}}>
429
+ succeeded: number
430
+ failed: number
431
+ ```
432
+
391
433
  ### `linear issue describe`
392
434
 
393
435
  Print a commit message for the issue: 'ID Title' plus Linear-issue trailers
@@ -790,6 +832,7 @@ linear issue update [options] [id]
790
832
  | `--estimate <n>` | estimate points |
791
833
  | `--parent <id>` | parent issue id |
792
834
  | `--due <date>` | due date (YYYY-MM-DD) |
835
+ | `-l, --label <name>` | replace all labels (repeatable / comma-separated) |
793
836
  | `--add-label <name>` | add a label (repeatable) |
794
837
  | `--remove-label <name>` | remove a label (repeatable) |
795
838
  | `--unassign` | clear the assignee |
@@ -825,10 +868,12 @@ Show an issue (defaults to the current branch's issue)
825
868
  linear issue view [options] [id]
826
869
  ```
827
870
 
828
- | Option | Description |
829
- | ------------ | ------------------------------------------------- |
830
- | `-w, --web` | open the issue in the browser instead of printing |
831
- | `--comments` | include recent comments |
871
+ | Option | Description |
872
+ | ------------------------- | ------------------------------------------------- |
873
+ | `-w, --web` | open the issue in the browser instead of printing |
874
+ | `--app` | open the issue in Linear.app instead of printing |
875
+ | `--no-comments` | exclude comments from the output |
876
+ | `--show-resolved-threads` | include resolved comment threads |
832
877
 
833
878
  **Output (`--json`)**: a bare object
834
879
 
@@ -856,18 +901,27 @@ team: {id: string, key: string, name: string} | null
856
901
  project: {id: string, name: string} | null
857
902
  milestone: {id: string, name: string} | null
858
903
  cycle: {id: string, number: number, name: string | null} | null
859
- parent: {id: string, identifier: string} | null
904
+ parent: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null} | null
905
+ children: Array<{id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}>
860
906
  labels: Array<{id: string, name: string}>
861
907
  subscribers: Array<{id: string, displayName: string}>
908
+ attachments: Array<{id: string, title: string, url: string, subtitle: string | null, sourceType: string | null, createdAt: string}>
909
+ documents: Array<{id: string, title: string, slugId: string, url: string, createdAt: string, updatedAt: string}>
910
+ relations: Array<{id: string, type: string, issue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}, relatedIssue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}}>
911
+ inverseRelations: Array<{id: string, type: string, issue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}, relatedIssue: {id: string, identifier: string, title: string, state: {id: string, name: string, type: string} | null}}>
912
+ comments: Array<{id: string, body: string, url: string, createdAt: string, editedAt: string | null, resolvedAt: string | null, parent: {id: string} | null, user: {id: string, displayName: string} | null, externalUser: {id: string, displayName: string} | null, resolvingCommentId: string | null, resolvingUser: {id: string, displayName: string} | null}>
862
913
  ```
863
914
 
864
- With `--comments`: the same, plus:
915
+ With `--web`: a receipt object
865
916
 
866
917
  ```text
867
- comments: Array<{id: string, body: string, user: {id: string, displayName: string} | null, createdAt: string, editedAt: string | null, resolvedAt: string | null, parent: {id: string} | null, url: string}>
918
+ id: string
919
+ identifier: string
920
+ url: string
921
+ opened: boolean
868
922
  ```
869
923
 
870
- With `--web`: a receipt object
924
+ With `--app`: a receipt object
871
925
 
872
926
  ```text
873
927
  id: string
@@ -0,0 +1,29 @@
1
+ # linear open
2
+
3
+ > Open the workspace, an issue, team, project, or URL
4
+
5
+ _Generated from `linear commands --json`. `linear open --help` (or `<subcommand> --help`) is authoritative._
6
+
7
+ Every command also accepts the global flags `-j/--json`, `--no-input`, `-y/--yes`, `-q/--quiet`, `--workspace <slug>`, `--api-key <key>`, `-t/--team <key>`, `-n/--limit <n>`, `--all`, `-f/--fields <a,b,c>`, `--no-ansi` (alias `--no-color`), and `--debug`. Only command-specific options are listed below.
8
+
9
+ ### `linear open`
10
+
11
+ Open the workspace, an issue, team, project, or URL
12
+
13
+ ```
14
+ linear open [options] [target]
15
+ ```
16
+
17
+ | Option | Description |
18
+ | ----------- | ----------------------------------------- |
19
+ | `--app` | open in Linear.app (macOS) |
20
+ | `-w, --web` | open in the default browser (the default) |
21
+
22
+ **Output (`--json`)**: a receipt object
23
+
24
+ ```text
25
+ target: string
26
+ url: string
27
+ label: string
28
+ opened: boolean
29
+ ```
@@ -86,6 +86,22 @@ movedIssues: number
86
86
  movedTo: {id: string, key: string, name: string} | null
87
87
  ```
88
88
 
89
+ ### `linear team id`
90
+
91
+ Print a team's UUID (defaults to the configured team)
92
+
93
+ ```
94
+ linear team id [options] [key]
95
+ ```
96
+
97
+ **Output (`--json`)**: a receipt object
98
+
99
+ ```text
100
+ id: string
101
+ key: string
102
+ name: string
103
+ ```
104
+
89
105
  ### `linear team labels`
90
106
 
91
107
  List a team's labels
@@ -70,7 +70,10 @@ const GLOBAL_OPTIONS = new Map([
70
70
  ["-t, --team <key>", "default team key (e.g. TES)"],
71
71
  ["-n, --limit <n>", "max results (positive integer; 0 = all)"],
72
72
  ["--all", "fetch all results (exhaust pagination)"],
73
- ["-f, --fields <a,b,c>", "select fields: table columns or detail lines (human), top-level keys (--json)"],
73
+ [
74
+ "-f, --fields <a,b,c>",
75
+ "select fields: table columns or detail lines (human), top-level keys (--json)",
76
+ ],
74
77
  ["-y, --yes", "skip confirmation prompts"],
75
78
  ["-q, --quiet", "suppress status output"],
76
79
  ["--no-input", "never prompt; fail instead"],
@@ -190,7 +193,8 @@ function formatOutput(out: OutputShape, heading = "**Output (`--json`)**"): stri
190
193
  lines.push(`With \`${when}\`: the same${drop}, plus:`);
191
194
  lines.push("");
192
195
  lines.push("```text");
193
- for (const [key, shape] of Object.entries(delta.added)) lines.push(`${key}: ${renderShape(shape)}`);
196
+ for (const [key, shape] of Object.entries(delta.added))
197
+ lines.push(`${key}: ${renderShape(shape)}`);
194
198
  lines.push("```");
195
199
  lines.push("");
196
200
  continue;
@@ -0,0 +1,97 @@
1
+ ---
2
+ name: linear-sdk-cli-maintenance
3
+ description: "Safely maintain the linear-sdk-cli repository: assess dependency updates, prepare and verify focused pull requests, and hand off releases. Use for scheduled upkeep, dependency reviews, release-automation checks, and maintenance PR reviews in this repository."
4
+ ---
5
+
6
+ # linear-sdk-cli maintenance
7
+
8
+ Use this skill from the repository root. It is deliberately agent-neutral: the same
9
+ `SKILL.md` is the source of truth for Codex and Claude Code.
10
+
11
+ ## Invocation modes
12
+
13
+ - **Review mode (default):** inspect and report only. Do not create branches, commits,
14
+ pull requests, merges, releases, or configuration changes without current user approval.
15
+ - **Scheduled autonomous mode:** the calling routine explicitly authorizes the maintenance
16
+ mutations described below. It may create and update PRs and merge a verified,
17
+ dependency-only roll-up PR. It must never push directly to `main`.
18
+
19
+ If the invocation does not state a mode, use review mode.
20
+
21
+ ## Guardrails
22
+
23
+ - Start from the current remote `main`; preserve all unrelated local or remote work.
24
+ - Never reveal, add, rotate, or work around credentials. Do not modify API keys, auth,
25
+ keychain behaviour, `.env` files, or `.linear.toml` merely to make a check pass.
26
+ - Do not weaken tests, linting, CI, branch protection, release checks, or provenance to
27
+ get a green result.
28
+ - Treat a failed verification, a conflict, a required reviewer, or a non-green check as a
29
+ stop condition for the affected change. Report the evidence and leave the repository
30
+ recoverable.
31
+ - Keep dependency-only changes isolated from source, test, configuration, workflow, or
32
+ documentation changes. Source changes always get their own draft PR and are never
33
+ auto-merged by this skill.
34
+ - Use conventional commits. Do not bypass required checks, dismiss reviews, or override
35
+ branch protection.
36
+ - For multiline GitHub PR descriptions or comments, write Markdown to a file and use the
37
+ corresponding `--body-file` option. Do not encode line breaks as `\n` inside a quoted
38
+ `--body` argument. Read the published body back once and confirm that headings, paragraphs,
39
+ and lists render as intended.
40
+
41
+ ## Maintenance loop
42
+
43
+ 1. Inspect the current `main`, open maintenance/release PRs, CI status, and repository
44
+ guidance. Confirm tool availability with `bun --version`, `gh auth status`, and the
45
+ repository scripts before changing anything.
46
+ 2. Survey dependency candidates with `bun outdated`. Group compatible patch/minor updates;
47
+ assess major updates separately. Check each material update's upstream release notes or
48
+ migration guide before proposing it.
49
+ 3. Prefer one focused dependency roll-up PR for compatible, low-risk updates. Defer an
50
+ update that causes a failure or requires an unverified migration; state its exact version,
51
+ reason, and next action in the report.
52
+ 4. For every candidate PR, run the repository's required verification:
53
+
54
+ ```sh
55
+ bun install
56
+ bun run verify
57
+ bun src/bin/linear.ts --version
58
+ bun src/bin/linear.ts commands --json > /dev/null
59
+ bun run janitor
60
+ ```
61
+
62
+ Run `bun run skill:docs` and include generated references whenever a command or option
63
+ changes. Keep the PR scope limited to the intended maintenance category.
64
+
65
+ 5. In scheduled autonomous mode, merge only a dependency-only roll-up PR after all required
66
+ checks are green, the merge is clean, and there are no unresolved review comments. Recheck
67
+ `main` CI after the merge. Otherwise, leave the PR ready for review and report why it was
68
+ not merged.
69
+
70
+ ## Release Please handoff
71
+
72
+ When a Release Please PR exists, review its diff, mergeability, checks, and discussion.
73
+ In scheduled autonomous mode, merge it only when all of the following are true:
74
+
75
+ - it contains only the expected version and changelog changes;
76
+ - required checks are green (or intentionally absent because the automation-created PR cannot
77
+ trigger them, while the exact release commit has already passed `main` CI);
78
+ - it is cleanly mergeable with no conflicts, review blockers, or unresolved comments.
79
+
80
+ Release Please may rewrite its PR whenever `main` changes. Record the `headRefOid` used by CI
81
+ and review, then fetch the PR again immediately before merging. If its head changed, discard the
82
+ earlier evidence and repeat diff review, verification, and review-comment checks on the new head.
83
+
84
+ After an approved merge, confirm the release workflow completed, then verify the GitHub Release,
85
+ the npm package version, and the `latest` dist-tag. npm publishing must retain OIDC provenance.
86
+ Never retry a failed publish by adding an npm token or disabling provenance; report the failure.
87
+
88
+ ## Report format
89
+
90
+ End every run with a short, evidence-backed summary:
91
+
92
+ - repository/branch and current commit inspected;
93
+ - dependency candidates, including deferred items and rationale;
94
+ - PRs created, updated, merged, or deliberately left open;
95
+ - each verification command and result;
96
+ - release status, if applicable; and
97
+ - blockers or the next safe action.