linear-sdk-cli 0.4.0 → 0.5.0
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 +9 -0
- package/COVERAGE.md +4 -0
- package/MIGRATING.md +6 -0
- package/README.md +188 -37
- package/package.json +5 -5
- package/skills/linear-sdk-cli/SKILL.md +1 -0
- package/skills/linear-sdk-cli/references/auth.md +1 -0
- package/skills/linear-sdk-cli/references/config.md +10 -7
- package/skills/linear-sdk-cli/references/initiative.md +10 -5
- package/skills/linear-sdk-cli/references/issue.md +222 -77
- package/skills/linear-sdk-cli/references/notification.md +3 -3
- package/skills/linear-sdk-cli/references/project.md +9 -4
- package/src/commands/initiative.ts +23 -6
- package/src/commands/issue.ts +313 -12
- package/src/commands/meta.ts +55 -9
- package/src/commands/notification.ts +5 -3
- package/src/commands/project.ts +21 -3
- package/src/config.ts +111 -10
- package/src/lib/delegation.ts +240 -0
- package/src/lib/options.ts +17 -3
- package/src/lib/output-shapes.ts +77 -3
- package/src/output/lifecycle.ts +10 -0
- package/src/services/initiative.ts +12 -3
- package/src/services/issue.ts +498 -21
- package/src/services/project.ts +14 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@ Release Please generates this file from Conventional Commits. Feature and fix pu
|
|
|
4
4
|
not edit it directly; their squash-commit titles are the release-note source of truth. This project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.5.0](https://github.com/zhendalf/linear-sdk-cli/compare/v0.4.0...v0.5.0) (2026-09-03)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **config:** support per-workspace default teams ([#50](https://github.com/zhendalf/linear-sdk-cli/issues/50)) ([06be757](https://github.com/zhendalf/linear-sdk-cli/commit/06be757ddb81652dea4da32434e63de773cb6760)), closes [#44](https://github.com/zhendalf/linear-sdk-cli/issues/44)
|
|
12
|
+
- **issue:** add native agent delegation ([#52](https://github.com/zhendalf/linear-sdk-cli/issues/52)) ([15055ff](https://github.com/zhendalf/linear-sdk-cli/commit/15055ff73d46f6ddf31679b7bb5f37fc6e3fddda)), closes [#45](https://github.com/zhendalf/linear-sdk-cli/issues/45)
|
|
13
|
+
- **issue:** set labels by group ([#54](https://github.com/zhendalf/linear-sdk-cli/issues/54)) ([4c471cd](https://github.com/zhendalf/linear-sdk-cli/commit/4c471cd23c9409ba395cf43514f9e251a42ef4d6)), closes [#46](https://github.com/zhendalf/linear-sdk-cli/issues/46)
|
|
14
|
+
- standardize archived-resource listing ([#53](https://github.com/zhendalf/linear-sdk-cli/issues/53)) ([735d1c8](https://github.com/zhendalf/linear-sdk-cli/commit/735d1c87894736de257b8888edb8500934e502f3)), closes [#49](https://github.com/zhendalf/linear-sdk-cli/issues/49)
|
|
15
|
+
|
|
7
16
|
## [0.4.0](https://github.com/zhendalf/linear-sdk-cli/compare/v0.3.3...v0.4.0) (2026-08-28)
|
|
8
17
|
|
|
9
18
|
### Features
|
package/COVERAGE.md
CHANGED
|
@@ -11,6 +11,10 @@ Generated by `bun run audit:coverage`. Total LinearClient members: **472**.
|
|
|
11
11
|
Every member is classified — CI fails otherwise. `raw-only` members are still
|
|
12
12
|
100% reachable through the raw GraphQL escape hatch; they simply lack a tailored command.
|
|
13
13
|
|
|
14
|
+
## Curated field capabilities
|
|
15
|
+
|
|
16
|
+
- Issue delegation (Developer Preview) — `Issue.delegate`, `IssueCreateInput.delegateId`, `IssueUpdateInput.delegateId`, and eligible agent-user fields are covered by `issue delegate` and the delegation options on `issue create`/`issue update`.
|
|
17
|
+
|
|
14
18
|
## Curated (107)
|
|
15
19
|
|
|
16
20
|
- `agentSession` — issue
|
package/MIGRATING.md
CHANGED
|
@@ -124,6 +124,10 @@ Everything with no row is spelled identically.
|
|
|
124
124
|
|
|
125
125
|
Passing both spellings at once (`--due` _and_ `--due-date`) is a usage error, not a coin flip.
|
|
126
126
|
|
|
127
|
+
This CLI previously taught `initiative list --archived`. Its canonical spelling is now
|
|
128
|
+
`--include-archived`, matching issue, project, and notification lists. The old spelling remains a
|
|
129
|
+
compatibility alias throughout `0.x`; passing both spellings together is a usage error.
|
|
130
|
+
|
|
127
131
|
**Short flags are the one place we did not follow.** schpet 2.5's own tree assigns `-a` four
|
|
128
132
|
meanings (`--app`, `--all`, `--assignee`, `--attach`), `-f` four, `-y` three, `-t` two (`--title`
|
|
129
133
|
and `--team`). There is no consistent target to copy. Ours holds **one meaning per letter across
|
|
@@ -154,6 +158,8 @@ Every one is now either identical, or says so on stderr, or is a usage error. Kn
|
|
|
154
158
|
under `--quiet`) that deactivated users are still excluded and names `--include-disabled`, and
|
|
155
159
|
`--help` says so up front. Not adopted: making `--all` mean "and deactivated" on two commands
|
|
156
160
|
would give one global two meanings.
|
|
161
|
+
The same rule applies to lifecycle history: `--all` never includes archived records. Use
|
|
162
|
+
`--include-archived --all` to widen lifecycle visibility and exhaust pagination independently.
|
|
157
163
|
5. **`-f <file>` on `project create/update`, `document create/update`** — theirs: `--description-file` /
|
|
158
164
|
`--content-file`. Ours: `-f` is `--fields`, and it used to be _dropped_ on those commands, so
|
|
159
165
|
`project create --name X -f desc.md` created the project with no description and exited 0.
|
package/README.md
CHANGED
|
@@ -64,7 +64,8 @@ retains their best ideas and provides a careful compatibility and migration path
|
|
|
64
64
|
- **Git-aware** — the current issue is inferred from your branch (`tes-123-fix` → `TES-123`), so most issue commands let you drop the id.
|
|
65
65
|
- **Git + GitHub workflow** — `issue start` checks out the branch and marks the issue started, `issue describe` prints a commit message with Linear-issue trailers, `issue pr` opens a GitHub PR — all linked back to the issue.
|
|
66
66
|
- **Forgiving inputs** — refer to things the way you think of them: `TES-123`, team `TES`, `--assignee me`, `--cycle current`, state and label by name.
|
|
67
|
-
- **Multi-workspace** — store credentials
|
|
67
|
+
- **Multi-workspace** — store credentials and a non-secret default team per workspace, then switch
|
|
68
|
+
both contexts with a global `--workspace`.
|
|
68
69
|
- **Complete & honest** — first-class commands for the core resource graph, a raw `linear api` for everything else, and a [measured coverage audit](#coverage) that CI keeps honest.
|
|
69
70
|
|
|
70
71
|
## Install
|
|
@@ -230,6 +231,7 @@ linear auth login --workspace other-org # …and another workspace
|
|
|
230
231
|
linear auth login --workspace acme --key - # personal API-key fallback via stdin
|
|
231
232
|
linear auth list # show configured workspaces + which is default
|
|
232
233
|
linear auth default acme # choose the default workspace
|
|
234
|
+
linear config set team ENG --user --workspace acme # set its validated default team
|
|
233
235
|
linear --workspace other-org issue list # use a specific workspace for one command
|
|
234
236
|
linear auth logout --workspace acme # revoke OAuth, then remove one credential
|
|
235
237
|
```
|
|
@@ -239,11 +241,13 @@ If browser login temporarily superseded an existing personal API-key profile for
|
|
|
239
241
|
OAuth logout preserves and reactivates the API key instead of deleting it.
|
|
240
242
|
|
|
241
243
|
**Selection precedence** (strict): an explicit `--api-key` or `--access-token` flag bypasses the
|
|
242
|
-
environment and
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
244
|
+
environment and stored-credential lookup. Otherwise `LINEAR_API_KEY` or `LINEAR_ACCESS_TOKEN` is
|
|
245
|
+
absolute. With no invocation-scoped credential, the workspace is chosen by `--workspace` →
|
|
246
|
+
`LINEAR_WORKSPACE` env → project config `workspace` → `default_workspace` in the user config. With
|
|
247
|
+
one configured workspace it's used automatically; with several and no selection, the CLI asks you
|
|
248
|
+
to pick (via `--workspace`, project config, or `auth default`). An invocation credential does not
|
|
249
|
+
silently inherit the default or project profile's team; pair it with `--workspace` (or
|
|
250
|
+
`LINEAR_WORKSPACE`) naming a configured profile when that profile metadata should apply.
|
|
247
251
|
|
|
248
252
|
## Core concepts
|
|
249
253
|
|
|
@@ -267,10 +271,76 @@ A few ideas run through every command:
|
|
|
267
271
|
linear issue create --title "Fix login redirect" --team TES -P 2 --assignee me
|
|
268
272
|
linear issue list --assignee me --state started
|
|
269
273
|
linear issue update TES-42 --state "In Review" --add-label backend
|
|
274
|
+
linear issue label TES-42 --set-group 'Team=QA'
|
|
275
|
+
linear issue delegate TES-42 Codex
|
|
270
276
|
linear issue comment TES-42 "ready for another look"
|
|
271
277
|
linear issue archive TES-42 --yes
|
|
272
278
|
```
|
|
273
279
|
|
|
280
|
+
**Agent delegation (Developer Preview)** — the assignee remains the human owner; the delegate is
|
|
281
|
+
the agent working on their behalf. Create/update accept `--delegate <name|id>` and
|
|
282
|
+
`--clear-delegate`; the focused command is convenient on a matching branch:
|
|
283
|
+
|
|
284
|
+
```sh
|
|
285
|
+
linear issue create --title "Investigate flaky CI" --assignee me --delegate Codex
|
|
286
|
+
linear issue update TES-42 --delegate Codex
|
|
287
|
+
linear issue update TES-42 --clear-delegate
|
|
288
|
+
linear issue delegate TES-42 Codex
|
|
289
|
+
linear issue delegate --clear # issue inferred from the branch
|
|
290
|
+
linear issue delegate TES-42 Codex --dry-run --json
|
|
291
|
+
linear issue delegate TES-42 Codex --full-result --json
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Delegate resolution accepts an agent-user UUID, exact display name, or exact full name, preferring
|
|
295
|
+
case-sensitive matches. It rejects human, inactive, non-assignable, ambiguous, and team-ineligible
|
|
296
|
+
users before writing. `--dry-run` resolves every field and prints the exact nullable `delegateId`
|
|
297
|
+
input without a mutation; `--full-result` (hidden alias `--read-back`) returns the relationship
|
|
298
|
+
receipt plus the canonical issue read-back and verifies the resulting delegate. These modes are
|
|
299
|
+
currently the delegation slice only: on `issue create`/`update`, pair them with `--delegate` or
|
|
300
|
+
`--clear-delegate`.
|
|
301
|
+
|
|
302
|
+
Delegating can trigger an externally observable Agent Session/webhook. Clearing a delegate does
|
|
303
|
+
not claim to cancel a session that is already running. Linear for Agents is in Developer Preview;
|
|
304
|
+
an unsupported workspace/schema returns `feature_not_accessible`, while ordinary `issue view`
|
|
305
|
+
falls back safely and reports `delegate: null` if the preview field itself is unavailable.
|
|
306
|
+
See Linear's current [agent integration guide](https://linear.app/developers/agents) and
|
|
307
|
+
[issue-assignment guide](https://linear.app/docs/assigning-issues) for the platform semantics.
|
|
308
|
+
|
|
309
|
+
**Label-group replacement** — replace only the selected group's direct member while preserving
|
|
310
|
+
every unrelated issue label. Repeat `--set-group` to plan several groups into one relative-label
|
|
311
|
+
mutation:
|
|
312
|
+
|
|
313
|
+
```sh
|
|
314
|
+
linear issue label TES-42 --set-group 'Team=QA'
|
|
315
|
+
linear issue label TES-42 \
|
|
316
|
+
--set-group 'Team=QA' \
|
|
317
|
+
--set-group 'Issue Type=Bug' \
|
|
318
|
+
--json
|
|
319
|
+
linear issue label TES-42 --set-group 'Team=QA' --dry-run --json
|
|
320
|
+
linear issue label TES-42 --set-group 'Team=QA' --full-result --json
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Both sides accept a UUID or an exact, case-sensitive name. The value is split on the first `=`:
|
|
324
|
+
shell-quote the whole assignment when either name contains spaces or shell metacharacters; a label
|
|
325
|
+
name may contain additional `=` characters without escaping. If the group name itself contains
|
|
326
|
+
`=`, use its UUID on the left. Group containers, archived labels, labels outside the issue team's
|
|
327
|
+
workspace/team/inherited scope, and labels that are not direct members of the named group are
|
|
328
|
+
rejected before writing. Repeating an identical assignment normalizes to one operation; conflicting
|
|
329
|
+
targets for the same resolved group are a usage error. `--set-group` cannot be mixed with the
|
|
330
|
+
existing `--add`/`--remove` mode.
|
|
331
|
+
|
|
332
|
+
The JSON receipt includes the resolved group/member IDs plus `changed` and `mutationSent`. An
|
|
333
|
+
already-satisfied request succeeds with both fields `false` and sends no mutation. `--dry-run`
|
|
334
|
+
returns the shared mutation-plan envelope and the exact `addedLabelIds`/`removedLabelIds` input;
|
|
335
|
+
`--full-result` adds the canonical issue read-back, verification, and each requested group's prior
|
|
336
|
+
members (including all members repaired from an inconsistent pre-existing state).
|
|
337
|
+
|
|
338
|
+
This is a read/modify/write operation: the CLI reads the current labels, then sends one update with
|
|
339
|
+
relative added/removed IDs, so unrelated concurrent label changes are not overwritten. Linear does
|
|
340
|
+
not expose a compare-and-swap precondition here, so another writer changing the same group between
|
|
341
|
+
the read and update can race; use `--full-result` when post-write verification matters. See Linear's
|
|
342
|
+
current [label documentation](https://linear.app/docs/labels) for group and inheritance semantics.
|
|
343
|
+
|
|
274
344
|
**Git + GitHub PR** — turn an issue into commits and a pull request. The id is inferred from the
|
|
275
345
|
branch everywhere below.
|
|
276
346
|
|
|
@@ -311,7 +381,9 @@ EOF
|
|
|
311
381
|
|
|
312
382
|
```sh
|
|
313
383
|
linear project list --team TES
|
|
384
|
+
linear project list --include-archived --all --json
|
|
314
385
|
linear project view "Q3 Launch"
|
|
386
|
+
linear initiative list --include-archived --json
|
|
315
387
|
linear project-update create "Q3 Launch" --health onTrack --body "Beta is out to 10% of users."
|
|
316
388
|
linear initiative-update create "Platform" --health atRisk --body-file update.md
|
|
317
389
|
```
|
|
@@ -355,33 +427,89 @@ Every group has `--help` with full options and (for the busy ones) an Examples s
|
|
|
355
427
|
are shown in parentheses. For a machine-readable tree of _every_ command, run
|
|
356
428
|
`linear commands --json`.
|
|
357
429
|
|
|
358
|
-
| Group | What you can do
|
|
359
|
-
| ------------------------------ |
|
|
360
|
-
| **`issue`** (`i`) | `view` · `list` · `mine` · `search` · `create` · `update` · `delete` · `archive`/`unarchive` · `start` (git branch) · `describe` · `pull-request`/`pr` · `assign` · `state` · `label` · `comment`/`comments` · `relation` · `subscribe`/`unsubscribe` · `id`/`title`/`url`/`branch` |
|
|
361
|
-
| **`team`** (`t`) | `list` · `view` · `members` · `states` · `labels` · `cycles` · `create` · `update`
|
|
362
|
-
| **`project`** (`p`) | `list` · `view` · `create` · `update` · `archive` · `milestones`
|
|
363
|
-
| **`project-update`** (`pu`) | `create` · `list` (project status updates, with `--health`)
|
|
364
|
-
| **`milestone`** (`m`) | `list` · `view` · `create` · `update` · `delete`
|
|
365
|
-
| **`cycle`** (`c`) | `list` · `view` · `current` · `create` · `update`
|
|
366
|
-
| **`user`** (`u`) | `list` · `view` · `me`
|
|
367
|
-
| **`label`** (`lb`) | `list` · `create` · `update` · `delete`
|
|
368
|
-
| **`state`** (`st`) | `list` · `view` (workflow states)
|
|
369
|
-
| **`comment`** (`cm`) | `list` · `add` · `reply` · `update` · `delete` · `resolve`/`unresolve`
|
|
370
|
-
| **`document`** (`doc`) | `list` · `view` · `create` · `update` · `delete`
|
|
371
|
-
| **`attachment`** (`at`) | `list` · `create` · `delete`
|
|
372
|
-
| **`favorite`** (`fav`) | `list` · `add` · `remove`
|
|
373
|
-
| **`custom-view`** (`cv`) | `list` · `view` · `results` · `create` · `update` · `delete`
|
|
374
|
-
| **`initiative`** (`init`) | `list` · `view` · `create` · `update` · `archive` · `delete`
|
|
375
|
-
| **`initiative-update`** (`iu`) | `create` · `list` (initiative status updates, with `--health`)
|
|
376
|
-
| **`roadmap`** (`rm`) | `list` · `view` · `create` · `update` · `delete` <sup>†</sup>
|
|
377
|
-
| **`notification`** (`notif`) | `list` · `read`/`unread` · `read-all` · `archive` · `snooze`
|
|
378
|
-
| **`organization`** (`org`) | `view` · `members` · `invites`
|
|
379
|
-
| **`webhook`** (`wh`) | `list` · `view` · `create` · `update` · `delete`
|
|
380
|
-
| **top-level** | `whoami` · `auth` (`login` · `list` · `default` · `token` · `status` · `logout`) · `config` · `api` · `commands` · `schema` · `completion`
|
|
430
|
+
| Group | What you can do |
|
|
431
|
+
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
432
|
+
| **`issue`** (`i`) | `view` · `list` · `mine` · `search` · `create` · `update` · `delete` · `archive`/`unarchive` · `start` (git branch) · `describe` · `pull-request`/`pr` · `assign` · `delegate` · `state` · `label` · `comment`/`comments` · `relation` · `subscribe`/`unsubscribe` · `id`/`title`/`url`/`branch` |
|
|
433
|
+
| **`team`** (`t`) | `list` · `view` · `members` · `states` · `labels` · `cycles` · `create` · `update` |
|
|
434
|
+
| **`project`** (`p`) | `list` · `view` · `create` · `update` · `archive` · `milestones` |
|
|
435
|
+
| **`project-update`** (`pu`) | `create` · `list` (project status updates, with `--health`) |
|
|
436
|
+
| **`milestone`** (`m`) | `list` · `view` · `create` · `update` · `delete` |
|
|
437
|
+
| **`cycle`** (`c`) | `list` · `view` · `current` · `create` · `update` |
|
|
438
|
+
| **`user`** (`u`) | `list` · `view` · `me` |
|
|
439
|
+
| **`label`** (`lb`) | `list` · `create` · `update` · `delete` |
|
|
440
|
+
| **`state`** (`st`) | `list` · `view` (workflow states) |
|
|
441
|
+
| **`comment`** (`cm`) | `list` · `add` · `reply` · `update` · `delete` · `resolve`/`unresolve` |
|
|
442
|
+
| **`document`** (`doc`) | `list` · `view` · `create` · `update` · `delete` |
|
|
443
|
+
| **`attachment`** (`at`) | `list` · `create` · `delete` |
|
|
444
|
+
| **`favorite`** (`fav`) | `list` · `add` · `remove` |
|
|
445
|
+
| **`custom-view`** (`cv`) | `list` · `view` · `results` · `create` · `update` · `delete` |
|
|
446
|
+
| **`initiative`** (`init`) | `list` · `view` · `create` · `update` · `archive` · `delete` |
|
|
447
|
+
| **`initiative-update`** (`iu`) | `create` · `list` (initiative status updates, with `--health`) |
|
|
448
|
+
| **`roadmap`** (`rm`) | `list` · `view` · `create` · `update` · `delete` <sup>†</sup> |
|
|
449
|
+
| **`notification`** (`notif`) | `list` · `read`/`unread` · `read-all` · `archive` · `snooze` |
|
|
450
|
+
| **`organization`** (`org`) | `view` · `members` · `invites` |
|
|
451
|
+
| **`webhook`** (`wh`) | `list` · `view` · `create` · `update` · `delete` |
|
|
452
|
+
| **top-level** | `whoami` · `auth` (`login` · `list` · `default` · `token` · `status` · `logout`) · `config` · `api` · `commands` · `schema` · `completion` |
|
|
381
453
|
|
|
382
454
|
<sup>†</sup> Linear has **deprecated roadmaps** in favor of initiatives — reads still work, but the
|
|
383
455
|
API rejects roadmap mutations with a deprecation notice. Use `initiative` for new work.
|
|
384
456
|
|
|
457
|
+
### Archived resources
|
|
458
|
+
|
|
459
|
+
Linear hides archived resources from paginated connections by default. On curated listings that
|
|
460
|
+
expose lifecycle history, `--include-archived` widens the result to live plus historical records;
|
|
461
|
+
it is not an archived-only filter. Linear can return trashed resources in that widened set, so
|
|
462
|
+
project, initiative, and issue JSON rows expose both `archivedAt: string|null` and
|
|
463
|
+
`trashed: boolean`, and human tables label `(archived)` and `(trashed)` separately. Notification
|
|
464
|
+
rows expose `archivedAt` (the public schema has no `trashed` field for notifications).
|
|
465
|
+
|
|
466
|
+
`--all` remains pagination-only. The two flags are independent and composable:
|
|
467
|
+
|
|
468
|
+
```sh
|
|
469
|
+
linear project list --include-archived --all --json
|
|
470
|
+
linear initiative list --include-archived --status Completed --json
|
|
471
|
+
linear issue search "migration" --include-archived --all --json
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
`initiative list --archived` remains a compatibility alias for `--include-archived`; passing both
|
|
475
|
+
spellings is an explicit usage error. The alias is retained for the current compatibility window
|
|
476
|
+
(all `0.x` releases; removal no earlier than `1.0`) and is listed by help and
|
|
477
|
+
`linear commands --json`.
|
|
478
|
+
|
|
479
|
+
The following matrix audits every curated list/search surface against the installed
|
|
480
|
+
`@linear/sdk@92.0.0` types and the live public schema exposed by `linear schema`. “Schema support”
|
|
481
|
+
means that the exact connection used by the command accepts `includeArchived`; it does not by
|
|
482
|
+
itself add a CLI contract. This change standardizes the four resource families named by
|
|
483
|
+
the issue. The remaining schema-capable collections stay unchanged until their own output and
|
|
484
|
+
resolver semantics are designed, rather than acquiring a silent partial implementation.
|
|
485
|
+
|
|
486
|
+
| Curated command(s) | Connection audited | Schema support | CLI lifecycle option | Lifecycle fields in list JSON |
|
|
487
|
+
| ------------------------------------------------------ | --------------------------------------------- | -------------- | ---------------------------------------------- | ----------------------------- |
|
|
488
|
+
| `issue list`, `issue mine` | `Query.issues` | yes | `--include-archived` | `archivedAt`, `trashed` |
|
|
489
|
+
| `issue search` | `Query.searchIssues` | yes | `--include-archived` | `archivedAt`, `trashed` |
|
|
490
|
+
| `project list` | `Query.projects` | yes | `--include-archived` | `archivedAt`, `trashed` |
|
|
491
|
+
| `initiative list` | `Query.initiatives` | yes | `--include-archived` (`--archived` alias) | `archivedAt`, `trashed` |
|
|
492
|
+
| `notification list` | `Query.notifications` | yes | `--include-archived` | `archivedAt` |
|
|
493
|
+
| `attachment list` | `Issue.attachments` | yes | not exposed | not exposed |
|
|
494
|
+
| `comment list`, `issue comment list`, `issue comments` | `Issue.comments` | yes | not exposed | not exposed |
|
|
495
|
+
| `cycle list`, `team cycles` | `Team.cycles` | yes | not exposed | not exposed |
|
|
496
|
+
| `custom-view list` | `Query.customViews` | yes | not exposed | `archivedAt` |
|
|
497
|
+
| `custom-view results` | `CustomView.issues/projects/initiatives` | yes | not exposed | not exposed |
|
|
498
|
+
| `document list` | `Query.documents` | yes | not exposed | not exposed |
|
|
499
|
+
| `favorite list` | `Query.favorites` | yes | not exposed | not exposed |
|
|
500
|
+
| `initiative-update list` | `Initiative.initiativeUpdates` | yes | not exposed | not exposed |
|
|
501
|
+
| `issue agent-session list` | `Query.agentSessions` / `Issue.agentSessions` | yes | not exposed | not exposed |
|
|
502
|
+
| `label list`, `team labels` | `Query.issueLabels` / `Team.labels` | yes | not exposed | not exposed |
|
|
503
|
+
| `milestone list`, `project milestones` | `Project.projectMilestones` | yes | not exposed | not exposed |
|
|
504
|
+
| `project-update list` | `Project.projectUpdates` | yes | not exposed | not exposed |
|
|
505
|
+
| `roadmap list` | `Query.roadmaps` | yes | not exposed | not exposed |
|
|
506
|
+
| `state list`, `team states` | `Team.states` | yes | not exposed | not exposed |
|
|
507
|
+
| `team list` | `Query.teams` | yes | not exposed | not exposed |
|
|
508
|
+
| `team members`, `user list`, `organization members` | user connections | yes | not exposed (`--include-disabled` is separate) | not exposed |
|
|
509
|
+
| `organization invites` | `Query.organizationInvites` | yes | not exposed | not exposed |
|
|
510
|
+
| `webhook list` | `Query.webhooks` | yes | not exposed | not exposed |
|
|
511
|
+
| `auth list` | local credential registry (no API connection) | no | not applicable | not applicable |
|
|
512
|
+
|
|
385
513
|
### Global flags
|
|
386
514
|
|
|
387
515
|
| Flag | Effect |
|
|
@@ -452,7 +580,8 @@ so prefer the `code` field for fine-grained handling and the exit code for coars
|
|
|
452
580
|
- **`-q, --quiet`** — suppress success/status lines on stderr (errors still print).
|
|
453
581
|
- **`-n, --limit <n>` / `--all`** — `--limit` caps results; `--all` exhausts pagination. With
|
|
454
582
|
neither, the default cap is **50**. `--all` (and very large `--limit`) can be slow and
|
|
455
|
-
rate-limit-prone on big workspaces.
|
|
583
|
+
rate-limit-prone on big workspaces. It never includes archived resources; combine it with
|
|
584
|
+
`--include-archived` where that option is available.
|
|
456
585
|
|
|
457
586
|
```sh
|
|
458
587
|
# agent-safe: no prompts, no chatter, fail fast with a parseable error
|
|
@@ -563,41 +692,54 @@ Non-secret defaults live in `~/.config/linear/config.toml` (user-wide) or a proj
|
|
|
563
692
|
file. **Secrets never go in a project file** — the API key is only ever read from the flag, the
|
|
564
693
|
env, the user config, or the OS keyring.
|
|
565
694
|
|
|
566
|
-
|
|
695
|
+
Effective team precedence, highest first — `linear config` prints the tier, file, and selected
|
|
696
|
+
profile slug where applicable:
|
|
567
697
|
|
|
568
698
|
1. the flag (`--team`, `--workspace`, `--sort`)
|
|
569
699
|
2. the environment (`LINEAR_TEAM`/`LINEAR_TEAM_ID`, `LINEAR_WORKSPACE`, `LINEAR_ISSUE_SORT`)
|
|
570
700
|
3. the **project config**: the first file found walking up from the working directory, checking in
|
|
571
701
|
each directory `linear.toml`, then `.linear.toml`, then `.config/linear.toml`; compatible
|
|
572
702
|
existing project configuration is picked up as-is
|
|
573
|
-
4. the
|
|
574
|
-
5. the legacy **
|
|
703
|
+
4. `team` on the selected `[workspaces."<slug>"]` profile
|
|
704
|
+
5. the legacy top-level `team` in the **user config**, `~/.config/linear/config.toml`
|
|
705
|
+
(`$XDG_CONFIG_HOME` honored)
|
|
706
|
+
6. the legacy **global config**, `~/.config/linear/linear.toml` — read for non-secret settings
|
|
575
707
|
only, so a migrating user's defaults carry over
|
|
708
|
+
7. no default team
|
|
709
|
+
|
|
710
|
+
`workspace` and `sort` keep their existing flag → environment → project → user → legacy-global
|
|
711
|
+
order. Workspace credential selection is independent and follows the order described above.
|
|
576
712
|
|
|
577
713
|
Keys: `team` (or `team_id`), `workspace`, and `sort` (or `issue_sort`). You can write these from
|
|
578
|
-
the CLI
|
|
714
|
+
the CLI. Project and top-level setting edits preserve comments and layout. Profile updates preserve
|
|
715
|
+
all TOML data and use the same locked, atomic rewrite as credential updates:
|
|
579
716
|
|
|
580
717
|
```sh
|
|
581
718
|
linear config init # pick a team from a list → <git root>/.linear.toml
|
|
582
719
|
linear config init --team TES # …or say which (scripts); --sort, --path, --force
|
|
583
720
|
linear config set sort updated # edit one key in the project config in effect
|
|
584
|
-
linear config set team ENG --user #
|
|
721
|
+
linear config set team ENG --user # legacy top-level user fallback (backward compatible)
|
|
722
|
+
linear config set team ENG --user --workspace acme # validated default for the acme profile
|
|
585
723
|
linear config # show the result, with each value's source
|
|
586
724
|
```
|
|
587
725
|
|
|
588
726
|
`config set` will not write `api_key` or anything else that belongs to the credential store — that
|
|
589
|
-
is what `auth login` is for.
|
|
727
|
+
is what `auth login` is for. A profile team is validated against the selected workspace whenever a
|
|
728
|
+
credential is available. Login, adopt, OAuth refresh/fallback, and credential migration preserve
|
|
729
|
+
profile metadata. Logout reports whether removing a whole profile also removed its team metadata.
|
|
590
730
|
|
|
591
731
|
```toml
|
|
592
732
|
# ~/.config/linear/config.toml
|
|
593
733
|
default_workspace = "acme" # which stored credential is active
|
|
594
|
-
team = "TES" #
|
|
734
|
+
team = "TES" # optional legacy/global fallback team
|
|
595
735
|
sort = "priority" # default issue-list sort: priority | updated | created
|
|
596
736
|
|
|
597
737
|
[workspaces."acme"] # per-workspace credentials (hyphenated slugs are quoted)
|
|
598
738
|
keyring = true # secret lives in the OS keyring (service linear-cli, account acme)
|
|
739
|
+
team = "ENG" # non-secret default team for this workspace
|
|
599
740
|
[workspaces."other-org"]
|
|
600
741
|
api_key = "lin_api_yyyyyyyy" # …or, with `auth login --plaintext`, in this 0600 file
|
|
742
|
+
team = "OPS"
|
|
601
743
|
```
|
|
602
744
|
|
|
603
745
|
Relevant environment variables: **`LINEAR_API_KEY`** or **`LINEAR_ACCESS_TOKEN`** (absolute —
|
|
@@ -655,6 +797,15 @@ bun run audit:coverage # regenerate COVERAGE.md (add --update to re-baseline t
|
|
|
655
797
|
bun run janitor # sweep leaked `clitest-` fixtures from the test workspace
|
|
656
798
|
```
|
|
657
799
|
|
|
800
|
+
The live delegation suite is additionally gated by `LINEAR_CLI_LIVE_AGENT_ID`, the UUID of an
|
|
801
|
+
explicit disposable-test agent. It can trigger that integration's Agent Session/webhook and is
|
|
802
|
+
never enabled by the general live-test flag alone.
|
|
803
|
+
|
|
804
|
+
The live label-group suite is additionally gated by `LINEAR_CLI_TEST_LABEL_GROUP` and
|
|
805
|
+
`LINEAR_CLI_TEST_LABEL_GROUP_MEMBER`, naming (or identifying by UUID) a pre-existing group and one
|
|
806
|
+
direct member usable by `LINEAR_CLI_TEST_TEAM`. It creates only a disposable issue; it does not
|
|
807
|
+
create, rename, move, or delete the shared label-group fixture.
|
|
808
|
+
|
|
658
809
|
Architecture is three layers — **commands** (commander wiring) → **services** (one module per
|
|
659
810
|
resource, the only place that touches the SDK) → **`@linear/sdk`**. The machine JSON envelope is
|
|
660
811
|
locked and contract-tested so output never silently drifts.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "linear-sdk-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Ergonomic command-line interface for Linear, built on @linear/sdk",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"janitor": "bun run test/janitor.ts"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@inquirer/prompts": "^8.7.
|
|
72
|
+
"@inquirer/prompts": "^8.7.1",
|
|
73
73
|
"@linear/sdk": "^92.0.0",
|
|
74
74
|
"commander": "^15.0.0",
|
|
75
75
|
"graphql": "^17.0.2",
|
|
@@ -79,9 +79,9 @@
|
|
|
79
79
|
"packageManager": "bun@1.4.0",
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@types/bun": "^1.4.0",
|
|
82
|
-
"@types/node": "^26.4.
|
|
83
|
-
"oxfmt": "^0.
|
|
84
|
-
"oxlint": "^1.
|
|
82
|
+
"@types/node": "^26.4.1",
|
|
83
|
+
"oxfmt": "^0.66.0",
|
|
84
|
+
"oxlint": "^1.81.0",
|
|
85
85
|
"typescript": "^7.0.2"
|
|
86
86
|
}
|
|
87
87
|
}
|
|
@@ -22,10 +22,11 @@ apiKeySource: string
|
|
|
22
22
|
accessToken: string
|
|
23
23
|
accessTokenSource: string
|
|
24
24
|
credentialWorkspace: string | null
|
|
25
|
+
workspaceProfile: string | null
|
|
25
26
|
team: string | null
|
|
26
27
|
workspace: string | null
|
|
27
28
|
sort: string
|
|
28
|
-
origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: string}}
|
|
29
|
+
origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
|
|
29
30
|
userConfigPath: string
|
|
30
31
|
projectConfigPath: string | null
|
|
31
32
|
globalConfigPath: string | null
|
|
@@ -57,16 +58,16 @@ sort?: string
|
|
|
57
58
|
|
|
58
59
|
### `linear config set`
|
|
59
60
|
|
|
60
|
-
Set one project setting (team, workspace, sort)
|
|
61
|
+
Set one project or user setting (team, workspace, sort)
|
|
61
62
|
|
|
62
63
|
```
|
|
63
64
|
linear config set [options] <key> <value>
|
|
64
65
|
```
|
|
65
66
|
|
|
66
|
-
| Option | Description
|
|
67
|
-
| --------------- |
|
|
68
|
-
| `--user` | write the user config (
|
|
69
|
-
| `--path <file>` | write this file instead of the project config in effect
|
|
67
|
+
| Option | Description |
|
|
68
|
+
| --------------- | ------------------------------------------------------------------------- |
|
|
69
|
+
| `--user` | write the user config (team + --workspace targets that workspace profile) |
|
|
70
|
+
| `--path <file>` | write this file instead of the project config in effect |
|
|
70
71
|
|
|
71
72
|
**Output (`--json`)**: a receipt object
|
|
72
73
|
|
|
@@ -75,6 +76,7 @@ success: boolean
|
|
|
75
76
|
path: string
|
|
76
77
|
key: string
|
|
77
78
|
value: string
|
|
79
|
+
workspace?: string
|
|
78
80
|
```
|
|
79
81
|
|
|
80
82
|
### `linear config show`
|
|
@@ -93,10 +95,11 @@ apiKeySource: string
|
|
|
93
95
|
accessToken: string
|
|
94
96
|
accessTokenSource: string
|
|
95
97
|
credentialWorkspace: string | null
|
|
98
|
+
workspaceProfile: string | null
|
|
96
99
|
team: string | null
|
|
97
100
|
workspace: string | null
|
|
98
101
|
sort: string
|
|
99
|
-
origins: {team: {source: string, path?: string, key?: string}, workspace: {source: string, path?: string, key?: string}, sort: {source: string, path?: string, key?: string}}
|
|
102
|
+
origins: {team: {source: string, path?: string, key?: string, workspace?: string}, workspace: {source: string, path?: string, key?: string, workspace?: string}, sort: {source: string, path?: string, key?: string, workspace?: string}}
|
|
100
103
|
userConfigPath: string
|
|
101
104
|
projectConfigPath: string | null
|
|
102
105
|
globalConfigPath: string | null
|
|
@@ -38,6 +38,7 @@ updatedAt: string
|
|
|
38
38
|
startedAt: string | null
|
|
39
39
|
completedAt: string | null
|
|
40
40
|
archivedAt: string | null
|
|
41
|
+
trashed: boolean
|
|
41
42
|
owner: string | null
|
|
42
43
|
creator: string | null
|
|
43
44
|
projects: Array<{id: string, name: string, status: {name: string, type: string} | null}>
|
|
@@ -138,11 +139,12 @@ Aliases: `ls`
|
|
|
138
139
|
linear initiative list [options]
|
|
139
140
|
```
|
|
140
141
|
|
|
141
|
-
| Option
|
|
142
|
-
|
|
|
143
|
-
| `--status <name>`
|
|
144
|
-
| `--owner <who>`
|
|
145
|
-
| `--archived`
|
|
142
|
+
| Option | Description |
|
|
143
|
+
| -------------------- | -------------------------------------------------------------------- |
|
|
144
|
+
| `--status <name>` | filter by status (Planned, Active, Completed, Canceled, Proposed) |
|
|
145
|
+
| `--owner <who>` | filter by owner (me\|email\|name\|id) |
|
|
146
|
+
| `--include-archived` | include archived resources (the API may also return trashed records) |
|
|
147
|
+
| `--archived` | compatibility alias of --include-archived |
|
|
146
148
|
|
|
147
149
|
**Output (`--json`)**: a bare array of objects
|
|
148
150
|
|
|
@@ -154,6 +156,8 @@ priority: number
|
|
|
154
156
|
targetDate: string | null
|
|
155
157
|
health: string | null
|
|
156
158
|
url: string
|
|
159
|
+
archivedAt: string | null
|
|
160
|
+
trashed: boolean
|
|
157
161
|
```
|
|
158
162
|
|
|
159
163
|
### `linear initiative remove-project`
|
|
@@ -250,6 +254,7 @@ updatedAt: string
|
|
|
250
254
|
startedAt: string | null
|
|
251
255
|
completedAt: string | null
|
|
252
256
|
archivedAt: string | null
|
|
257
|
+
trashed: boolean
|
|
253
258
|
owner: string | null
|
|
254
259
|
creator: string | null
|
|
255
260
|
projects: Array<{id: string, name: string, status: {name: string, type: string} | null}>
|