@proletariat/cli 0.3.22 → 0.3.24

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 (173) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +7 -7
  3. package/dist/commands/action/create.js +1 -1
  4. package/dist/commands/agent/{temp/cleanup.d.ts → cleanup.d.ts} +1 -1
  5. package/dist/commands/agent/{temp/cleanup.js → cleanup.js} +4 -4
  6. package/dist/commands/agent/index.js +8 -8
  7. package/dist/commands/branch/create.js +2 -2
  8. package/dist/commands/epic/create.d.ts +1 -0
  9. package/dist/commands/epic/create.js +39 -2
  10. package/dist/commands/epic/index.js +2 -2
  11. package/dist/commands/{epic/link/remove.d.ts → link/create.d.ts} +6 -7
  12. package/dist/commands/link/create.js +141 -0
  13. package/dist/commands/{epic/link/relates.d.ts → link/index.d.ts} +4 -5
  14. package/dist/commands/link/index.js +87 -0
  15. package/dist/commands/{epic/link/duplicates.d.ts → link/list.d.ts} +7 -4
  16. package/dist/commands/link/list.js +182 -0
  17. package/dist/commands/{spec/link → link}/remove.d.ts +4 -5
  18. package/dist/commands/link/remove.js +120 -0
  19. package/dist/commands/mcp-server.d.ts +22 -0
  20. package/dist/commands/mcp-server.js +98 -0
  21. package/dist/commands/phase/create.js +1 -1
  22. package/dist/commands/project/create.d.ts +1 -0
  23. package/dist/commands/project/create.js +38 -4
  24. package/dist/commands/spec/create.d.ts +1 -0
  25. package/dist/commands/spec/create.js +43 -2
  26. package/dist/commands/spec/index.js +2 -2
  27. package/dist/commands/{agent/staff → staff}/add.js +10 -10
  28. package/dist/commands/{agent/staff → staff}/index.d.ts +1 -1
  29. package/dist/commands/{agent/staff → staff}/index.js +7 -7
  30. package/dist/commands/{agent/staff → staff}/list.js +3 -3
  31. package/dist/commands/{agent/staff → staff}/remove.d.ts +1 -1
  32. package/dist/commands/{agent/staff → staff}/remove.js +8 -8
  33. package/dist/commands/{ticket/template → template}/apply.d.ts +8 -6
  34. package/dist/commands/template/apply.js +262 -0
  35. package/dist/commands/{ticket/template → template}/create.d.ts +5 -6
  36. package/dist/commands/template/create.js +238 -0
  37. package/dist/commands/template/index.js +48 -36
  38. package/dist/commands/{ticket/template → template}/save.d.ts +2 -2
  39. package/dist/commands/template/save.js +104 -0
  40. package/dist/commands/{phase/template → template}/update.d.ts +2 -2
  41. package/dist/commands/template/update.js +99 -0
  42. package/dist/commands/{agent/themes → theme}/add-names.d.ts +1 -1
  43. package/dist/commands/{agent/themes → theme}/add-names.js +6 -6
  44. package/dist/commands/{agent/themes → theme}/create.d.ts +1 -1
  45. package/dist/commands/{agent/themes → theme}/create.js +5 -5
  46. package/dist/commands/{agent/themes → theme}/index.d.ts +1 -1
  47. package/dist/commands/{agent/themes → theme}/index.js +10 -10
  48. package/dist/commands/{agent/themes → theme}/list.d.ts +1 -1
  49. package/dist/commands/{agent/themes → theme}/list.js +5 -5
  50. package/dist/commands/{agent/themes → theme}/set.d.ts +1 -1
  51. package/dist/commands/{agent/themes → theme}/set.js +7 -7
  52. package/dist/commands/ticket/create.d.ts +1 -0
  53. package/dist/commands/ticket/create.js +54 -2
  54. package/dist/commands/ticket/index.js +6 -6
  55. package/dist/commands/work/spawn.js +1 -1
  56. package/dist/lib/mcp/helpers.d.ts +43 -0
  57. package/dist/lib/mcp/helpers.js +57 -0
  58. package/dist/lib/mcp/index.d.ts +6 -0
  59. package/dist/lib/mcp/index.js +6 -0
  60. package/dist/lib/mcp/tools/action.d.ts +6 -0
  61. package/dist/lib/mcp/tools/action.js +88 -0
  62. package/dist/lib/mcp/tools/board.d.ts +6 -0
  63. package/dist/lib/mcp/tools/board.js +139 -0
  64. package/dist/lib/mcp/tools/category.d.ts +6 -0
  65. package/dist/lib/mcp/tools/category.js +84 -0
  66. package/dist/lib/mcp/tools/cli-passthrough.d.ts +15 -0
  67. package/dist/lib/mcp/tools/cli-passthrough.js +333 -0
  68. package/dist/lib/mcp/tools/epic.d.ts +6 -0
  69. package/dist/lib/mcp/tools/epic.js +178 -0
  70. package/dist/lib/mcp/tools/index.d.ts +18 -0
  71. package/dist/lib/mcp/tools/index.js +19 -0
  72. package/dist/lib/mcp/tools/phase.d.ts +6 -0
  73. package/dist/lib/mcp/tools/phase.js +131 -0
  74. package/dist/lib/mcp/tools/project.d.ts +6 -0
  75. package/dist/lib/mcp/tools/project.js +196 -0
  76. package/dist/lib/mcp/tools/roadmap.d.ts +6 -0
  77. package/dist/lib/mcp/tools/roadmap.js +123 -0
  78. package/dist/lib/mcp/tools/spec.d.ts +6 -0
  79. package/dist/lib/mcp/tools/spec.js +196 -0
  80. package/dist/lib/mcp/tools/status.d.ts +6 -0
  81. package/dist/lib/mcp/tools/status.js +109 -0
  82. package/dist/lib/mcp/tools/template.d.ts +6 -0
  83. package/dist/lib/mcp/tools/template.js +107 -0
  84. package/dist/lib/mcp/tools/ticket.d.ts +6 -0
  85. package/dist/lib/mcp/tools/ticket.js +393 -0
  86. package/dist/lib/mcp/tools/view.d.ts +6 -0
  87. package/dist/lib/mcp/tools/view.js +76 -0
  88. package/dist/lib/mcp/tools/work.d.ts +6 -0
  89. package/dist/lib/mcp/tools/work.js +132 -0
  90. package/dist/lib/mcp/tools/workflow.d.ts +6 -0
  91. package/dist/lib/mcp/tools/workflow.js +95 -0
  92. package/dist/lib/mcp/types.d.ts +17 -0
  93. package/dist/lib/mcp/types.js +4 -0
  94. package/dist/lib/prompt-json.d.ts +52 -1
  95. package/dist/lib/prompt-json.js +45 -0
  96. package/oclif.manifest.json +3553 -5457
  97. package/package.json +10 -7
  98. package/dist/commands/agent/temp/index.d.ts +0 -14
  99. package/dist/commands/agent/temp/index.js +0 -85
  100. package/dist/commands/agent/temp/list.d.ts +0 -7
  101. package/dist/commands/agent/temp/list.js +0 -108
  102. package/dist/commands/epic/link/block.d.ts +0 -14
  103. package/dist/commands/epic/link/block.js +0 -81
  104. package/dist/commands/epic/link/duplicates.js +0 -68
  105. package/dist/commands/epic/link/index.d.ts +0 -19
  106. package/dist/commands/epic/link/index.js +0 -272
  107. package/dist/commands/epic/link/relates.js +0 -68
  108. package/dist/commands/epic/link/remove.js +0 -93
  109. package/dist/commands/phase/template/apply.d.ts +0 -17
  110. package/dist/commands/phase/template/apply.js +0 -108
  111. package/dist/commands/phase/template/create.d.ts +0 -17
  112. package/dist/commands/phase/template/create.js +0 -104
  113. package/dist/commands/phase/template/delete.d.ts +0 -17
  114. package/dist/commands/phase/template/delete.js +0 -100
  115. package/dist/commands/phase/template/index.d.ts +0 -15
  116. package/dist/commands/phase/template/index.js +0 -130
  117. package/dist/commands/phase/template/list.d.ts +0 -16
  118. package/dist/commands/phase/template/list.js +0 -97
  119. package/dist/commands/phase/template/update.js +0 -89
  120. package/dist/commands/spec/link/depends.d.ts +0 -14
  121. package/dist/commands/spec/link/depends.js +0 -64
  122. package/dist/commands/spec/link/duplicates.d.ts +0 -14
  123. package/dist/commands/spec/link/duplicates.js +0 -63
  124. package/dist/commands/spec/link/index.d.ts +0 -19
  125. package/dist/commands/spec/link/index.js +0 -207
  126. package/dist/commands/spec/link/relates.d.ts +0 -14
  127. package/dist/commands/spec/link/relates.js +0 -63
  128. package/dist/commands/spec/link/remove.js +0 -96
  129. package/dist/commands/template/phase/apply.d.ts +0 -14
  130. package/dist/commands/template/phase/apply.js +0 -43
  131. package/dist/commands/template/phase/create.d.ts +0 -13
  132. package/dist/commands/template/phase/create.js +0 -38
  133. package/dist/commands/template/phase/delete.d.ts +0 -13
  134. package/dist/commands/template/phase/delete.js +0 -36
  135. package/dist/commands/template/phase/index.d.ts +0 -10
  136. package/dist/commands/template/phase/index.js +0 -63
  137. package/dist/commands/template/phase/list.d.ts +0 -11
  138. package/dist/commands/template/phase/list.js +0 -36
  139. package/dist/commands/template/phase/update.d.ts +0 -14
  140. package/dist/commands/template/phase/update.js +0 -43
  141. package/dist/commands/template/ticket/apply.d.ts +0 -17
  142. package/dist/commands/template/ticket/apply.js +0 -60
  143. package/dist/commands/template/ticket/create.d.ts +0 -20
  144. package/dist/commands/template/ticket/create.js +0 -89
  145. package/dist/commands/template/ticket/delete.d.ts +0 -13
  146. package/dist/commands/template/ticket/delete.js +0 -38
  147. package/dist/commands/template/ticket/index.d.ts +0 -10
  148. package/dist/commands/template/ticket/index.js +0 -63
  149. package/dist/commands/template/ticket/list.d.ts +0 -11
  150. package/dist/commands/template/ticket/list.js +0 -36
  151. package/dist/commands/template/ticket/save.d.ts +0 -15
  152. package/dist/commands/template/ticket/save.js +0 -46
  153. package/dist/commands/ticket/link/block.d.ts +0 -14
  154. package/dist/commands/ticket/link/block.js +0 -96
  155. package/dist/commands/ticket/link/duplicates.d.ts +0 -14
  156. package/dist/commands/ticket/link/duplicates.js +0 -95
  157. package/dist/commands/ticket/link/index.d.ts +0 -19
  158. package/dist/commands/ticket/link/index.js +0 -256
  159. package/dist/commands/ticket/link/relates.d.ts +0 -14
  160. package/dist/commands/ticket/link/relates.js +0 -95
  161. package/dist/commands/ticket/link/remove.d.ts +0 -16
  162. package/dist/commands/ticket/link/remove.js +0 -132
  163. package/dist/commands/ticket/template/apply.js +0 -252
  164. package/dist/commands/ticket/template/create.js +0 -386
  165. package/dist/commands/ticket/template/delete.d.ts +0 -17
  166. package/dist/commands/ticket/template/delete.js +0 -94
  167. package/dist/commands/ticket/template/index.d.ts +0 -15
  168. package/dist/commands/ticket/template/index.js +0 -120
  169. package/dist/commands/ticket/template/list.d.ts +0 -16
  170. package/dist/commands/ticket/template/list.js +0 -112
  171. package/dist/commands/ticket/template/save.js +0 -163
  172. /package/dist/commands/{agent/staff → staff}/add.d.ts +0 -0
  173. /package/dist/commands/{agent/staff → staff}/list.d.ts +0 -0
@@ -1,132 +0,0 @@
1
- import { Args, Flags } from '@oclif/core';
2
- import { autoExportToBoard, 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 TicketLinkRemove extends PMOCommand {
6
- static description = 'Remove a dependency from a ticket';
7
- static examples = [
8
- '<%= config.bin %> <%= command.id %> TKT-001 TKT-002',
9
- '<%= config.bin %> <%= command.id %> TKT-001 TKT-002 --type blocks',
10
- '<%= config.bin %> <%= command.id %> TKT-001 --all',
11
- '<%= config.bin %> <%= command.id %> TKT-001 # Interactive selection',
12
- ];
13
- static args = {
14
- id: Args.string({
15
- description: 'Ticket ID',
16
- required: true,
17
- }),
18
- target: Args.string({
19
- description: 'Target ticket ID to unlink',
20
- required: false,
21
- }),
22
- };
23
- static flags = {
24
- ...pmoBaseFlags,
25
- json: Flags.boolean({
26
- char: 'm',
27
- aliases: ['machine'],
28
- description: 'Output prompt configuration as JSON (for AI agents/scripts)',
29
- default: false,
30
- }),
31
- type: Flags.string({
32
- char: 't',
33
- description: 'Dependency type to remove',
34
- options: ['blocks', 'relates_to', 'duplicates'],
35
- }),
36
- all: Flags.boolean({
37
- char: 'a',
38
- description: 'Remove all dependencies for this ticket',
39
- default: false,
40
- }),
41
- };
42
- async execute() {
43
- const { args, flags } = await this.parse(TicketLinkRemove);
44
- // Check if JSON output mode is active
45
- const jsonMode = shouldOutputJson(flags);
46
- // Helper to handle errors in JSON mode
47
- const handleError = (code, message) => {
48
- if (jsonMode) {
49
- outputErrorAsJson(code, message, createMetadata('ticket link remove', flags));
50
- this.exit(1);
51
- }
52
- this.error(message);
53
- };
54
- const ticket = await this.storage.getTicket(args.id);
55
- if (!ticket) {
56
- return handleError('TICKET_NOT_FOUND', `Ticket not found: ${args.id}`);
57
- }
58
- const dependencies = await this.storage.listTicketDependencies(args.id);
59
- if (dependencies.length === 0) {
60
- if (jsonMode) {
61
- outputErrorAsJson('NO_DEPENDENCIES', `Ticket ${args.id} has no dependencies.`, createMetadata('ticket link remove', flags));
62
- return;
63
- }
64
- this.log(styles.muted(`\nTicket ${args.id} has no dependencies.`));
65
- return;
66
- }
67
- // If --all flag, remove all dependencies
68
- if (flags.all) {
69
- const confirmChoices = [
70
- { id: 'no', name: 'No, cancel' },
71
- { id: 'yes', name: `Yes, remove all ${dependencies.length} dependencies` },
72
- ];
73
- const confirmed = await this.selectFromList({
74
- message: `Remove all ${dependencies.length} dependencies from ${args.id}?`,
75
- items: confirmChoices,
76
- getName: (c) => c.name,
77
- getValue: (c) => c.id,
78
- getCommand: (c) => c.id === 'yes' ? `prlt ticket link remove ${args.id} --all --force --json` : '',
79
- jsonMode: jsonMode ? { flags, commandName: 'ticket link remove' } : null,
80
- });
81
- if (confirmed !== 'yes') {
82
- this.log(styles.muted('\nCancelled.'));
83
- return;
84
- }
85
- // Delete sequentially for data integrity
86
- for (const dep of dependencies) {
87
- // eslint-disable-next-line no-await-in-loop
88
- await this.storage.deleteTicketDependency(args.id, dep.dependsOnTicketId, dep.dependencyType);
89
- }
90
- await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
91
- this.log(styles.success(`\n✅ Removed ${dependencies.length} dependencies from ${args.id}`));
92
- return;
93
- }
94
- let targetId = args.target;
95
- // If no target provided, prompt for selection
96
- if (!targetId) {
97
- const depChoices = await Promise.all(dependencies.map(async (dep) => {
98
- const depTicket = await this.storage.getTicket(dep.dependsOnTicketId);
99
- return {
100
- id: dep.dependsOnTicketId,
101
- name: `${dep.dependsOnTicketId} - ${depTicket?.title || 'Unknown'} (${dep.dependencyType})`,
102
- type: dep.dependencyType,
103
- };
104
- }));
105
- const selected = await this.selectFromList({
106
- message: 'Select dependency to remove:',
107
- items: depChoices,
108
- getName: (d) => d.name,
109
- getValue: (d) => d.id,
110
- getCommand: (d) => `prlt ticket link remove ${args.id} ${d.id} --type ${d.type}${flags.project ? ` -P ${flags.project}` : ''} --json`,
111
- jsonMode: jsonMode ? { flags, commandName: 'ticket link remove' } : null,
112
- });
113
- if (!selected) {
114
- return;
115
- }
116
- targetId = selected;
117
- }
118
- // Find the dependency
119
- const dep = dependencies.find(d => d.dependsOnTicketId === targetId);
120
- if (!dep) {
121
- this.error(`No dependency found from ${args.id} to ${targetId}`);
122
- }
123
- const dependencyType = flags.type;
124
- await this.storage.deleteTicketDependency(args.id, targetId, dependencyType);
125
- await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
126
- const depTicket = await this.storage.getTicket(targetId);
127
- this.log(styles.success(`\n✅ Removed dependency: ${args.id} → ${targetId}`));
128
- if (depTicket) {
129
- this.log(styles.muted(` ${ticket.title} no longer linked to ${depTicket.title}`));
130
- }
131
- }
132
- }
@@ -1,252 +0,0 @@
1
- import { Flags, Args } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
- import { PMOCommand, pmoBaseFlags, autoExportToBoard } from '../../../lib/pmo/index.js';
4
- import { PRIORITIES, PRIORITY_LABELS } from '../../../lib/pmo/types.js';
5
- import { styles } from '../../../lib/styles.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildFormPromptConfig, } from '../../../lib/prompt-json.js';
7
- export default class TicketTemplateApply extends PMOCommand {
8
- static description = 'Create a new ticket from a template';
9
- static examples = [
10
- '<%= config.bin %> <%= command.id %> bug-report',
11
- '<%= config.bin %> <%= command.id %> feature-request --title "Add dark mode"',
12
- '<%= config.bin %> <%= command.id %> bug-report --project my-project',
13
- '<%= config.bin %> <%= command.id %> bug-report -t "Login fails" -c Backlog',
14
- ];
15
- static args = {
16
- template: Args.string({
17
- description: 'Template ID to use',
18
- required: false,
19
- }),
20
- };
21
- static flags = {
22
- ...pmoBaseFlags,
23
- title: Flags.string({
24
- char: 't',
25
- description: 'Ticket title (overrides template pattern)',
26
- }),
27
- column: Flags.string({
28
- char: 'c',
29
- description: 'Column to place the ticket in',
30
- }),
31
- priority: Flags.string({
32
- char: 'p',
33
- description: 'Priority (overrides template default)',
34
- options: [...PRIORITIES],
35
- }),
36
- category: Flags.string({
37
- description: 'Category (overrides template default)',
38
- }),
39
- assignee: Flags.string({
40
- char: 'a',
41
- description: 'Assignee (overrides template default)',
42
- }),
43
- owner: Flags.string({
44
- char: 'o',
45
- description: 'Owner (overrides template default)',
46
- }),
47
- status: Flags.string({
48
- char: 's',
49
- description: 'Status ID (overrides template default)',
50
- }),
51
- labels: Flags.string({
52
- char: 'l',
53
- description: 'Labels (comma-separated, overrides template default)',
54
- }),
55
- description: Flags.string({
56
- char: 'd',
57
- description: 'Description (overrides template)',
58
- }),
59
- interactive: Flags.boolean({
60
- char: 'i',
61
- description: 'Interactive mode - prompt for values',
62
- default: false,
63
- }),
64
- json: Flags.boolean({
65
- char: 'm',
66
- aliases: ['machine'],
67
- description: 'Output prompt configuration as JSON (for AI agents/scripts)',
68
- default: false,
69
- }),
70
- 'no-subtasks': Flags.boolean({
71
- description: 'Do not create suggested subtasks',
72
- default: false,
73
- }),
74
- epic: Flags.string({
75
- char: 'e',
76
- description: 'Link ticket to an epic',
77
- }),
78
- };
79
- async execute() {
80
- const { args, flags } = await this.parse(TicketTemplateApply);
81
- // This command requires project context - get projectId and board info
82
- const projectId = await this.requireProject();
83
- const board = await this.storage.getBoard(projectId);
84
- const columns = board.columns.map(col => col.name);
85
- const projectName = board.name;
86
- // Check if JSON output mode is active
87
- const jsonMode = shouldOutputJson(flags);
88
- // Helper to handle errors in JSON mode
89
- const handleError = (code, message) => {
90
- if (jsonMode) {
91
- outputErrorAsJson(code, message, createMetadata('ticket template apply', flags));
92
- this.exit(1);
93
- }
94
- this.error(message);
95
- };
96
- // Get the template - prompt for selection if not provided
97
- let templateId = args.template;
98
- if (!templateId) {
99
- const templates = await this.storage.listTicketTemplates();
100
- if (templates.length === 0) {
101
- return handleError('NO_TEMPLATES', `No ticket templates found.\nCreate one with: prlt ticket template save <ticket-id> "Template Name"`);
102
- }
103
- const { selectedTemplate } = await inquirer.prompt([{
104
- type: 'list',
105
- name: 'selectedTemplate',
106
- message: 'Select a template:',
107
- choices: templates.map(t => ({
108
- name: `${t.name}${t.description ? ` - ${t.description}` : ''}`,
109
- value: t.id,
110
- })),
111
- }]);
112
- templateId = selectedTemplate;
113
- }
114
- const template = await this.storage.getTicketTemplate(templateId);
115
- if (!template) {
116
- return handleError('TEMPLATE_NOT_FOUND', `Template not found: ${templateId}\nRun 'prlt ticket template list' to see available templates.`);
117
- }
118
- // Validate epic if provided
119
- if (flags.epic) {
120
- const epic = await this.storage.getEpic(flags.epic);
121
- if (!epic) {
122
- this.error(`Epic not found: ${flags.epic}. Use 'prlt epic list' to see available epics.`);
123
- }
124
- }
125
- // Determine ticket data
126
- let title = flags.title || template.titlePattern || '';
127
- let column = flags.column || columns[0];
128
- let priority = flags.priority || template.defaultPriority;
129
- let category = flags.category || template.defaultCategory;
130
- let assignee = flags.assignee || template.defaultAssignee;
131
- let owner = flags.owner || template.defaultOwner;
132
- const statusId = flags.status || template.defaultStatusId;
133
- const labels = flags.labels ? flags.labels.split(',').map(l => l.trim()).filter(Boolean) : template.defaultLabels;
134
- let description = flags.description || template.descriptionTemplate;
135
- // Interactive mode - prompt for values
136
- if (flags.interactive || !title) {
137
- // Build choices once - single source of truth
138
- const columnChoices = columns.map(c => ({ name: c, value: c }));
139
- const priorityChoices = [
140
- { name: 'None', value: '' },
141
- ...PRIORITIES.map(p => ({ name: PRIORITY_LABELS[p], value: p })),
142
- ];
143
- // Define fields once - single source of truth for both JSON and interactive modes
144
- const fields = [
145
- { type: 'input', name: 'title', message: 'Ticket title:', default: title || undefined },
146
- { type: 'list', name: 'column', message: 'Column:', choices: columnChoices, default: column },
147
- { type: 'list', name: 'priority', message: 'Priority:', choices: priorityChoices, default: priority },
148
- { type: 'input', name: 'category', message: 'Category:', default: category },
149
- { type: 'input', name: 'assignee', message: 'Assignee:', default: assignee },
150
- { type: 'input', name: 'owner', message: 'Owner:', default: owner },
151
- { type: 'editor', name: 'description', message: 'Description:', default: description },
152
- ];
153
- // In JSON mode, output form prompts
154
- if (jsonMode) {
155
- outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('ticket template apply', flags));
156
- }
157
- // Build inquirer prompts from fields, adding validators and inquirer-specific options
158
- const answers = await inquirer.prompt(fields.map(field => ({
159
- ...field,
160
- // Convert empty string to undefined for priority choices in inquirer
161
- choices: field.name === 'priority' && field.choices
162
- ? field.choices.map(c => ({ ...c, value: c.value || undefined }))
163
- : field.name === 'column'
164
- ? columns // Use simple array for column in interactive mode
165
- : field.choices,
166
- // Add validator for title
167
- validate: field.name === 'title'
168
- ? ((input) => input.length > 0 || 'Title is required')
169
- : undefined,
170
- // Update editor message for interactive mode
171
- message: field.name === 'description' ? 'Description (opens editor):' : field.message,
172
- // Add waitForUseInput for editor
173
- waitForUseInput: field.type === 'editor' ? false : undefined,
174
- })));
175
- title = answers.title;
176
- column = answers.column;
177
- priority = answers.priority;
178
- category = answers.category || undefined;
179
- assignee = answers.assignee || undefined;
180
- owner = answers.owner || undefined;
181
- description = answers.description || undefined;
182
- }
183
- // Validate column
184
- if (!columns.includes(column)) {
185
- this.error(`Invalid column "${column}". Available columns: ${columns.join(', ')}`);
186
- }
187
- // Validate status ID if provided
188
- if (statusId) {
189
- const status = await this.storage.getStatus(statusId);
190
- if (!status) {
191
- // Get project's workflow to list available statuses
192
- const projectInfo = await this.storage.getProject(projectId);
193
- const workflowId = projectInfo?.workflowId;
194
- const statuses = workflowId ? await this.storage.listStatuses(workflowId) : [];
195
- const statusNames = statuses.map(s => `${s.id} (${s.name})`).join(', ');
196
- this.error(`Invalid status "${statusId}". Available statuses: ${statusNames}`);
197
- }
198
- }
199
- // Create the ticket
200
- const ticket = await this.storage.createTicket(projectId, {
201
- title,
202
- statusName: column,
203
- priority,
204
- category,
205
- assignee,
206
- owner,
207
- statusId,
208
- labels,
209
- description,
210
- epicId: flags.epic,
211
- });
212
- // Add subtasks from template (unless disabled) - sequential for ordering
213
- if (!flags['no-subtasks'] && template.suggestedSubtasks.length > 0) {
214
- for (const subtask of template.suggestedSubtasks) {
215
- // eslint-disable-next-line no-await-in-loop
216
- await this.storage.addSubtask(ticket.id, subtask.title);
217
- }
218
- }
219
- // Auto-export to board.md
220
- await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
221
- this.log(styles.success(`\nCreated ticket ${styles.emphasis(ticket.id)} from template "${template.name}"`));
222
- this.log(styles.muted(` Project: ${projectName}`));
223
- this.log(styles.muted(` Title: ${ticket.title}`));
224
- this.log(styles.muted(` Status: ${ticket.statusName}`));
225
- if (priority) {
226
- this.log(styles.muted(` Priority: ${priority}`));
227
- }
228
- if (category) {
229
- this.log(styles.muted(` Category: ${category}`));
230
- }
231
- if (assignee) {
232
- this.log(styles.muted(` Assignee: ${assignee}`));
233
- }
234
- if (owner) {
235
- this.log(styles.muted(` Owner: ${owner}`));
236
- }
237
- if (statusId) {
238
- this.log(styles.muted(` Status: ${statusId}`));
239
- }
240
- if (labels && labels.length > 0) {
241
- this.log(styles.muted(` Labels: ${labels.join(', ')}`));
242
- }
243
- if (flags.epic) {
244
- this.log(styles.muted(` Epic: ${flags.epic}`));
245
- }
246
- if (!flags['no-subtasks'] && template.suggestedSubtasks.length > 0) {
247
- this.log(styles.muted(` Subtasks: ${template.suggestedSubtasks.length} created`));
248
- }
249
- this.log('');
250
- this.log(styles.muted(`View ticket: prlt ticket view ${ticket.id}`));
251
- }
252
- }