linear-cli-agents 0.2.1 → 0.4.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 (78) hide show
  1. package/README.md +166 -3
  2. package/bin/dev.js +0 -0
  3. package/dist/commands/comments/add.d.ts +13 -0
  4. package/dist/commands/comments/add.js +89 -0
  5. package/dist/commands/comments/delete.d.ts +12 -0
  6. package/dist/commands/comments/delete.js +50 -0
  7. package/dist/commands/comments/list.d.ts +14 -0
  8. package/dist/commands/comments/list.js +103 -0
  9. package/dist/commands/comments/update.d.ts +13 -0
  10. package/dist/commands/comments/update.js +81 -0
  11. package/dist/commands/issues/add-labels.d.ts +13 -0
  12. package/dist/commands/issues/add-labels.js +90 -0
  13. package/dist/commands/issues/archive.d.ts +13 -0
  14. package/dist/commands/issues/archive.js +83 -0
  15. package/dist/commands/issues/remove-labels.d.ts +13 -0
  16. package/dist/commands/issues/remove-labels.js +90 -0
  17. package/dist/commands/labels/create.d.ts +14 -0
  18. package/dist/commands/labels/create.js +102 -0
  19. package/dist/commands/labels/delete.d.ts +12 -0
  20. package/dist/commands/labels/delete.js +50 -0
  21. package/dist/commands/labels/list.d.ts +12 -0
  22. package/dist/commands/labels/list.js +117 -0
  23. package/dist/commands/labels/update.d.ts +16 -0
  24. package/dist/commands/labels/update.js +109 -0
  25. package/dist/commands/me.js +1 -5
  26. package/dist/commands/milestones/create.d.ts +15 -0
  27. package/dist/commands/milestones/create.js +90 -0
  28. package/dist/commands/milestones/get.d.ts +12 -0
  29. package/dist/commands/milestones/get.js +74 -0
  30. package/dist/commands/milestones/list.d.ts +14 -0
  31. package/dist/commands/milestones/list.js +97 -0
  32. package/dist/commands/milestones/update.d.ts +15 -0
  33. package/dist/commands/milestones/update.js +94 -0
  34. package/dist/commands/project-updates/create.d.ts +14 -0
  35. package/dist/commands/project-updates/create.js +96 -0
  36. package/dist/commands/project-updates/get.d.ts +12 -0
  37. package/dist/commands/project-updates/get.js +80 -0
  38. package/dist/commands/project-updates/list.d.ts +14 -0
  39. package/dist/commands/project-updates/list.js +120 -0
  40. package/dist/commands/project-updates/update.d.ts +14 -0
  41. package/dist/commands/project-updates/update.js +96 -0
  42. package/dist/commands/projects/archive.d.ts +13 -0
  43. package/dist/commands/projects/archive.js +79 -0
  44. package/dist/commands/projects/create.d.ts +16 -0
  45. package/dist/commands/projects/create.js +115 -0
  46. package/dist/commands/projects/delete.d.ts +12 -0
  47. package/dist/commands/projects/delete.js +50 -0
  48. package/dist/commands/projects/get.d.ts +12 -0
  49. package/dist/commands/projects/get.js +102 -0
  50. package/dist/commands/projects/list.d.ts +13 -0
  51. package/dist/commands/projects/list.js +141 -0
  52. package/dist/commands/projects/update.d.ts +18 -0
  53. package/dist/commands/projects/update.js +125 -0
  54. package/dist/commands/relations/create.d.ts +14 -0
  55. package/dist/commands/relations/create.js +98 -0
  56. package/dist/commands/relations/delete.d.ts +12 -0
  57. package/dist/commands/relations/delete.js +47 -0
  58. package/dist/commands/relations/list.d.ts +12 -0
  59. package/dist/commands/relations/list.js +128 -0
  60. package/dist/commands/search.d.ts +15 -0
  61. package/dist/commands/search.js +102 -0
  62. package/dist/commands/states/list.d.ts +12 -0
  63. package/dist/commands/states/list.js +151 -0
  64. package/dist/commands/templates/create.d.ts +14 -0
  65. package/dist/commands/templates/create.js +102 -0
  66. package/dist/commands/templates/get.d.ts +12 -0
  67. package/dist/commands/templates/get.js +84 -0
  68. package/dist/commands/templates/list.d.ts +12 -0
  69. package/dist/commands/templates/list.js +110 -0
  70. package/dist/commands/templates/update.d.ts +15 -0
  71. package/dist/commands/templates/update.js +101 -0
  72. package/dist/commands/users/get.d.ts +12 -0
  73. package/dist/commands/users/get.js +91 -0
  74. package/dist/commands/users/list.d.ts +12 -0
  75. package/dist/commands/users/list.js +99 -0
  76. package/dist/lib/config.js +1 -1
  77. package/oclif.manifest.json +2397 -184
  78. package/package.json +47 -17
@@ -0,0 +1,101 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { success, print, printItem } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ export default class TemplatesUpdate extends Command {
6
+ static description = 'Update a template';
7
+ static examples = [
8
+ '<%= config.bin %> templates update TEMPLATE_ID --name "Updated Name"',
9
+ '<%= config.bin %> templates update TEMPLATE_ID --template-data \'{"title":"New Bug: ","priority":1}\'',
10
+ ];
11
+ static args = {
12
+ id: Args.string({
13
+ description: 'Template ID',
14
+ required: true,
15
+ }),
16
+ };
17
+ static flags = {
18
+ format: Flags.string({
19
+ char: 'F',
20
+ description: 'Output format',
21
+ options: ['json', 'table', 'plain'],
22
+ default: 'json',
23
+ }),
24
+ name: Flags.string({
25
+ char: 'n',
26
+ description: 'Template name',
27
+ }),
28
+ description: Flags.string({
29
+ char: 'd',
30
+ description: 'Template description',
31
+ }),
32
+ 'template-data': Flags.string({
33
+ description: 'Template data as JSON',
34
+ }),
35
+ };
36
+ async run() {
37
+ try {
38
+ const { args, flags } = await this.parse(TemplatesUpdate);
39
+ const format = flags.format;
40
+ const client = getClient();
41
+ const input = {};
42
+ if (flags.name)
43
+ input.name = flags.name;
44
+ if (flags.description)
45
+ input.description = flags.description;
46
+ if (flags['template-data']) {
47
+ try {
48
+ input.templateData = JSON.parse(flags['template-data']);
49
+ }
50
+ catch {
51
+ throw new CliError(ErrorCodes.INVALID_INPUT, 'Invalid JSON in --template-data');
52
+ }
53
+ }
54
+ if (Object.keys(input).length === 0) {
55
+ throw new CliError(ErrorCodes.INVALID_INPUT, 'At least one field to update is required');
56
+ }
57
+ const payload = await client.updateTemplate(args.id, input);
58
+ if (!payload.success || !payload.template) {
59
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to update template');
60
+ }
61
+ const template = await payload.template;
62
+ const team = await template.team;
63
+ const data = {
64
+ id: template.id,
65
+ name: template.name,
66
+ type: template.type,
67
+ description: template.description,
68
+ templateData: template.templateData,
69
+ team: team
70
+ ? {
71
+ id: team.id,
72
+ key: team.key,
73
+ name: team.name,
74
+ }
75
+ : null,
76
+ createdAt: template.createdAt,
77
+ updatedAt: template.updatedAt,
78
+ };
79
+ if (format === 'json') {
80
+ print(success(data));
81
+ }
82
+ else if (format === 'table') {
83
+ printItem({
84
+ id: data.id,
85
+ name: data.name,
86
+ type: data.type,
87
+ description: data.description ?? 'N/A',
88
+ team: data.team?.key ?? 'Organization',
89
+ updatedAt: data.updatedAt,
90
+ }, format);
91
+ }
92
+ else {
93
+ console.log(data.id);
94
+ }
95
+ }
96
+ catch (err) {
97
+ handleError(err);
98
+ this.exit(1);
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class UsersGet 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
+ format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,91 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { success, print, printItem } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ export default class UsersGet extends Command {
6
+ static description = 'Get a single user by ID';
7
+ static examples = [
8
+ '<%= config.bin %> users get USER_ID',
9
+ '<%= config.bin %> users get USER_ID --format table',
10
+ '<%= config.bin %> users get me',
11
+ ];
12
+ static args = {
13
+ id: Args.string({
14
+ description: 'User ID (use "me" for current user)',
15
+ required: true,
16
+ }),
17
+ };
18
+ static flags = {
19
+ format: Flags.string({
20
+ char: 'F',
21
+ description: 'Output format',
22
+ options: ['json', 'table', 'plain'],
23
+ default: 'json',
24
+ }),
25
+ };
26
+ async run() {
27
+ try {
28
+ const { args, flags } = await this.parse(UsersGet);
29
+ const format = flags.format;
30
+ const client = getClient();
31
+ let user;
32
+ if (args.id === 'me') {
33
+ user = await client.viewer;
34
+ }
35
+ else {
36
+ user = await client.user(args.id);
37
+ }
38
+ if (!user) {
39
+ throw new CliError(ErrorCodes.NOT_FOUND, `User ${args.id} not found`);
40
+ }
41
+ // Fetch assigned issues count
42
+ const assignedIssues = await user.assignedIssues({ first: 0 });
43
+ const teams = await user.teams();
44
+ const data = {
45
+ id: user.id,
46
+ name: user.name,
47
+ displayName: user.displayName,
48
+ email: user.email,
49
+ active: user.active,
50
+ admin: user.admin,
51
+ guest: user.guest,
52
+ avatarUrl: user.avatarUrl ?? undefined,
53
+ timezone: user.timezone,
54
+ createdAt: user.createdAt,
55
+ updatedAt: user.updatedAt,
56
+ assignedIssuesCount: assignedIssues.pageInfo.hasNextPage ? '50+' : assignedIssues.nodes.length,
57
+ teams: teams.nodes.map((team) => ({
58
+ id: team.id,
59
+ key: team.key,
60
+ name: team.name,
61
+ })),
62
+ };
63
+ if (format === 'json') {
64
+ print(success(data));
65
+ }
66
+ else if (format === 'table') {
67
+ printItem({
68
+ id: data.id,
69
+ name: data.name,
70
+ displayName: data.displayName,
71
+ email: data.email,
72
+ active: data.active ? 'Yes' : 'No',
73
+ admin: data.admin ? 'Yes' : 'No',
74
+ guest: data.guest ? 'Yes' : 'No',
75
+ timezone: data.timezone ?? 'N/A',
76
+ assignedIssues: data.assignedIssuesCount,
77
+ teams: data.teams.map((t) => t.key).join(', ') || 'None',
78
+ createdAt: data.createdAt,
79
+ }, format);
80
+ }
81
+ else {
82
+ // plain: just the ID
83
+ console.log(data.id);
84
+ }
85
+ }
86
+ catch (err) {
87
+ handleError(err);
88
+ this.exit(1);
89
+ }
90
+ }
91
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class UsersList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ active: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ first: import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
9
+ after: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,99 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { successList, print, printList } from '../../lib/output.js';
4
+ import { handleError } from '../../lib/errors.js';
5
+ import { colors } from '../../lib/formatter.js';
6
+ const COLUMNS = [
7
+ {
8
+ key: 'name',
9
+ header: 'NAME',
10
+ format: (value) => colors.bold(String(value)),
11
+ },
12
+ {
13
+ key: 'email',
14
+ header: 'EMAIL',
15
+ format: (value) => colors.dim(String(value)),
16
+ },
17
+ {
18
+ key: 'active',
19
+ header: 'ACTIVE',
20
+ format: (value) => (value ? colors.green('Yes') : colors.red('No')),
21
+ },
22
+ {
23
+ key: 'admin',
24
+ header: 'ADMIN',
25
+ format: (value) => (value ? colors.yellow('Yes') : colors.gray('No')),
26
+ },
27
+ ];
28
+ export default class UsersList extends Command {
29
+ static description = 'List users in the workspace';
30
+ static examples = [
31
+ '<%= config.bin %> users list',
32
+ '<%= config.bin %> users list --format table',
33
+ '<%= config.bin %> users list --active',
34
+ ];
35
+ static flags = {
36
+ format: Flags.string({
37
+ char: 'F',
38
+ description: 'Output format',
39
+ options: ['json', 'table', 'plain'],
40
+ default: 'json',
41
+ }),
42
+ active: Flags.boolean({
43
+ description: 'Show only active users',
44
+ default: false,
45
+ }),
46
+ first: Flags.integer({
47
+ description: 'Number of users to fetch (default: 100)',
48
+ default: 100,
49
+ }),
50
+ after: Flags.string({
51
+ description: 'Cursor for pagination',
52
+ }),
53
+ };
54
+ async run() {
55
+ try {
56
+ const { flags } = await this.parse(UsersList);
57
+ const format = flags.format;
58
+ const client = getClient();
59
+ const filter = flags.active ? { active: { eq: true } } : undefined;
60
+ const users = await client.users({
61
+ filter,
62
+ first: flags.first,
63
+ after: flags.after,
64
+ });
65
+ const data = users.nodes.map((user) => ({
66
+ id: user.id,
67
+ name: user.name,
68
+ displayName: user.displayName,
69
+ email: user.email,
70
+ active: user.active,
71
+ admin: user.admin,
72
+ guest: user.guest,
73
+ avatarUrl: user.avatarUrl ?? undefined,
74
+ createdAt: user.createdAt,
75
+ }));
76
+ const pageInfo = {
77
+ hasNextPage: users.pageInfo.hasNextPage,
78
+ hasPreviousPage: users.pageInfo.hasPreviousPage,
79
+ startCursor: users.pageInfo.startCursor,
80
+ endCursor: users.pageInfo.endCursor,
81
+ };
82
+ if (format === 'json') {
83
+ print(successList(data, pageInfo));
84
+ }
85
+ else {
86
+ printList(data, format, {
87
+ columns: COLUMNS,
88
+ primaryKey: 'name',
89
+ secondaryKey: 'email',
90
+ pageInfo,
91
+ });
92
+ }
93
+ }
94
+ catch (err) {
95
+ handleError(err);
96
+ this.exit(1);
97
+ }
98
+ }
99
+ }
@@ -2,7 +2,7 @@ import { homedir } from 'node:os';
2
2
  import { join } from 'node:path';
3
3
  import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, unlinkSync } from 'node:fs';
4
4
  import { CliError, ErrorCodes } from './errors.js';
5
- const CONFIG_DIR = join(homedir(), '.linear-cli');
5
+ const CONFIG_DIR = join(homedir(), '.linear-cli-agents');
6
6
  const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
7
7
  /**
8
8
  * Ensure the config directory exists.