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 +66 -11
- package/bin/dev.js +0 -0
- package/dist/commands/config/get.d.ts +9 -0
- package/dist/commands/config/get.js +37 -0
- package/dist/commands/config/list.d.ts +6 -0
- package/dist/commands/config/list.js +30 -0
- package/dist/commands/config/set.d.ts +10 -0
- package/dist/commands/config/set.js +40 -0
- package/dist/commands/info.d.ts +9 -0
- package/dist/commands/info.js +676 -0
- package/dist/commands/issues/bulk-label.d.ts +11 -0
- package/dist/commands/issues/bulk-label.js +113 -0
- package/dist/commands/issues/bulk-update.d.ts +15 -0
- package/dist/commands/issues/bulk-update.js +131 -0
- package/dist/commands/issues/create.js +6 -3
- package/dist/commands/projects/create.d.ts +1 -1
- package/dist/commands/projects/create.js +14 -3
- package/dist/commands/setup.d.ts +9 -0
- package/dist/commands/setup.js +91 -0
- package/dist/lib/config.d.ts +36 -1
- package/dist/lib/config.js +76 -0
- package/dist/lib/types.d.ts +6 -0
- package/oclif.manifest.json +633 -352
- package/package.json +18 -16
- package/scripts/postinstall.js +97 -0
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. **
|
|
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. **
|
|
384
|
-
4. **
|
|
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.
|
|
390
|
-
linear
|
|
434
|
+
# 1. Get complete CLI documentation in one command
|
|
435
|
+
linear info
|
|
391
436
|
|
|
392
|
-
# 2.
|
|
393
|
-
linear
|
|
437
|
+
# 2. Or get compact version for limited context
|
|
438
|
+
linear info --compact
|
|
394
439
|
|
|
395
|
-
# 3.
|
|
396
|
-
linear issues
|
|
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
|
-
#
|
|
399
|
-
linear
|
|
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,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
|
+
}
|