linear-cli-agents 0.2.0 → 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 +253 -5
  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,109 @@
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 LabelsUpdate extends Command {
6
+ static description = 'Update a label';
7
+ static examples = [
8
+ '<%= config.bin %> labels update LABEL_ID --name "Updated Name"',
9
+ '<%= config.bin %> labels update LABEL_ID --color "#00FF00"',
10
+ '<%= config.bin %> labels update LABEL_ID --description "New description"',
11
+ ];
12
+ static args = {
13
+ id: Args.string({
14
+ description: 'Label ID',
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
+ name: Flags.string({
26
+ char: 'n',
27
+ description: 'Label name',
28
+ }),
29
+ color: Flags.string({
30
+ char: 'c',
31
+ description: 'Label color (hex, e.g., #FF0000)',
32
+ }),
33
+ description: Flags.string({
34
+ char: 'd',
35
+ description: 'Label description',
36
+ }),
37
+ 'parent-id': Flags.string({
38
+ description: 'Parent label ID',
39
+ }),
40
+ };
41
+ async run() {
42
+ try {
43
+ const { args, flags } = await this.parse(LabelsUpdate);
44
+ const format = flags.format;
45
+ const client = getClient();
46
+ const input = {};
47
+ if (flags.name)
48
+ input.name = flags.name;
49
+ if (flags.color)
50
+ input.color = flags.color;
51
+ if (flags.description)
52
+ input.description = flags.description;
53
+ if (flags['parent-id'])
54
+ input.parentId = flags['parent-id'];
55
+ if (Object.keys(input).length === 0) {
56
+ throw new CliError(ErrorCodes.INVALID_INPUT, 'At least one field to update is required');
57
+ }
58
+ const payload = await client.updateIssueLabel(args.id, input);
59
+ if (!payload.success || !payload.issueLabel) {
60
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to update label');
61
+ }
62
+ const label = await payload.issueLabel;
63
+ const [team, parent] = await Promise.all([label.team, label.parent]);
64
+ const data = {
65
+ id: label.id,
66
+ name: label.name,
67
+ color: label.color,
68
+ description: label.description,
69
+ isGroup: label.isGroup,
70
+ team: team
71
+ ? {
72
+ id: team.id,
73
+ key: team.key,
74
+ name: team.name,
75
+ }
76
+ : null,
77
+ parent: parent
78
+ ? {
79
+ id: parent.id,
80
+ name: parent.name,
81
+ }
82
+ : null,
83
+ createdAt: label.createdAt,
84
+ updatedAt: label.updatedAt,
85
+ };
86
+ if (format === 'json') {
87
+ print(success(data));
88
+ }
89
+ else if (format === 'table') {
90
+ printItem({
91
+ id: data.id,
92
+ name: data.name,
93
+ color: data.color,
94
+ description: data.description ?? 'N/A',
95
+ team: data.team?.key ?? 'Workspace',
96
+ parent: data.parent?.name ?? 'N/A',
97
+ updatedAt: data.updatedAt,
98
+ }, format);
99
+ }
100
+ else {
101
+ console.log(data.id);
102
+ }
103
+ }
104
+ catch (err) {
105
+ handleError(err);
106
+ this.exit(1);
107
+ }
108
+ }
109
+ }
@@ -5,11 +5,7 @@ import { handleError } from '../lib/errors.js';
5
5
  export default class Me extends Command {
6
6
  static description = 'Show current user information';
7
7
  static aliases = ['whoami'];
8
- static examples = [
9
- '<%= config.bin %> me',
10
- '<%= config.bin %> me --format table',
11
- '<%= config.bin %> whoami',
12
- ];
8
+ static examples = ['<%= config.bin %> me', '<%= config.bin %> me --format table', '<%= config.bin %> whoami'];
13
9
  static flags = {
14
10
  format: Flags.string({
15
11
  char: 'F',
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class MilestonesCreate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ projectId: 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
+ name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'target-date': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,90 @@
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 MilestonesCreate extends Command {
6
+ static description = 'Create a project milestone';
7
+ static examples = [
8
+ '<%= config.bin %> milestones create PROJECT_ID --name "Beta Release"',
9
+ '<%= config.bin %> milestones create PROJECT_ID --name "Launch" --target-date 2024-03-01',
10
+ ];
11
+ static args = {
12
+ projectId: Args.string({
13
+ description: 'Project 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: 'Milestone name',
27
+ required: true,
28
+ }),
29
+ description: Flags.string({
30
+ char: 'd',
31
+ description: 'Milestone description',
32
+ }),
33
+ 'target-date': Flags.string({
34
+ description: 'Target date (YYYY-MM-DD)',
35
+ }),
36
+ };
37
+ async run() {
38
+ try {
39
+ const { args, flags } = await this.parse(MilestonesCreate);
40
+ const format = flags.format;
41
+ const client = getClient();
42
+ const project = await client.project(args.projectId);
43
+ if (!project) {
44
+ throw new CliError(ErrorCodes.NOT_FOUND, `Project ${args.projectId} not found`);
45
+ }
46
+ const payload = await client.createProjectMilestone({
47
+ projectId: args.projectId,
48
+ name: flags.name,
49
+ description: flags.description,
50
+ targetDate: flags['target-date'],
51
+ });
52
+ if (!payload.success || !payload.projectMilestone) {
53
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to create milestone');
54
+ }
55
+ const milestone = await payload.projectMilestone;
56
+ const data = {
57
+ id: milestone.id,
58
+ name: milestone.name,
59
+ description: milestone.description,
60
+ targetDate: milestone.targetDate,
61
+ sortOrder: milestone.sortOrder,
62
+ project: {
63
+ id: project.id,
64
+ name: project.name,
65
+ },
66
+ createdAt: milestone.createdAt,
67
+ };
68
+ if (format === 'json') {
69
+ print(success(data));
70
+ }
71
+ else if (format === 'table') {
72
+ printItem({
73
+ id: data.id,
74
+ name: data.name,
75
+ description: data.description ?? 'N/A',
76
+ targetDate: data.targetDate ?? 'N/A',
77
+ project: data.project.name,
78
+ createdAt: data.createdAt,
79
+ }, format);
80
+ }
81
+ else {
82
+ console.log(data.id);
83
+ }
84
+ }
85
+ catch (err) {
86
+ handleError(err);
87
+ this.exit(1);
88
+ }
89
+ }
90
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class MilestonesGet 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,74 @@
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 MilestonesGet extends Command {
6
+ static description = 'Get a project milestone by ID';
7
+ static examples = [
8
+ '<%= config.bin %> milestones get MILESTONE_ID',
9
+ '<%= config.bin %> milestones get MILESTONE_ID --format table',
10
+ ];
11
+ static args = {
12
+ id: Args.string({
13
+ description: 'Milestone 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
+ };
25
+ async run() {
26
+ try {
27
+ const { args, flags } = await this.parse(MilestonesGet);
28
+ const format = flags.format;
29
+ const client = getClient();
30
+ const milestone = await client.projectMilestone(args.id);
31
+ if (!milestone) {
32
+ throw new CliError(ErrorCodes.NOT_FOUND, `Milestone ${args.id} not found`);
33
+ }
34
+ const project = await milestone.project;
35
+ const data = {
36
+ id: milestone.id,
37
+ name: milestone.name,
38
+ description: milestone.description,
39
+ targetDate: milestone.targetDate,
40
+ sortOrder: milestone.sortOrder,
41
+ project: project
42
+ ? {
43
+ id: project.id,
44
+ name: project.name,
45
+ }
46
+ : null,
47
+ createdAt: milestone.createdAt,
48
+ updatedAt: milestone.updatedAt,
49
+ };
50
+ if (format === 'json') {
51
+ print(success(data));
52
+ }
53
+ else if (format === 'table') {
54
+ printItem({
55
+ id: data.id,
56
+ name: data.name,
57
+ description: data.description ?? 'N/A',
58
+ targetDate: data.targetDate ?? 'N/A',
59
+ project: data.project?.name ?? 'N/A',
60
+ sortOrder: data.sortOrder,
61
+ createdAt: data.createdAt,
62
+ updatedAt: data.updatedAt,
63
+ }, format);
64
+ }
65
+ else {
66
+ console.log(data.id);
67
+ }
68
+ }
69
+ catch (err) {
70
+ handleError(err);
71
+ this.exit(1);
72
+ }
73
+ }
74
+ }
@@ -0,0 +1,14 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class MilestonesList extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ projectId: 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
+ 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
+ }
@@ -0,0 +1,97 @@
1
+ import { Args, Command, Flags } from '@oclif/core';
2
+ import { getClient } from '../../lib/client.js';
3
+ import { successList, print, printList } from '../../lib/output.js';
4
+ import { handleError, CliError, ErrorCodes } from '../../lib/errors.js';
5
+ import { colors, truncate } from '../../lib/formatter.js';
6
+ const COLUMNS = [
7
+ {
8
+ key: 'name',
9
+ header: 'NAME',
10
+ format: (value) => colors.bold(truncate(String(value), 30)),
11
+ },
12
+ {
13
+ key: 'projectName',
14
+ header: 'PROJECT',
15
+ format: (value) => colors.cyan(truncate(String(value), 20)),
16
+ },
17
+ {
18
+ key: 'targetDate',
19
+ header: 'TARGET',
20
+ format: (value) => (value ? colors.dim(String(value)) : colors.gray('No date')),
21
+ },
22
+ ];
23
+ export default class MilestonesList extends Command {
24
+ static description = 'List project milestones';
25
+ static examples = [
26
+ '<%= config.bin %> milestones list PROJECT_ID',
27
+ '<%= config.bin %> milestones list PROJECT_ID --format table',
28
+ ];
29
+ static args = {
30
+ projectId: Args.string({
31
+ description: 'Project ID',
32
+ required: true,
33
+ }),
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
+ first: Flags.integer({
43
+ description: 'Number of milestones to fetch (default: 50)',
44
+ default: 50,
45
+ }),
46
+ after: Flags.string({
47
+ description: 'Cursor for pagination',
48
+ }),
49
+ };
50
+ async run() {
51
+ try {
52
+ const { args, flags } = await this.parse(MilestonesList);
53
+ const format = flags.format;
54
+ const client = getClient();
55
+ const project = await client.project(args.projectId);
56
+ if (!project) {
57
+ throw new CliError(ErrorCodes.NOT_FOUND, `Project ${args.projectId} not found`);
58
+ }
59
+ const milestones = await project.projectMilestones({
60
+ first: flags.first,
61
+ after: flags.after,
62
+ });
63
+ const data = milestones.nodes.map((milestone) => ({
64
+ id: milestone.id,
65
+ name: milestone.name,
66
+ description: milestone.description ?? undefined,
67
+ targetDate: milestone.targetDate ?? undefined,
68
+ sortOrder: milestone.sortOrder,
69
+ projectId: project.id,
70
+ projectName: project.name,
71
+ createdAt: milestone.createdAt,
72
+ updatedAt: milestone.updatedAt,
73
+ }));
74
+ const pageInfo = {
75
+ hasNextPage: milestones.pageInfo.hasNextPage,
76
+ hasPreviousPage: milestones.pageInfo.hasPreviousPage,
77
+ startCursor: milestones.pageInfo.startCursor,
78
+ endCursor: milestones.pageInfo.endCursor,
79
+ };
80
+ if (format === 'json') {
81
+ print(successList(data, pageInfo));
82
+ }
83
+ else {
84
+ printList(data, format, {
85
+ columns: COLUMNS,
86
+ primaryKey: 'name',
87
+ secondaryKey: 'targetDate',
88
+ pageInfo,
89
+ });
90
+ }
91
+ }
92
+ catch (err) {
93
+ handleError(err);
94
+ this.exit(1);
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class MilestonesUpdate 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
+ name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ 'target-date': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,94 @@
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 MilestonesUpdate extends Command {
6
+ static description = 'Update a project milestone';
7
+ static examples = [
8
+ '<%= config.bin %> milestones update MILESTONE_ID --name "Updated Name"',
9
+ '<%= config.bin %> milestones update MILESTONE_ID --target-date 2024-06-01',
10
+ ];
11
+ static args = {
12
+ id: Args.string({
13
+ description: 'Milestone 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: 'Milestone name',
27
+ }),
28
+ description: Flags.string({
29
+ char: 'd',
30
+ description: 'Milestone description',
31
+ }),
32
+ 'target-date': Flags.string({
33
+ description: 'Target date (YYYY-MM-DD)',
34
+ }),
35
+ };
36
+ async run() {
37
+ try {
38
+ const { args, flags } = await this.parse(MilestonesUpdate);
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['target-date'])
47
+ input.targetDate = flags['target-date'];
48
+ if (Object.keys(input).length === 0) {
49
+ throw new CliError(ErrorCodes.INVALID_INPUT, 'At least one field to update is required');
50
+ }
51
+ const payload = await client.updateProjectMilestone(args.id, input);
52
+ if (!payload.success || !payload.projectMilestone) {
53
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to update milestone');
54
+ }
55
+ const milestone = await payload.projectMilestone;
56
+ const project = await milestone.project;
57
+ const data = {
58
+ id: milestone.id,
59
+ name: milestone.name,
60
+ description: milestone.description,
61
+ targetDate: milestone.targetDate,
62
+ sortOrder: milestone.sortOrder,
63
+ project: project
64
+ ? {
65
+ id: project.id,
66
+ name: project.name,
67
+ }
68
+ : null,
69
+ createdAt: milestone.createdAt,
70
+ updatedAt: milestone.updatedAt,
71
+ };
72
+ if (format === 'json') {
73
+ print(success(data));
74
+ }
75
+ else if (format === 'table') {
76
+ printItem({
77
+ id: data.id,
78
+ name: data.name,
79
+ description: data.description ?? 'N/A',
80
+ targetDate: data.targetDate ?? 'N/A',
81
+ project: data.project?.name ?? 'N/A',
82
+ updatedAt: data.updatedAt,
83
+ }, format);
84
+ }
85
+ else {
86
+ console.log(data.id);
87
+ }
88
+ }
89
+ catch (err) {
90
+ handleError(err);
91
+ this.exit(1);
92
+ }
93
+ }
94
+ }
@@ -0,0 +1,14 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectUpdatesCreate extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ projectId: 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
+ body: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
+ health: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ run(): Promise<void>;
14
+ }
@@ -0,0 +1,96 @@
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
+ const HEALTH_OPTIONS = ['onTrack', 'atRisk', 'offTrack'];
6
+ export default class ProjectUpdatesCreate extends Command {
7
+ static description = 'Create a project update';
8
+ static examples = [
9
+ '<%= config.bin %> project-updates create PROJECT_ID --body "Sprint completed successfully"',
10
+ '<%= config.bin %> project-updates create PROJECT_ID --body "Delayed due to dependencies" --health atRisk',
11
+ ];
12
+ static args = {
13
+ projectId: Args.string({
14
+ description: 'Project ID',
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
+ body: Flags.string({
26
+ char: 'b',
27
+ description: 'Update body (supports markdown)',
28
+ required: true,
29
+ }),
30
+ health: Flags.string({
31
+ char: 'h',
32
+ description: 'Project health status',
33
+ options: [...HEALTH_OPTIONS],
34
+ default: 'onTrack',
35
+ }),
36
+ };
37
+ async run() {
38
+ try {
39
+ const { args, flags } = await this.parse(ProjectUpdatesCreate);
40
+ const format = flags.format;
41
+ const health = flags.health;
42
+ const client = getClient();
43
+ const project = await client.project(args.projectId);
44
+ if (!project) {
45
+ throw new CliError(ErrorCodes.NOT_FOUND, `Project ${args.projectId} not found`);
46
+ }
47
+ const payload = await client.createProjectUpdate({
48
+ projectId: args.projectId,
49
+ body: flags.body,
50
+ health,
51
+ });
52
+ if (!payload.success || !payload.projectUpdate) {
53
+ throw new CliError(ErrorCodes.API_ERROR, 'Failed to create project update');
54
+ }
55
+ const update = await payload.projectUpdate;
56
+ const user = await update.user;
57
+ const data = {
58
+ id: update.id,
59
+ body: update.body,
60
+ health: update.health,
61
+ url: update.url,
62
+ project: {
63
+ id: project.id,
64
+ name: project.name,
65
+ },
66
+ user: user
67
+ ? {
68
+ id: user.id,
69
+ name: user.name,
70
+ }
71
+ : null,
72
+ createdAt: update.createdAt,
73
+ };
74
+ if (format === 'json') {
75
+ print(success(data));
76
+ }
77
+ else if (format === 'table') {
78
+ printItem({
79
+ id: data.id,
80
+ project: data.project.name,
81
+ health: data.health,
82
+ body: data.body,
83
+ user: data.user?.name ?? 'Unknown',
84
+ createdAt: data.createdAt,
85
+ }, format);
86
+ }
87
+ else {
88
+ console.log(data.id);
89
+ }
90
+ }
91
+ catch (err) {
92
+ handleError(err);
93
+ this.exit(1);
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,12 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class ProjectUpdatesGet 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
+ }