linear-cli-agents 0.1.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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -0
  3. package/bin/dev.js +5 -0
  4. package/bin/run.js +5 -0
  5. package/dist/commands/auth/login.d.ts +12 -0
  6. package/dist/commands/auth/login.js +52 -0
  7. package/dist/commands/auth/logout.d.ts +6 -0
  8. package/dist/commands/auth/logout.js +26 -0
  9. package/dist/commands/auth/status.d.ts +6 -0
  10. package/dist/commands/auth/status.js +40 -0
  11. package/dist/commands/issues/create.d.ts +18 -0
  12. package/dist/commands/issues/create.js +109 -0
  13. package/dist/commands/issues/delete.d.ts +12 -0
  14. package/dist/commands/issues/delete.js +61 -0
  15. package/dist/commands/issues/get.d.ts +9 -0
  16. package/dist/commands/issues/get.js +81 -0
  17. package/dist/commands/issues/list.d.ts +14 -0
  18. package/dist/commands/issues/list.js +101 -0
  19. package/dist/commands/issues/update.d.ts +20 -0
  20. package/dist/commands/issues/update.js +110 -0
  21. package/dist/commands/query.d.ts +11 -0
  22. package/dist/commands/query.js +94 -0
  23. package/dist/commands/schema.d.ts +13 -0
  24. package/dist/commands/schema.js +198 -0
  25. package/dist/index.d.ts +1 -0
  26. package/dist/index.js +1 -0
  27. package/dist/lib/client.d.ts +17 -0
  28. package/dist/lib/client.js +23 -0
  29. package/dist/lib/config.d.ts +33 -0
  30. package/dist/lib/config.js +97 -0
  31. package/dist/lib/errors.d.ts +30 -0
  32. package/dist/lib/errors.js +79 -0
  33. package/dist/lib/issue-utils.d.ts +17 -0
  34. package/dist/lib/issue-utils.js +56 -0
  35. package/dist/lib/output.d.ts +16 -0
  36. package/dist/lib/output.js +33 -0
  37. package/dist/lib/types.d.ts +33 -0
  38. package/dist/lib/types.js +5 -0
  39. package/oclif.manifest.json +549 -0
  40. package/package.json +69 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # linear-cli
2
+
3
+ A CLI for interacting with [Linear](https://linear.app), designed for LLMs and agents.
4
+
5
+ ## Features
6
+
7
+ - **JSON output**: All commands return structured JSON, perfect for parsing by LLMs
8
+ - **Schema introspection**: Discover available operations programmatically
9
+ - **Full CRUD for issues**: List, create, update, and delete issues
10
+ - **Raw GraphQL queries**: Execute any GraphQL query directly
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ npm install -g linear-cli
16
+ # or
17
+ pnpm add -g linear-cli
18
+ ```
19
+
20
+ ## Authentication
21
+
22
+ Get your API key from [Linear Settings > API](https://linear.app/settings/api).
23
+
24
+ ```bash
25
+ # Login with API key
26
+ linear auth login --key lin_api_xxxxx
27
+
28
+ # Or use environment variable
29
+ export LINEAR_API_KEY=lin_api_xxxxx
30
+
31
+ # Check auth status
32
+ linear auth status
33
+
34
+ # Logout
35
+ linear auth logout
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ### Issues
41
+
42
+ ```bash
43
+ # List all issues
44
+ linear issues list
45
+
46
+ # List with filters
47
+ linear issues list --team ENG
48
+ linear issues list --assignee me
49
+ linear issues list --state "In Progress"
50
+ linear issues list --filter '{"priority":{"lte":2}}'
51
+
52
+ # Get a specific issue
53
+ linear issues get ENG-123
54
+
55
+ # Create an issue
56
+ linear issues create --title "Bug fix" --team-id <team-id>
57
+ linear issues create --input '{"title":"Feature","teamId":"xxx","priority":2}'
58
+
59
+ # Update an issue
60
+ linear issues update ENG-123 --title "Updated title"
61
+ linear issues update ENG-123 --state-id <state-id> --assignee-id <user-id>
62
+
63
+ # Delete an issue (moves to trash)
64
+ linear issues delete ENG-123
65
+ ```
66
+
67
+ ### Schema Introspection (for LLMs)
68
+
69
+ ```bash
70
+ # List available entities
71
+ linear schema
72
+
73
+ # Get schema for a specific entity
74
+ linear schema issues
75
+
76
+ # Get full schema (all entities)
77
+ linear schema --full
78
+
79
+ # Include usage examples
80
+ linear schema issues --include-examples
81
+ ```
82
+
83
+ ### Raw GraphQL Queries
84
+
85
+ ```bash
86
+ # Execute any GraphQL query
87
+ linear query --gql "query { viewer { id name email } }"
88
+
89
+ # With variables
90
+ linear query --gql "query(\$id: String!) { issue(id: \$id) { title } }" \
91
+ --variables '{"id":"xxx"}'
92
+ ```
93
+
94
+ ## Output Format
95
+
96
+ All commands return structured JSON:
97
+
98
+ ```json
99
+ // Success
100
+ {
101
+ "success": true,
102
+ "data": { ... }
103
+ }
104
+
105
+ // Success with pagination
106
+ {
107
+ "success": true,
108
+ "data": [...],
109
+ "pageInfo": {
110
+ "hasNextPage": true,
111
+ "endCursor": "abc123"
112
+ }
113
+ }
114
+
115
+ // Error
116
+ {
117
+ "success": false,
118
+ "error": {
119
+ "code": "NOT_FOUND",
120
+ "message": "Issue ENG-123 not found"
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## For LLM Integration
126
+
127
+ The CLI is designed to be easily used by LLMs and AI agents:
128
+
129
+ 1. **Discover capabilities**: Use `linear schema` to understand available operations
130
+ 2. **Structured output**: All responses are JSON with consistent format
131
+ 3. **Error codes**: Programmatic error handling via error codes
132
+ 4. **Raw queries**: Use `linear query` for complex operations not covered by built-in commands
133
+
134
+ ### Example LLM Workflow
135
+
136
+ ```bash
137
+ # 1. Discover what operations are available
138
+ linear schema
139
+
140
+ # 2. Get details about issues
141
+ linear schema issues
142
+
143
+ # 3. List issues assigned to current user
144
+ linear issues list --assignee me
145
+
146
+ # 4. Create a new issue
147
+ linear issues create --input '{"title":"From LLM","teamId":"xxx"}'
148
+ ```
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ # Install dependencies
154
+ pnpm install
155
+
156
+ # Build
157
+ pnpm build
158
+
159
+ # Run in development
160
+ ./bin/dev.js issues list
161
+
162
+ # Run tests
163
+ pnpm test
164
+ ```
165
+
166
+ ## License
167
+
168
+ MIT
package/bin/dev.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({development: true, dir: import.meta.url})
package/bin/run.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {execute} from '@oclif/core'
4
+
5
+ await execute({dir: import.meta.url})
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class AuthLogin extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ key: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ static args: {
9
+ key: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,52 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { createClient } from '../../lib/client.js';
3
+ import { saveApiKey, getConfigPath } from '../../lib/config.js';
4
+ import { success, print } from '../../lib/output.js';
5
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
6
+ export default class AuthLogin extends Command {
7
+ static description = 'Authenticate with Linear using an API key';
8
+ static examples = [
9
+ '<%= config.bin %> auth login --key lin_api_xxxxx',
10
+ 'LINEAR_API_KEY=lin_api_xxxxx <%= config.bin %> auth login',
11
+ ];
12
+ static flags = {
13
+ key: Flags.string({
14
+ char: 'k',
15
+ description: 'Linear API key (or set LINEAR_API_KEY env var)',
16
+ env: 'LINEAR_API_KEY',
17
+ }),
18
+ };
19
+ static args = {
20
+ key: Args.string({
21
+ description: 'Linear API key (alternative to --key flag)',
22
+ required: false,
23
+ }),
24
+ };
25
+ async run() {
26
+ try {
27
+ const { args, flags } = await this.parse(AuthLogin);
28
+ const apiKey = flags.key || args.key;
29
+ if (!apiKey) {
30
+ throw new CliError(ErrorCodes.MISSING_REQUIRED_FIELD, 'API key is required. Use --key flag or set LINEAR_API_KEY environment variable.');
31
+ }
32
+ // Validate the API key by making a test request
33
+ const client = createClient(apiKey);
34
+ const viewer = await client.viewer;
35
+ // Save the API key
36
+ saveApiKey(apiKey);
37
+ print(success({
38
+ message: 'Successfully authenticated',
39
+ user: {
40
+ id: viewer.id,
41
+ name: viewer.name,
42
+ email: viewer.email,
43
+ },
44
+ configPath: getConfigPath(),
45
+ }));
46
+ }
47
+ catch (err) {
48
+ handleError(err);
49
+ this.exit(1);
50
+ }
51
+ }
52
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class AuthLogout extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,26 @@
1
+ import { Command } from '@oclif/core';
2
+ import { removeApiKey, getConfigPath, getApiKey } from '../../lib/config.js';
3
+ import { success, print } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ export default class AuthLogout extends Command {
6
+ static description = 'Remove stored Linear API key';
7
+ static examples = ['<%= config.bin %> auth logout'];
8
+ async run() {
9
+ await this.parse(AuthLogout);
10
+ try {
11
+ const apiKey = getApiKey();
12
+ if (!apiKey) {
13
+ throw new CliError(ErrorCodes.NOT_AUTHENTICATED, 'Not currently authenticated');
14
+ }
15
+ removeApiKey();
16
+ print(success({
17
+ message: 'Successfully logged out',
18
+ configPath: getConfigPath(),
19
+ }));
20
+ }
21
+ catch (err) {
22
+ handleError(err);
23
+ this.exit(1);
24
+ }
25
+ }
26
+ }
@@ -0,0 +1,6 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class AuthStatus extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
@@ -0,0 +1,40 @@
1
+ import { Command } from '@oclif/core';
2
+ import { getApiKey, getConfigPath } from '../../lib/config.js';
3
+ import { createClient } from '../../lib/client.js';
4
+ import { success, print } from '../../lib/output.js';
5
+ import { handleError } from '../../lib/errors.js';
6
+ export default class AuthStatus extends Command {
7
+ static description = 'Check authentication status';
8
+ static examples = ['<%= config.bin %> auth status'];
9
+ async run() {
10
+ await this.parse(AuthStatus);
11
+ try {
12
+ const apiKey = getApiKey();
13
+ if (!apiKey) {
14
+ print(success({
15
+ authenticated: false,
16
+ message: 'Not authenticated',
17
+ configPath: getConfigPath(),
18
+ }));
19
+ return;
20
+ }
21
+ // Verify the API key is still valid
22
+ const client = createClient(apiKey);
23
+ const viewer = await client.viewer;
24
+ print(success({
25
+ authenticated: true,
26
+ user: {
27
+ id: viewer.id,
28
+ name: viewer.name,
29
+ email: viewer.email,
30
+ },
31
+ source: process.env.LINEAR_API_KEY ? 'environment' : 'config',
32
+ configPath: getConfigPath(),
33
+ }));
34
+ }
35
+ catch (err) {
36
+ handleError(err);
37
+ this.exit(1);
38
+ }
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IssuesCreate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ input: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ 'team-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ priority: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ 'assignee-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'state-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ 'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ estimate: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ 'label-ids': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ };
17
+ run(): Promise<void>;
18
+ }
@@ -0,0 +1,109 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { success, print } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ export default class IssuesCreate extends Command {
6
+ static description = 'Create a new issue';
7
+ static examples = [
8
+ '<%= config.bin %> issues create --input \'{"title":"Bug fix","teamId":"xxx"}\'',
9
+ '<%= config.bin %> issues create --title "New feature" --team-id xxx',
10
+ '<%= config.bin %> issues create --title "Task" --team-id xxx --description "Details here" --priority 2',
11
+ ];
12
+ static flags = {
13
+ input: Flags.string({
14
+ char: 'i',
15
+ description: 'JSON input object (IssueCreateInput)',
16
+ exclusive: ['title'],
17
+ }),
18
+ title: Flags.string({
19
+ description: 'Issue title',
20
+ exclusive: ['input'],
21
+ }),
22
+ 'team-id': Flags.string({
23
+ description: 'Team ID',
24
+ }),
25
+ description: Flags.string({
26
+ char: 'd',
27
+ description: 'Issue description (markdown supported)',
28
+ }),
29
+ priority: Flags.integer({
30
+ char: 'p',
31
+ description: 'Priority (0=none, 1=urgent, 2=high, 3=medium, 4=low)',
32
+ }),
33
+ 'assignee-id': Flags.string({
34
+ description: 'Assignee user ID',
35
+ }),
36
+ 'state-id': Flags.string({
37
+ description: 'State ID',
38
+ }),
39
+ 'project-id': Flags.string({
40
+ description: 'Project ID',
41
+ }),
42
+ estimate: Flags.integer({
43
+ description: 'Estimate points',
44
+ }),
45
+ 'label-ids': Flags.string({
46
+ description: 'Comma-separated label IDs',
47
+ }),
48
+ };
49
+ async run() {
50
+ try {
51
+ const { flags } = await this.parse(IssuesCreate);
52
+ const client = getClient();
53
+ let input;
54
+ if (flags.input) {
55
+ // Parse JSON input
56
+ try {
57
+ input = JSON.parse(flags.input);
58
+ }
59
+ catch {
60
+ throw new CliError(ErrorCodes.INVALID_INPUT, 'Invalid JSON in --input flag');
61
+ }
62
+ }
63
+ else {
64
+ // Build input from individual flags
65
+ if (!flags.title) {
66
+ throw new CliError(ErrorCodes.MISSING_REQUIRED_FIELD, 'Title is required. Use --title or --input');
67
+ }
68
+ if (!flags['team-id']) {
69
+ throw new CliError(ErrorCodes.MISSING_REQUIRED_FIELD, 'Team ID is required. Use --team-id or --input');
70
+ }
71
+ input = {
72
+ title: flags.title,
73
+ teamId: flags['team-id'],
74
+ };
75
+ if (flags.description)
76
+ input.description = flags.description;
77
+ if (flags.priority !== undefined)
78
+ input.priority = flags.priority;
79
+ if (flags['assignee-id'])
80
+ input.assigneeId = flags['assignee-id'];
81
+ if (flags['state-id'])
82
+ input.stateId = flags['state-id'];
83
+ if (flags['project-id'])
84
+ input.projectId = flags['project-id'];
85
+ if (flags.estimate !== undefined)
86
+ input.estimate = flags.estimate;
87
+ if (flags['label-ids'])
88
+ input.labelIds = flags['label-ids'].split(',');
89
+ }
90
+ // Create the issue
91
+ const payload = await client.createIssue(input);
92
+ const issue = await payload.issue;
93
+ if (!issue) {
94
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to create issue');
95
+ }
96
+ print(success({
97
+ id: issue.id,
98
+ identifier: issue.identifier,
99
+ title: issue.title,
100
+ url: issue.url,
101
+ createdAt: issue.createdAt,
102
+ }));
103
+ }
104
+ catch (err) {
105
+ handleError(err);
106
+ this.exit(1);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IssuesDelete extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ permanent: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,61 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { success, print } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ import { resolveIssueId } from '../../lib/issue-utils.js';
6
+ export default class IssuesDelete extends Command {
7
+ static description = 'Delete an issue (moves to trash)';
8
+ static examples = [
9
+ '<%= config.bin %> issues delete abc123',
10
+ '<%= config.bin %> issues delete ENG-123',
11
+ '<%= config.bin %> issues delete ENG-123 --permanent',
12
+ ];
13
+ static args = {
14
+ id: Args.string({
15
+ description: 'Issue ID or identifier (e.g., ENG-123)',
16
+ required: true,
17
+ }),
18
+ };
19
+ static flags = {
20
+ permanent: Flags.boolean({
21
+ description: 'Permanently delete (cannot be undone)',
22
+ default: false,
23
+ }),
24
+ };
25
+ async run() {
26
+ try {
27
+ const { args, flags } = await this.parse(IssuesDelete);
28
+ const client = getClient();
29
+ const issueId = await resolveIssueId(client, args.id);
30
+ // Get issue info before deletion
31
+ const issue = await client.issue(issueId);
32
+ if (!issue) {
33
+ throw new CliError(ErrorCodes.NOT_FOUND, `Issue ${args.id} not found`);
34
+ }
35
+ const identifier = issue.identifier;
36
+ // Delete the issue
37
+ if (flags.permanent) {
38
+ // Archive first, then delete permanently
39
+ await client.archiveIssue(issueId);
40
+ await client.deleteIssue(issueId);
41
+ }
42
+ else {
43
+ // Just archive (trash)
44
+ await client.archiveIssue(issueId);
45
+ }
46
+ print(success({
47
+ id: issueId,
48
+ identifier,
49
+ deleted: true,
50
+ permanent: flags.permanent,
51
+ message: flags.permanent
52
+ ? `Issue ${identifier} permanently deleted`
53
+ : `Issue ${identifier} moved to trash`,
54
+ }));
55
+ }
56
+ catch (err) {
57
+ handleError(err);
58
+ this.exit(1);
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IssuesGet extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
@@ -0,0 +1,81 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { success, print } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ import { resolveIssueId } from '../../lib/issue-utils.js';
6
+ export default class IssuesGet extends Command {
7
+ static description = 'Get a single issue by ID or identifier';
8
+ static examples = [
9
+ '<%= config.bin %> issues get abc123',
10
+ '<%= config.bin %> issues get ENG-123',
11
+ ];
12
+ static args = {
13
+ id: Args.string({
14
+ description: 'Issue ID or identifier (e.g., ENG-123)',
15
+ required: true,
16
+ }),
17
+ };
18
+ async run() {
19
+ try {
20
+ const { args } = await this.parse(IssuesGet);
21
+ const client = getClient();
22
+ const issueId = await resolveIssueId(client, args.id);
23
+ const issue = await client.issue(issueId);
24
+ if (!issue) {
25
+ throw new CliError(ErrorCodes.NOT_FOUND, `Issue ${args.id} not found`);
26
+ }
27
+ // Fetch related data
28
+ const [state, assignee, team, labels, comments] = await Promise.all([
29
+ issue.state,
30
+ issue.assignee,
31
+ issue.team,
32
+ issue.labels(),
33
+ issue.comments(),
34
+ ]);
35
+ print(success({
36
+ id: issue.id,
37
+ identifier: issue.identifier,
38
+ title: issue.title,
39
+ description: issue.description,
40
+ priority: issue.priority,
41
+ priorityLabel: issue.priorityLabel,
42
+ estimate: issue.estimate,
43
+ url: issue.url,
44
+ createdAt: issue.createdAt,
45
+ updatedAt: issue.updatedAt,
46
+ state: state
47
+ ? {
48
+ id: state.id,
49
+ name: state.name,
50
+ color: state.color,
51
+ type: state.type,
52
+ }
53
+ : null,
54
+ assignee: assignee
55
+ ? {
56
+ id: assignee.id,
57
+ name: assignee.name,
58
+ email: assignee.email,
59
+ }
60
+ : null,
61
+ team: team
62
+ ? {
63
+ id: team.id,
64
+ key: team.key,
65
+ name: team.name,
66
+ }
67
+ : null,
68
+ labels: labels.nodes.map((label) => ({
69
+ id: label.id,
70
+ name: label.name,
71
+ color: label.color,
72
+ })),
73
+ commentsCount: comments.nodes.length,
74
+ }));
75
+ }
76
+ catch (err) {
77
+ handleError(err);
78
+ this.exit(1);
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,14 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class IssuesList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ team: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ assignee: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ state: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ filter: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ first: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
11
+ after: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ run(): Promise<void>;
14
+ }