linear-cli-agents 0.4.1 → 0.5.1

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/README.md CHANGED
@@ -10,6 +10,9 @@ A CLI for interacting with [Linear](https://linear.app), designed for LLMs and a
10
10
 
11
11
  - **JSON output**: All commands return structured JSON, perfect for parsing by LLMs
12
12
  - **Multiple formats**: JSON (default), table (colored), or plain text output
13
+ - **Comprehensive docs**: `linear info` returns full CLI documentation in one command
14
+ - **Configurable defaults**: Set default team to skip `--team-id` on every command
15
+ - **Bulk operations**: Update multiple issues at once with `bulk-update` and `bulk-label`
13
16
  - **Schema introspection**: Discover available operations programmatically
14
17
  - **Full CRUD**: Issues, projects, labels, comments, templates, milestones
15
18
  - **Issue relations**: Manage blocks, duplicates, and related issues
@@ -27,6 +30,25 @@ npm install -g linear-cli-agents
27
30
  pnpm add -g linear-cli-agents
28
31
  ```
29
32
 
33
+ ## Quick Start
34
+
35
+ ```bash
36
+ # Install
37
+ npm install -g linear-cli-agents
38
+
39
+ # Authenticate
40
+ linear auth login
41
+
42
+ # Get full CLI documentation (recommended for LLMs)
43
+ linear info
44
+
45
+ # Configure default team (optional, skips --team-id on every command)
46
+ linear config set default-team-id YOUR_TEAM_ID
47
+
48
+ # Add CLI instructions to your CLAUDE.md (optional)
49
+ linear setup
50
+ ```
51
+
30
52
  ## Authentication
31
53
 
32
54
  ```bash
@@ -49,6 +71,20 @@ linear me
49
71
  linear auth logout
50
72
  ```
51
73
 
74
+ ## Configuration
75
+
76
+ ```bash
77
+ # Set default team (skips --team-id on create commands)
78
+ linear config set default-team-id YOUR_TEAM_UUID
79
+ linear config set default-team-key TEAM_KEY
80
+
81
+ # Get a config value
82
+ linear config get default-team-id
83
+
84
+ # List all config
85
+ linear config list
86
+ ```
87
+
52
88
  ## Usage
53
89
 
54
90
  ### Issues
@@ -89,6 +125,14 @@ linear issues archive ENG-123 --unarchive
89
125
  # Manage labels on issues
90
126
  linear issues add-labels ENG-123 --label-ids LABEL_ID1,LABEL_ID2
91
127
  linear issues remove-labels ENG-123 --label-ids LABEL_ID1
128
+
129
+ # Bulk update multiple issues at once
130
+ linear issues bulk-update --ids ENG-1,ENG-2,ENG-3 --state-id STATE_ID
131
+ linear issues bulk-update --ids ENG-1,ENG-2 --priority 2 --assignee-id USER_ID
132
+
133
+ # Bulk add/remove labels from multiple issues
134
+ linear issues bulk-label --ids ENG-1,ENG-2,ENG-3 --add-labels LABEL1,LABEL2
135
+ linear issues bulk-label --ids ENG-1,ENG-2 --remove-labels LABEL1
92
136
  ```
93
137
 
94
138
  ### Projects
@@ -378,25 +422,36 @@ linear issues list --format table --no-color
378
422
 
379
423
  The CLI is designed to be easily used by LLMs and AI agents:
380
424
 
381
- 1. **Discover capabilities**: Use `linear schema` to understand available operations
425
+ 1. **Single discovery command**: Use `linear info` to get complete documentation in one JSON response
382
426
  2. **Structured output**: All responses are JSON with consistent format
383
- 3. **Error codes**: Programmatic error handling via error codes
384
- 4. **Raw queries**: Use `linear query` for complex operations not covered by built-in commands
427
+ 3. **Configurable defaults**: Set default team to reduce command complexity
428
+ 4. **Bulk operations**: Update multiple issues efficiently
429
+ 5. **Error codes**: Programmatic error handling via error codes
385
430
 
386
431
  ### Example LLM Workflow
387
432
 
388
433
  ```bash
389
- # 1. Discover what operations are available
390
- linear schema
434
+ # 1. Get complete CLI documentation in one command
435
+ linear info
391
436
 
392
- # 2. Get details about issues
393
- linear schema issues
437
+ # 2. Or get compact version for limited context
438
+ linear info --compact
394
439
 
395
- # 3. List issues assigned to current user
396
- linear issues list --assignee me
440
+ # 3. Create issues (uses default team if configured)
441
+ linear issues create --title "From LLM"
442
+
443
+ # 4. Bulk update multiple issues
444
+ linear issues bulk-update --ids ENG-1,ENG-2,ENG-3 --state-id STATE_ID
445
+ ```
446
+
447
+ ### Claude Code Integration
448
+
449
+ ```bash
450
+ # Add CLI instructions to CLAUDE.md
451
+ linear setup
397
452
 
398
- # 4. Create a new issue
399
- linear issues create --input '{"title":"From LLM","teamId":"xxx"}'
453
+ # Remove instructions
454
+ linear setup --remove
400
455
  ```
401
456
 
402
457
  ## Development
package/bin/dev.js CHANGED
File without changes
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ConfigGet extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,37 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { success, print } from '../../lib/output.js';
3
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
4
+ import { getDefaults, isValidConfigKey, configKeyToDefaultsKey, CONFIG_KEYS } from '../../lib/config.js';
5
+ export default class ConfigGet extends Command {
6
+ static description = 'Get a configuration value';
7
+ static examples = [
8
+ '<%= config.bin %> config get default-team-id',
9
+ '<%= config.bin %> config get default-team-key',
10
+ ];
11
+ static args = {
12
+ key: Args.string({
13
+ description: `Config key (${CONFIG_KEYS.join(', ')})`,
14
+ required: true,
15
+ }),
16
+ };
17
+ async run() {
18
+ try {
19
+ const { args } = await this.parse(ConfigGet);
20
+ if (!isValidConfigKey(args.key)) {
21
+ throw new CliError(ErrorCodes.INVALID_INPUT, `Invalid config key: ${args.key}. Valid keys: ${CONFIG_KEYS.join(', ')}`);
22
+ }
23
+ const defaults = getDefaults();
24
+ const defaultsKey = configKeyToDefaultsKey(args.key);
25
+ const value = defaults[defaultsKey];
26
+ print(success({
27
+ key: args.key,
28
+ value: value ?? null,
29
+ isSet: value !== undefined,
30
+ }));
31
+ }
32
+ catch (err) {
33
+ handleError(err);
34
+ this.exit(1);
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ConfigList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,30 @@
1
+ import { Command } from '@oclif/core';
2
+ import { success, print } from '../../lib/output.js';
3
+ import { handleError } from '../../lib/errors.js';
4
+ import { getDefaults, getApiKey, getConfigPath, CONFIG_KEYS, configKeyToDefaultsKey } from '../../lib/config.js';
5
+ export default class ConfigList extends Command {
6
+ static description = 'List all configuration values';
7
+ static examples = ['<%= config.bin %> config list'];
8
+ async run() {
9
+ try {
10
+ const defaults = getDefaults();
11
+ const apiKey = getApiKey();
12
+ const config = {};
13
+ // Add all config keys with their values
14
+ for (const key of CONFIG_KEYS) {
15
+ const defaultsKey = configKeyToDefaultsKey(key);
16
+ config[key] = defaults[defaultsKey] ?? null;
17
+ }
18
+ print(success({
19
+ configPath: getConfigPath(),
20
+ authenticated: apiKey !== undefined,
21
+ apiKeySource: apiKey ? (process.env.LINEAR_API_KEY ? 'environment' : 'config') : null,
22
+ defaults: config,
23
+ }));
24
+ }
25
+ catch (err) {
26
+ handleError(err);
27
+ this.exit(1);
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ConfigSet extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ key: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ value: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,40 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { success, print } from '../../lib/output.js';
3
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
4
+ import { setDefault, isValidConfigKey, configKeyToDefaultsKey, CONFIG_KEYS } from '../../lib/config.js';
5
+ export default class ConfigSet extends Command {
6
+ static description = 'Set a configuration value';
7
+ static examples = [
8
+ '<%= config.bin %> config set default-team-id d1ad1a80-9267-4ebc-979a-eaf885898a2c',
9
+ '<%= config.bin %> config set default-team-key MITO',
10
+ ];
11
+ static args = {
12
+ key: Args.string({
13
+ description: `Config key (${CONFIG_KEYS.join(', ')})`,
14
+ required: true,
15
+ }),
16
+ value: Args.string({
17
+ description: 'Config value',
18
+ required: true,
19
+ }),
20
+ };
21
+ async run() {
22
+ try {
23
+ const { args } = await this.parse(ConfigSet);
24
+ if (!isValidConfigKey(args.key)) {
25
+ throw new CliError(ErrorCodes.INVALID_INPUT, `Invalid config key: ${args.key}. Valid keys: ${CONFIG_KEYS.join(', ')}`);
26
+ }
27
+ const defaultsKey = configKeyToDefaultsKey(args.key);
28
+ setDefault(defaultsKey, args.value);
29
+ print(success({
30
+ key: args.key,
31
+ value: args.value,
32
+ message: `Configuration "${args.key}" set successfully`,
33
+ }));
34
+ }
35
+ catch (err) {
36
+ handleError(err);
37
+ this.exit(1);
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class Info extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ compact: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ }