@proletariat/cli 0.3.34 → 0.3.36

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 (198) hide show
  1. package/dist/commands/agent/auth.d.ts +15 -3
  2. package/dist/commands/agent/auth.js +136 -15
  3. package/dist/commands/agent/index.js +11 -2
  4. package/dist/commands/agent/list.js +16 -7
  5. package/dist/commands/agent/staff/add.d.ts +1 -0
  6. package/dist/commands/agent/staff/add.js +1 -0
  7. package/dist/commands/agent/staff/index.d.ts +15 -0
  8. package/dist/commands/agent/staff/index.js +83 -0
  9. package/dist/commands/agent/staff/list.d.ts +1 -0
  10. package/dist/commands/agent/staff/list.js +1 -0
  11. package/dist/commands/agent/staff/remove.d.ts +1 -0
  12. package/dist/commands/agent/staff/remove.js +1 -0
  13. package/dist/commands/agent/status.js +32 -4
  14. package/dist/commands/agent/themes/add-names.d.ts +1 -0
  15. package/dist/commands/agent/themes/add-names.js +1 -0
  16. package/dist/commands/agent/themes/create.d.ts +1 -0
  17. package/dist/commands/agent/themes/create.js +1 -0
  18. package/dist/commands/agent/themes/index.d.ts +10 -0
  19. package/dist/commands/agent/themes/index.js +144 -0
  20. package/dist/commands/agent/themes/list.d.ts +1 -0
  21. package/dist/commands/agent/themes/list.js +1 -0
  22. package/dist/commands/agent/themes/set.d.ts +1 -0
  23. package/dist/commands/agent/themes/set.js +1 -0
  24. package/dist/commands/agents/themes/add-names.d.ts +1 -0
  25. package/dist/commands/agents/themes/add-names.js +1 -0
  26. package/dist/commands/agents/themes/create.d.ts +1 -0
  27. package/dist/commands/agents/themes/create.js +1 -0
  28. package/dist/commands/agents/themes/list.d.ts +1 -0
  29. package/dist/commands/agents/themes/list.js +1 -0
  30. package/dist/commands/board/watch.js +6 -0
  31. package/dist/commands/branch/list.d.ts +1 -0
  32. package/dist/commands/branch/list.js +43 -12
  33. package/dist/commands/branch/where.js +3 -2
  34. package/dist/commands/category/list.d.ts +2 -1
  35. package/dist/commands/category/list.js +38 -13
  36. package/dist/commands/{claude.d.ts → claude/index.d.ts} +1 -1
  37. package/dist/commands/{claude.js → claude/index.js} +12 -12
  38. package/dist/commands/claude/open.d.ts +13 -0
  39. package/dist/commands/claude/open.js +175 -0
  40. package/dist/commands/diet.js +18 -2
  41. package/dist/commands/docker/logs.js +7 -3
  42. package/dist/commands/docker/shell.js +6 -0
  43. package/dist/commands/docker/start.js +20 -4
  44. package/dist/commands/docker/sync.d.ts +4 -0
  45. package/dist/commands/docker/sync.js +30 -2
  46. package/dist/commands/epic/show.d.ts +13 -0
  47. package/dist/commands/epic/show.js +16 -0
  48. package/dist/commands/epic/view.js +27 -0
  49. package/dist/commands/execution/config.d.ts +0 -4
  50. package/dist/commands/execution/config.js +10 -32
  51. package/dist/commands/execution/index.js +2 -1
  52. package/dist/commands/execution/logs.js +1 -1
  53. package/dist/commands/execution/stop.js +2 -1
  54. package/dist/commands/execution/view.js +22 -26
  55. package/dist/commands/init.js +2 -19
  56. package/dist/commands/label/create.d.ts +20 -0
  57. package/dist/commands/label/create.js +57 -0
  58. package/dist/commands/label/delete.d.ts +17 -0
  59. package/dist/commands/label/delete.js +32 -0
  60. package/dist/commands/label/group/create.d.ts +20 -0
  61. package/dist/commands/label/group/create.js +55 -0
  62. package/dist/commands/label/group/list.d.ts +14 -0
  63. package/dist/commands/label/group/list.js +52 -0
  64. package/dist/commands/label/index.d.ts +15 -0
  65. package/dist/commands/label/index.js +58 -0
  66. package/dist/commands/label/list.d.ts +16 -0
  67. package/dist/commands/label/list.js +83 -0
  68. package/dist/commands/link/list.js +3 -2
  69. package/dist/commands/mcp-server.js +27 -1
  70. package/dist/commands/phase/template/apply.d.ts +26 -0
  71. package/dist/commands/phase/template/apply.js +14 -0
  72. package/dist/commands/phase/template/create.d.ts +23 -0
  73. package/dist/commands/phase/template/create.js +14 -0
  74. package/dist/commands/phase/template/delete.d.ts +18 -0
  75. package/dist/commands/phase/template/delete.js +61 -0
  76. package/dist/commands/phase/template/list.d.ts +17 -0
  77. package/dist/commands/phase/template/list.js +89 -0
  78. package/dist/commands/phase/template/update.d.ts +1 -0
  79. package/dist/commands/phase/template/update.js +1 -0
  80. package/dist/commands/priority/add.js +1 -1
  81. package/dist/commands/project/create.js +3 -4
  82. package/dist/commands/project/update.js +5 -8
  83. package/dist/commands/pull.js +24 -0
  84. package/dist/commands/roadmap/generate.js +1 -2
  85. package/dist/commands/session/create.d.ts +19 -0
  86. package/dist/commands/session/create.js +102 -0
  87. package/dist/commands/session/health.js +2 -21
  88. package/dist/commands/session/index.js +14 -1
  89. package/dist/commands/session/list.js +26 -7
  90. package/dist/commands/session/peek.d.ts +38 -0
  91. package/dist/commands/session/peek.js +316 -0
  92. package/dist/commands/session/poke.d.ts +27 -0
  93. package/dist/commands/session/poke.js +219 -0
  94. package/dist/commands/spec/link/depends.d.ts +18 -0
  95. package/dist/commands/spec/link/depends.js +86 -0
  96. package/dist/commands/spec/link/index.d.ts +17 -0
  97. package/dist/commands/spec/link/index.js +92 -0
  98. package/dist/commands/spec/link/remove.d.ts +18 -0
  99. package/dist/commands/spec/link/remove.js +90 -0
  100. package/dist/commands/spec/view.js +29 -0
  101. package/dist/commands/support/logs.js +2 -2
  102. package/dist/commands/template/apply.js +5 -4
  103. package/dist/commands/template/create.js +1 -1
  104. package/dist/commands/template/list.js +2 -1
  105. package/dist/commands/theme/add-names.d.ts +4 -0
  106. package/dist/commands/theme/add-names.js +11 -1
  107. package/dist/commands/theme/create.d.ts +2 -0
  108. package/dist/commands/theme/create.js +8 -0
  109. package/dist/commands/ticket/bulk.js +2 -2
  110. package/dist/commands/ticket/complete.js +2 -2
  111. package/dist/commands/ticket/create.js +21 -0
  112. package/dist/commands/ticket/delete.js +8 -0
  113. package/dist/commands/ticket/edit.js +25 -0
  114. package/dist/commands/ticket/index.js +2 -2
  115. package/dist/commands/ticket/link/block.d.ts +15 -0
  116. package/dist/commands/ticket/link/block.js +95 -0
  117. package/dist/commands/ticket/link/index.d.ts +14 -0
  118. package/dist/commands/ticket/link/index.js +96 -0
  119. package/dist/commands/ticket/list.d.ts +1 -0
  120. package/dist/commands/ticket/list.js +6 -0
  121. package/dist/commands/ticket/move.js +25 -2
  122. package/dist/commands/ticket/resolve.js +4 -5
  123. package/dist/commands/ticket/show.d.ts +13 -0
  124. package/dist/commands/ticket/show.js +16 -0
  125. package/dist/commands/ticket/template/apply.d.ts +26 -0
  126. package/dist/commands/ticket/template/apply.js +14 -0
  127. package/dist/commands/ticket/template/delete.d.ts +18 -0
  128. package/dist/commands/ticket/template/delete.js +61 -0
  129. package/dist/commands/ticket/template/list.d.ts +17 -0
  130. package/dist/commands/ticket/template/list.js +78 -0
  131. package/dist/commands/ticket/template/save.d.ts +17 -0
  132. package/dist/commands/ticket/template/save.js +97 -0
  133. package/dist/commands/ticket/view.js +30 -0
  134. package/dist/commands/work/index.js +4 -0
  135. package/dist/commands/work/ready.js +17 -0
  136. package/dist/commands/work/resolve.js +1 -1
  137. package/dist/commands/work/spawn.js +4 -4
  138. package/dist/commands/work/start.d.ts +1 -0
  139. package/dist/commands/work/start.js +203 -93
  140. package/dist/commands/work/status.d.ts +14 -0
  141. package/dist/commands/work/status.js +60 -0
  142. package/dist/commands/workflow/index.js +2 -1
  143. package/dist/commands/workflow/show.d.ts +13 -0
  144. package/dist/commands/workflow/show.js +16 -0
  145. package/dist/commands/workspace/add.js +15 -0
  146. package/dist/commands/workspace/list.js +2 -1
  147. package/dist/commands/workspace/prune.js +5 -5
  148. package/dist/lib/branch/index.d.ts +1 -0
  149. package/dist/lib/database/index.d.ts +1 -1
  150. package/dist/lib/database/index.js +20 -0
  151. package/dist/lib/execution/config.d.ts +15 -1
  152. package/dist/lib/execution/config.js +28 -0
  153. package/dist/lib/execution/devcontainer.js +3 -1
  154. package/dist/lib/execution/runners.d.ts +18 -2
  155. package/dist/lib/execution/runners.js +71 -29
  156. package/dist/lib/execution/session-utils.d.ts +11 -1
  157. package/dist/lib/execution/session-utils.js +26 -1
  158. package/dist/lib/execution/storage.d.ts +5 -0
  159. package/dist/lib/execution/storage.js +18 -3
  160. package/dist/lib/execution/types.d.ts +3 -0
  161. package/dist/lib/flags/resolver.js +1 -0
  162. package/dist/lib/mcp/helpers.d.ts +1 -2
  163. package/dist/lib/mcp/tools/board.js +4 -6
  164. package/dist/lib/mcp/tools/cli-passthrough.js +25 -6
  165. package/dist/lib/mcp/tools/diet.js +1 -0
  166. package/dist/lib/mcp/tools/epic.js +8 -3
  167. package/dist/lib/mcp/tools/index.d.ts +1 -0
  168. package/dist/lib/mcp/tools/index.js +1 -0
  169. package/dist/lib/mcp/tools/label.d.ts +6 -0
  170. package/dist/lib/mcp/tools/label.js +338 -0
  171. package/dist/lib/mcp/tools/spec.js +1 -1
  172. package/dist/lib/mcp/tools/ticket.js +57 -19
  173. package/dist/lib/mcp/tools/work.js +96 -6
  174. package/dist/lib/mcp/types.d.ts +10 -0
  175. package/dist/lib/multiline-input.js +8 -19
  176. package/dist/lib/pmo/base-command.d.ts +0 -1
  177. package/dist/lib/pmo/base-command.js +4 -5
  178. package/dist/lib/pmo/schema.d.ts +6 -0
  179. package/dist/lib/pmo/schema.js +44 -0
  180. package/dist/lib/pmo/storage/actions.js +1 -1
  181. package/dist/lib/pmo/storage/base.d.ts +6 -0
  182. package/dist/lib/pmo/storage/base.js +311 -52
  183. package/dist/lib/pmo/storage/index.d.ts +23 -1
  184. package/dist/lib/pmo/storage/index.js +59 -1
  185. package/dist/lib/pmo/storage/labels.d.ts +55 -0
  186. package/dist/lib/pmo/storage/labels.js +346 -0
  187. package/dist/lib/pmo/storage/tickets.js +17 -0
  188. package/dist/lib/pmo/storage/types.d.ts +25 -0
  189. package/dist/lib/pmo/types.d.ts +44 -0
  190. package/dist/lib/pmo/utils.js +1 -1
  191. package/dist/lib/prompt-command.d.ts +20 -0
  192. package/dist/lib/prompt-command.js +38 -2
  193. package/dist/lib/prompt-json.d.ts +36 -4
  194. package/dist/lib/prompt-json.js +129 -7
  195. package/dist/lib/styles.d.ts +37 -0
  196. package/dist/lib/styles.js +73 -0
  197. package/oclif.manifest.json +6399 -3799
  198. package/package.json +1 -1
@@ -0,0 +1,15 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class TicketLinkBlock extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ ticket: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ blocker: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ execute(): Promise<void>;
15
+ }
@@ -0,0 +1,95 @@
1
+ import { Args } from '@oclif/core';
2
+ import { autoExportToBoard, PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputPromptAsJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
5
+ export default class TicketLinkBlock extends PMOCommand {
6
+ static description = 'Add a blocking dependency to a ticket';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %> TKT-001',
9
+ '<%= config.bin %> <%= command.id %> TKT-001 TKT-002',
10
+ '<%= config.bin %> <%= command.id %> TKT-001 --json',
11
+ ];
12
+ static args = {
13
+ ticket: Args.string({
14
+ description: 'Ticket that will be blocked',
15
+ required: true,
16
+ }),
17
+ blocker: Args.string({
18
+ description: 'Ticket that blocks (the blocker)',
19
+ required: false,
20
+ }),
21
+ };
22
+ static flags = {
23
+ ...pmoBaseFlags,
24
+ };
25
+ async execute() {
26
+ const { args, flags } = await this.parse(TicketLinkBlock);
27
+ const jsonMode = shouldOutputJson(flags);
28
+ const projectId = await this.requireProject();
29
+ const handleError = (code, message) => {
30
+ if (jsonMode) {
31
+ outputErrorAsJson(code, message, createMetadata('ticket link block', flags));
32
+ this.exit(1);
33
+ }
34
+ this.error(message);
35
+ };
36
+ // Verify the target ticket exists
37
+ const ticket = await this.storage.getTicket(args.ticket);
38
+ if (!ticket) {
39
+ return handleError('TICKET_NOT_FOUND', `Ticket not found: ${args.ticket}`);
40
+ }
41
+ // If blocker not provided, prompt for selection
42
+ if (!args.blocker) {
43
+ const tickets = await this.storage.listTickets(projectId);
44
+ const otherTickets = tickets.filter(t => t.id !== args.ticket);
45
+ if (otherTickets.length === 0) {
46
+ return handleError('NO_TICKETS', 'No other tickets to select as blocker.');
47
+ }
48
+ const projectFlag = flags.project ? ` -P ${flags.project}` : '';
49
+ const choices = otherTickets.map(t => ({
50
+ name: `${t.id} - ${t.title}`,
51
+ value: t.id,
52
+ command: `prlt ticket link block ${args.ticket} ${t.id}${projectFlag} --json`,
53
+ }));
54
+ const message = `Select ticket that blocks ${args.ticket}:`;
55
+ if (jsonMode) {
56
+ outputPromptAsJson(buildPromptConfig('list', 'blocker', message, choices), createMetadata('ticket link block', flags));
57
+ return;
58
+ }
59
+ const { selected } = await this.prompt([{
60
+ type: 'list',
61
+ name: 'selected',
62
+ message,
63
+ choices,
64
+ }], null);
65
+ args.blocker = selected;
66
+ }
67
+ // Verify blocker exists
68
+ const blockerTicket = await this.storage.getTicket(args.blocker);
69
+ if (!blockerTicket) {
70
+ return handleError('BLOCKER_NOT_FOUND', `Blocker ticket not found: ${args.blocker}`);
71
+ }
72
+ // Create the blocking dependency
73
+ try {
74
+ await this.storage.createTicketDependency(args.ticket, args.blocker, 'blocks');
75
+ await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
76
+ if (jsonMode) {
77
+ outputSuccessAsJson({
78
+ ticketId: args.ticket,
79
+ blockerId: args.blocker,
80
+ type: 'blocks',
81
+ }, createMetadata('ticket link block', flags));
82
+ return;
83
+ }
84
+ this.log(styles.success(`\n${args.ticket} is now blocked by ${args.blocker}`));
85
+ this.log(styles.muted(` ${ticket.title}`));
86
+ this.log(styles.muted(` blocked by: ${blockerTicket.title}`));
87
+ }
88
+ catch (error) {
89
+ if (error instanceof Error && error.message.includes('already exists')) {
90
+ return handleError('ALREADY_EXISTS', 'Blocking dependency already exists.');
91
+ }
92
+ throw error;
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,14 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class TicketLink extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ ticket: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ execute(): Promise<void>;
14
+ }
@@ -0,0 +1,96 @@
1
+ import { Args } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
5
+ export default class TicketLink extends PMOCommand {
6
+ static description = 'Manage links (dependencies) for a ticket';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %>',
9
+ '<%= config.bin %> <%= command.id %> TKT-001',
10
+ '<%= config.bin %> <%= command.id %> TKT-001 --json',
11
+ ];
12
+ static args = {
13
+ ticket: Args.string({
14
+ description: 'Ticket ID',
15
+ required: false,
16
+ }),
17
+ };
18
+ static flags = {
19
+ ...pmoBaseFlags,
20
+ };
21
+ async execute() {
22
+ const { args, flags } = await this.parse(TicketLink);
23
+ const jsonMode = shouldOutputJson(flags);
24
+ const projectId = await this.requireProject();
25
+ // If no ticket ID provided, prompt for selection
26
+ if (!args.ticket) {
27
+ const tickets = await this.storage.listTickets(projectId);
28
+ if (tickets.length === 0) {
29
+ this.log(styles.muted('No tickets found.'));
30
+ return;
31
+ }
32
+ const choices = tickets.map(t => ({
33
+ name: `${t.id} - ${t.title}`,
34
+ value: t.id,
35
+ command: `prlt ticket link ${t.id}${flags.project ? ` -P ${flags.project}` : ''} --json`,
36
+ }));
37
+ const message = 'Select a ticket to manage links:';
38
+ if (jsonMode) {
39
+ outputPromptAsJson(buildPromptConfig('list', 'ticket', message, choices), createMetadata('ticket link', flags));
40
+ return;
41
+ }
42
+ const { selected } = await this.prompt([{
43
+ type: 'list',
44
+ name: 'selected',
45
+ message,
46
+ choices,
47
+ }], null);
48
+ args.ticket = selected;
49
+ }
50
+ const ticket = await this.storage.getTicket(args.ticket);
51
+ if (!ticket) {
52
+ this.error(`Ticket not found: ${args.ticket}`);
53
+ }
54
+ // Show link actions submenu
55
+ const projectFlag = flags.project ? ` -P ${flags.project}` : '';
56
+ const menuChoices = [
57
+ { name: 'Add blocker', value: 'block', command: `prlt ticket link block ${args.ticket}${projectFlag} --json` },
58
+ { name: 'View links', value: 'view', command: `prlt link list ${args.ticket}${projectFlag} --json` },
59
+ { name: 'Remove link', value: 'remove', command: `prlt link remove ${args.ticket}${projectFlag} --json` },
60
+ { name: 'Cancel', value: 'cancel', command: '' },
61
+ ];
62
+ const message = `Manage links for ${args.ticket}: ${ticket.title}`;
63
+ if (jsonMode) {
64
+ outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('ticket link', flags));
65
+ return;
66
+ }
67
+ const { action } = await this.prompt([{
68
+ type: 'list',
69
+ name: 'action',
70
+ message,
71
+ choices: menuChoices,
72
+ }], null);
73
+ if (action === 'cancel') {
74
+ this.log(styles.muted('Cancelled.'));
75
+ return;
76
+ }
77
+ switch (action) {
78
+ case 'block': {
79
+ const { default: BlockCommand } = await import('./block.js');
80
+ const cmd = new BlockCommand([args.ticket, ...(flags.project ? ['-P', flags.project] : [])], this.config);
81
+ await cmd.run();
82
+ break;
83
+ }
84
+ case 'view': {
85
+ const { default: LinkListCommand } = await import('../../link/list.js');
86
+ const cmd = new LinkListCommand([args.ticket, ...(flags.project ? ['-P', flags.project] : [])], this.config);
87
+ await cmd.run();
88
+ break;
89
+ }
90
+ case 'remove': {
91
+ this.log(styles.muted('Use: prlt link remove <from> <to>'));
92
+ break;
93
+ }
94
+ }
95
+ }
96
+ }
@@ -11,6 +11,7 @@ export default class TicketList extends Command {
11
11
  search: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
13
  all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ label: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
15
  'group-by': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
16
  limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
17
  offset: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -55,6 +55,9 @@ export default class TicketList extends Command {
55
55
  description: 'Show tickets across all projects',
56
56
  default: false,
57
57
  }),
58
+ label: Flags.string({
59
+ description: 'Filter by label name',
60
+ }),
58
61
  'group-by': Flags.string({
59
62
  char: 'g',
60
63
  description: 'Group tickets by field',
@@ -106,6 +109,9 @@ export default class TicketList extends Command {
106
109
  if (flags.search) {
107
110
  filter.search = flags.search;
108
111
  }
112
+ if (flags.label) {
113
+ filter.label = flags.label;
114
+ }
109
115
  // Determine projectId for the query
110
116
  const projectId = flags.all ? undefined : (filter.projectId || undefined);
111
117
  // Validate project if specified (not in --all mode)
@@ -3,6 +3,7 @@ import { autoExportToBoard, PMOCommand, pmoBaseFlags, } from '../../lib/pmo/inde
3
3
  import { PMOError } from '../../lib/pmo/types.js';
4
4
  import { styles } from '../../lib/styles.js';
5
5
  import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
6
+ import { formatTicket } from '../../lib/mcp/helpers.js';
6
7
  export default class TicketMove extends PMOCommand {
7
8
  static description = 'Move ticket(s) to a different column';
8
9
  static examples = [
@@ -195,6 +196,14 @@ export default class TicketMove extends PMOCommand {
195
196
  const moved = await this.storage.moveTicket(projectId, ticketId, targetColumn, flags.position);
196
197
  // Auto-export to board.md after write
197
198
  await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
199
+ // JSON output mode - match MCP tool response shape
200
+ if (jsonMode) {
201
+ this.log(JSON.stringify({
202
+ success: true,
203
+ ticket: formatTicket(moved),
204
+ }, null, 2));
205
+ return;
206
+ }
198
207
  this.log(styles.success(`\n✅ Moved ticket ${styles.emphasis(moved.id)}`));
199
208
  if (targetColumn !== ticket.statusName) {
200
209
  this.log(styles.muted(` From: ${ticket.statusName}`));
@@ -206,7 +215,7 @@ export default class TicketMove extends PMOCommand {
206
215
  }
207
216
  async executeBulk(allTickets, flags, projectId) {
208
217
  // Only show header in interactive mode
209
- if (!(flags.json || flags.machine)) {
218
+ if (!shouldOutputJson(flags)) {
210
219
  this.log(styles.emphasis('📦 Move Multiple Tickets\n'));
211
220
  }
212
221
  // Get columns
@@ -216,7 +225,7 @@ export default class TicketMove extends PMOCommand {
216
225
  }
217
226
  const columns = board.columns.map(col => col.name);
218
227
  // Agent mode config for prompts
219
- const jsonModeConfig = (flags.json || flags.machine) ? { flags, commandName: 'ticket move --bulk' } : null;
228
+ const jsonModeConfig = shouldOutputJson(flags) ? { flags, commandName: 'ticket move --bulk' } : null;
220
229
  // Select tickets to move (now agent-compatible!)
221
230
  const { selectedTickets } = await this.prompt([{
222
231
  type: 'checkbox',
@@ -328,6 +337,13 @@ export default class TicketMove extends PMOCommand {
328
337
  // Refresh ticket to get updated status
329
338
  const updatedTicket = await this.storage.getTicket(ticketId);
330
339
  await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
340
+ if (jsonMode && updatedTicket) {
341
+ this.log(JSON.stringify({
342
+ success: true,
343
+ ticket: formatTicket(updatedTicket),
344
+ }, null, 2));
345
+ return;
346
+ }
331
347
  this.log(styles.success(`\n✅ Moved ticket ${styles.emphasis(ticketId)} to project ${styles.emphasis(targetProject.id)}`));
332
348
  this.log(styles.muted(` From project: ${sourceProjectId}`));
333
349
  this.log(styles.muted(` To project: ${targetProject.id}`));
@@ -345,6 +361,13 @@ export default class TicketMove extends PMOCommand {
345
361
  }
346
362
  }
347
363
  await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
364
+ if (jsonMode) {
365
+ this.log(JSON.stringify({
366
+ success: true,
367
+ ticket: formatTicket(movedTicket),
368
+ }, null, 2));
369
+ return;
370
+ }
348
371
  this.log(styles.success(`\n✅ Moved ticket ${styles.emphasis(ticketId)} to project ${styles.emphasis(targetProject.id)}`));
349
372
  this.log(styles.muted(` From project: ${sourceProjectId}`));
350
373
  this.log(styles.muted(` To project: ${targetProject.id}`));
@@ -1,5 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { autoExportToBoard, PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputErrorAsJson, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
@@ -137,7 +136,7 @@ export default class TicketResolve extends PMOCommand {
137
136
  }),
138
137
  };
139
138
  async execute() {
140
- const { args, flags, argv } = await this.parse(TicketResolve);
139
+ const { flags, argv } = await this.parse(TicketResolve);
141
140
  const projectId = flags.project;
142
141
  const jsonMode = shouldOutputJson(flags);
143
142
  const handleError = (code, message) => {
@@ -223,18 +222,18 @@ export default class TicketResolve extends PMOCommand {
223
222
  for (const question of unanswered) {
224
223
  this.log(styles.emphasis(` Q${question.number}: ${question.text}`));
225
224
  // eslint-disable-next-line no-await-in-loop
226
- const { answer } = await inquirer.prompt([
225
+ const { answer } = await this.prompt([
227
226
  {
228
227
  type: 'input',
229
228
  name: 'answer',
230
229
  message: ` A${question.number}:`,
231
230
  validate: (input) => {
232
- if (!input.trim())
231
+ if (!String(input).trim())
233
232
  return 'Please provide an answer (or type "skip" to skip)';
234
233
  return true;
235
234
  },
236
235
  },
237
- ]);
236
+ ], null);
238
237
  if (answer.toLowerCase() === 'cancel') {
239
238
  cancelled = true;
240
239
  this.log(styles.warning('\nResolution cancelled.'));
@@ -0,0 +1,13 @@
1
+ import TicketView from './view.js';
2
+ export default class TicketShow extends TicketView {
3
+ static description: string;
4
+ static hidden: boolean;
5
+ static args: {
6
+ ticketId: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ }
@@ -0,0 +1,16 @@
1
+ import { Args } from '@oclif/core';
2
+ import { pmoBaseFlags } from '../../lib/pmo/index.js';
3
+ import TicketView from './view.js';
4
+ export default class TicketShow extends TicketView {
5
+ static description = 'View detailed ticket information (alias for ticket view)';
6
+ static hidden = true;
7
+ static args = {
8
+ ticketId: Args.string({
9
+ description: 'Ticket ID to view - prompts with dropdown if not provided',
10
+ required: false,
11
+ }),
12
+ };
13
+ static flags = {
14
+ ...pmoBaseFlags,
15
+ };
16
+ }
@@ -0,0 +1,26 @@
1
+ import TemplateApply from '../../template/apply.js';
2
+ export default class TicketTemplateApply extends TemplateApply {
3
+ static description: string;
4
+ static args: {
5
+ template: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
6
+ };
7
+ static flags: {
8
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ column: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ assignee: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ owner: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ epic: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ 'no-subtasks': import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
22
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
+ };
24
+ static examples: string[];
25
+ run(): Promise<void>;
26
+ }
@@ -0,0 +1,14 @@
1
+ import TemplateApply from '../../template/apply.js';
2
+ export default class TicketTemplateApply extends TemplateApply {
3
+ static description = 'Apply a ticket template to create a new ticket';
4
+ static args = TemplateApply.args;
5
+ static flags = TemplateApply.flags;
6
+ static examples = TemplateApply.examples;
7
+ async run() {
8
+ const argv = this.argv;
9
+ if (!argv.includes('--type') && !argv.includes('-t')) {
10
+ argv.push('--type', 'ticket');
11
+ }
12
+ return super.run();
13
+ }
14
+ }
@@ -0,0 +1,18 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class TicketTemplateDelete extends PMOCommand {
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
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ protected getPMOOptions(): {
15
+ promptIfMultiple: boolean;
16
+ };
17
+ execute(): Promise<void>;
18
+ }
@@ -0,0 +1,61 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../../lib/prompt-json.js';
5
+ export default class TicketTemplateDelete extends PMOCommand {
6
+ static description = 'Delete a ticket template';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %> my-template --force',
9
+ ];
10
+ static args = {
11
+ id: Args.string({
12
+ description: 'Template ID to delete',
13
+ required: true,
14
+ }),
15
+ };
16
+ static flags = {
17
+ ...pmoBaseFlags,
18
+ force: Flags.boolean({
19
+ char: 'f',
20
+ description: 'Skip confirmation',
21
+ default: false,
22
+ }),
23
+ };
24
+ getPMOOptions() {
25
+ return { promptIfMultiple: false };
26
+ }
27
+ async execute() {
28
+ const { args, flags } = await this.parse(TicketTemplateDelete);
29
+ const jsonMode = shouldOutputJson(flags);
30
+ const handleError = (code, message) => {
31
+ if (jsonMode) {
32
+ outputErrorAsJson(code, message, createMetadata('ticket template delete', flags));
33
+ }
34
+ this.error(message);
35
+ };
36
+ const template = await this.storage.getTicketTemplate(args.id);
37
+ if (!template) {
38
+ return handleError('NOT_FOUND', `Ticket template not found: ${args.id}`);
39
+ }
40
+ if (template.isBuiltin) {
41
+ return handleError('BUILTIN', `Cannot delete built-in template "${template.name}".`);
42
+ }
43
+ if (!flags.force) {
44
+ const { confirm } = await this.prompt([{
45
+ type: 'list',
46
+ name: 'confirm',
47
+ message: `Delete ticket template "${template.name}"?`,
48
+ choices: [
49
+ { name: 'No', value: false },
50
+ { name: 'Yes', value: true },
51
+ ],
52
+ }], jsonMode ? { flags, commandName: 'ticket template delete' } : null);
53
+ if (!confirm) {
54
+ this.log(styles.muted('Cancelled.'));
55
+ return;
56
+ }
57
+ }
58
+ await this.storage.deleteTicketTemplate(args.id);
59
+ this.log(styles.success(`\nDeleted template "${template.name}"`));
60
+ }
61
+ }
@@ -0,0 +1,17 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class TicketTemplateList extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ builtin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ custom: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ protected getPMOOptions(): {
13
+ promptIfMultiple: boolean;
14
+ };
15
+ execute(): Promise<void>;
16
+ private printTemplate;
17
+ }
@@ -0,0 +1,78 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { shouldOutputJson } from '../../../lib/prompt-json.js';
4
+ import { styles } from '../../../lib/styles.js';
5
+ export default class TicketTemplateList extends PMOCommand {
6
+ static description = 'List ticket templates';
7
+ static examples = [
8
+ '<%= config.bin %> <%= command.id %>',
9
+ '<%= config.bin %> <%= command.id %> --builtin',
10
+ '<%= config.bin %> <%= command.id %> --json',
11
+ ];
12
+ static flags = {
13
+ ...pmoBaseFlags,
14
+ builtin: Flags.boolean({
15
+ description: 'Show only built-in templates',
16
+ exclusive: ['custom'],
17
+ }),
18
+ custom: Flags.boolean({
19
+ description: 'Show only custom templates',
20
+ exclusive: ['builtin'],
21
+ }),
22
+ };
23
+ getPMOOptions() {
24
+ return { promptIfMultiple: false };
25
+ }
26
+ async execute() {
27
+ const { flags } = await this.parse(TicketTemplateList);
28
+ let builtinFilter;
29
+ if (flags.builtin)
30
+ builtinFilter = { isBuiltin: true };
31
+ if (flags.custom)
32
+ builtinFilter = { isBuiltin: false };
33
+ const templates = await this.storage.listTicketTemplates(builtinFilter);
34
+ if (shouldOutputJson(flags)) {
35
+ this.log(JSON.stringify(templates, null, 2));
36
+ return;
37
+ }
38
+ if (templates.length === 0) {
39
+ this.log(styles.muted('\nNo ticket templates found.'));
40
+ return;
41
+ }
42
+ this.log(`\n${styles.emphasis('Ticket Templates')}`);
43
+ this.log('═'.repeat(60));
44
+ const builtinTemplates = templates.filter(t => t.isBuiltin);
45
+ const customTemplates = templates.filter(t => !t.isBuiltin);
46
+ if (builtinTemplates.length > 0 && !flags.custom) {
47
+ this.log(`\n${styles.emphasis('Built-in Templates')}`);
48
+ this.log('─'.repeat(40));
49
+ for (const template of builtinTemplates) {
50
+ this.printTemplate(template);
51
+ }
52
+ }
53
+ if (customTemplates.length > 0 && !flags.builtin) {
54
+ this.log(`\n${styles.emphasis('Custom Templates')}`);
55
+ this.log('─'.repeat(40));
56
+ for (const template of customTemplates) {
57
+ this.printTemplate(template);
58
+ }
59
+ }
60
+ this.log('');
61
+ }
62
+ printTemplate(template) {
63
+ this.log(` ${styles.emphasis(template.name)} ${styles.muted(`(${template.id})`)}`);
64
+ if (template.description) {
65
+ this.log(` ${styles.muted(template.description)}`);
66
+ }
67
+ const details = [];
68
+ if (template.defaultPriority)
69
+ details.push(`Priority: ${template.defaultPriority}`);
70
+ if (template.defaultCategory)
71
+ details.push(`Category: ${template.defaultCategory}`);
72
+ if (template.suggestedSubtasks.length > 0)
73
+ details.push(`Subtasks: ${template.suggestedSubtasks.length}`);
74
+ if (details.length > 0) {
75
+ this.log(` ${styles.muted(details.join(' | '))}`);
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,17 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class TicketTemplateSave extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ ticket: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
+ name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
8
+ };
9
+ static flags: {
10
+ 'template-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
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ };
16
+ execute(): Promise<void>;
17
+ }