@proletariat/cli 0.3.23 → 0.3.25

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 (235) hide show
  1. package/dist/commands/action/create.js +4 -4
  2. package/dist/commands/action/update.js +3 -3
  3. package/dist/commands/agent/{temp/cleanup.d.ts → cleanup.d.ts} +1 -1
  4. package/dist/commands/agent/{temp/cleanup.js → cleanup.js} +4 -4
  5. package/dist/commands/agent/index.js +8 -8
  6. package/dist/commands/branch/create.js +2 -2
  7. package/dist/commands/epic/activate.js +9 -17
  8. package/dist/commands/epic/archive.js +13 -24
  9. package/dist/commands/epic/create.d.ts +1 -0
  10. package/dist/commands/epic/create.js +46 -8
  11. package/dist/commands/epic/index.js +2 -2
  12. package/dist/commands/epic/move.js +28 -47
  13. package/dist/commands/epic/progress.js +10 -14
  14. package/dist/commands/epic/project.js +42 -59
  15. package/dist/commands/epic/reorder.js +25 -30
  16. package/dist/commands/epic/spec.d.ts +1 -0
  17. package/dist/commands/epic/spec.js +39 -40
  18. package/dist/commands/epic/ticket.d.ts +2 -0
  19. package/dist/commands/epic/ticket.js +63 -37
  20. package/dist/commands/feedback/index.d.ts +10 -0
  21. package/dist/commands/feedback/index.js +60 -0
  22. package/dist/commands/feedback/list.d.ts +12 -0
  23. package/dist/commands/feedback/list.js +126 -0
  24. package/dist/commands/feedback/submit.d.ts +16 -0
  25. package/dist/commands/feedback/submit.js +220 -0
  26. package/dist/commands/{template/phase/delete.d.ts → feedback/view.d.ts} +7 -5
  27. package/dist/commands/feedback/view.js +109 -0
  28. package/dist/commands/gh/index.js +4 -0
  29. package/dist/commands/{epic/link/remove.d.ts → link/create.d.ts} +6 -7
  30. package/dist/commands/link/create.js +141 -0
  31. package/dist/commands/{epic/link/relates.d.ts → link/index.d.ts} +4 -5
  32. package/dist/commands/link/index.js +87 -0
  33. package/dist/commands/{epic/link/duplicates.d.ts → link/list.d.ts} +7 -4
  34. package/dist/commands/link/list.js +182 -0
  35. package/dist/commands/{spec/link → link}/remove.d.ts +4 -5
  36. package/dist/commands/link/remove.js +120 -0
  37. package/dist/commands/mcp-server.d.ts +22 -0
  38. package/dist/commands/mcp-server.js +98 -0
  39. package/dist/commands/phase/create.js +1 -1
  40. package/dist/commands/project/create.d.ts +1 -0
  41. package/dist/commands/project/create.js +38 -4
  42. package/dist/commands/repo/create.d.ts +38 -0
  43. package/dist/commands/repo/create.js +283 -0
  44. package/dist/commands/repo/index.js +7 -0
  45. package/dist/commands/roadmap/add-project.js +9 -22
  46. package/dist/commands/roadmap/create.d.ts +0 -1
  47. package/dist/commands/roadmap/create.js +46 -40
  48. package/dist/commands/roadmap/delete.js +10 -24
  49. package/dist/commands/roadmap/generate.d.ts +1 -0
  50. package/dist/commands/roadmap/generate.js +21 -22
  51. package/dist/commands/roadmap/remove-project.js +14 -34
  52. package/dist/commands/roadmap/reorder.js +19 -26
  53. package/dist/commands/roadmap/update.js +27 -26
  54. package/dist/commands/roadmap/view.js +5 -12
  55. package/dist/commands/session/attach.d.ts +1 -8
  56. package/dist/commands/session/attach.js +93 -59
  57. package/dist/commands/session/list.d.ts +0 -8
  58. package/dist/commands/session/list.js +130 -81
  59. package/dist/commands/spec/create.d.ts +1 -0
  60. package/dist/commands/spec/create.js +44 -3
  61. package/dist/commands/spec/edit.js +63 -33
  62. package/dist/commands/spec/index.js +2 -2
  63. package/dist/commands/{agent/staff → staff}/add.js +10 -10
  64. package/dist/commands/{agent/staff → staff}/index.d.ts +1 -1
  65. package/dist/commands/{agent/staff → staff}/index.js +7 -7
  66. package/dist/commands/{agent/staff → staff}/list.js +3 -3
  67. package/dist/commands/{agent/staff → staff}/remove.d.ts +1 -1
  68. package/dist/commands/{agent/staff → staff}/remove.js +8 -8
  69. package/dist/commands/{template/phase/index.d.ts → support/book.d.ts} +2 -2
  70. package/dist/commands/support/book.js +54 -0
  71. package/dist/commands/{template/ticket/index.d.ts → support/discord.d.ts} +2 -2
  72. package/dist/commands/support/discord.js +54 -0
  73. package/dist/commands/support/docs.d.ts +10 -0
  74. package/dist/commands/support/docs.js +54 -0
  75. package/dist/commands/support/index.d.ts +19 -0
  76. package/dist/commands/support/index.js +81 -0
  77. package/dist/commands/support/issues.d.ts +11 -0
  78. package/dist/commands/support/issues.js +77 -0
  79. package/dist/commands/support/logs.d.ts +18 -0
  80. package/dist/commands/support/logs.js +247 -0
  81. package/dist/commands/{ticket/template → template}/apply.d.ts +8 -6
  82. package/dist/commands/template/apply.js +262 -0
  83. package/dist/commands/{ticket/template → template}/create.d.ts +5 -6
  84. package/dist/commands/template/create.js +238 -0
  85. package/dist/commands/template/index.js +48 -36
  86. package/dist/commands/{ticket/template → template}/save.d.ts +2 -2
  87. package/dist/commands/template/save.js +104 -0
  88. package/dist/commands/{phase/template → template}/update.d.ts +2 -2
  89. package/dist/commands/template/update.js +99 -0
  90. package/dist/commands/{agent/themes → theme}/add-names.d.ts +1 -1
  91. package/dist/commands/{agent/themes → theme}/add-names.js +6 -6
  92. package/dist/commands/{agent/themes → theme}/create.d.ts +1 -1
  93. package/dist/commands/{agent/themes → theme}/create.js +5 -5
  94. package/dist/commands/{agent/themes → theme}/index.d.ts +1 -1
  95. package/dist/commands/{agent/themes → theme}/index.js +10 -10
  96. package/dist/commands/{agent/themes → theme}/list.d.ts +1 -1
  97. package/dist/commands/{agent/themes → theme}/list.js +5 -5
  98. package/dist/commands/{agent/themes → theme}/set.d.ts +1 -1
  99. package/dist/commands/{agent/themes → theme}/set.js +7 -7
  100. package/dist/commands/ticket/create.d.ts +1 -0
  101. package/dist/commands/ticket/create.js +75 -15
  102. package/dist/commands/ticket/edit.js +44 -13
  103. package/dist/commands/ticket/index.js +6 -6
  104. package/dist/commands/ticket/move.d.ts +7 -0
  105. package/dist/commands/ticket/move.js +132 -0
  106. package/dist/commands/work/spawn.d.ts +1 -0
  107. package/dist/commands/work/spawn.js +72 -8
  108. package/dist/commands/work/start.js +6 -0
  109. package/dist/lib/execution/runners.js +21 -17
  110. package/dist/lib/execution/session-utils.d.ts +60 -0
  111. package/dist/lib/execution/session-utils.js +162 -0
  112. package/dist/lib/execution/spawner.d.ts +2 -0
  113. package/dist/lib/execution/spawner.js +42 -0
  114. package/dist/lib/flags/resolver.d.ts +2 -2
  115. package/dist/lib/flags/resolver.js +15 -0
  116. package/dist/lib/init/index.js +18 -0
  117. package/dist/lib/mcp/helpers.d.ts +43 -0
  118. package/dist/lib/mcp/helpers.js +57 -0
  119. package/dist/lib/mcp/index.d.ts +6 -0
  120. package/dist/lib/mcp/index.js +6 -0
  121. package/dist/lib/mcp/tools/action.d.ts +6 -0
  122. package/dist/lib/mcp/tools/action.js +88 -0
  123. package/dist/lib/mcp/tools/board.d.ts +6 -0
  124. package/dist/lib/mcp/tools/board.js +139 -0
  125. package/dist/lib/mcp/tools/category.d.ts +6 -0
  126. package/dist/lib/mcp/tools/category.js +84 -0
  127. package/dist/lib/mcp/tools/cli-passthrough.d.ts +15 -0
  128. package/dist/lib/mcp/tools/cli-passthrough.js +333 -0
  129. package/dist/lib/mcp/tools/epic.d.ts +6 -0
  130. package/dist/lib/mcp/tools/epic.js +178 -0
  131. package/dist/lib/mcp/tools/index.d.ts +18 -0
  132. package/dist/lib/mcp/tools/index.js +19 -0
  133. package/dist/lib/mcp/tools/phase.d.ts +6 -0
  134. package/dist/lib/mcp/tools/phase.js +131 -0
  135. package/dist/lib/mcp/tools/project.d.ts +6 -0
  136. package/dist/lib/mcp/tools/project.js +196 -0
  137. package/dist/lib/mcp/tools/roadmap.d.ts +6 -0
  138. package/dist/lib/mcp/tools/roadmap.js +123 -0
  139. package/dist/lib/mcp/tools/spec.d.ts +6 -0
  140. package/dist/lib/mcp/tools/spec.js +196 -0
  141. package/dist/lib/mcp/tools/status.d.ts +6 -0
  142. package/dist/lib/mcp/tools/status.js +109 -0
  143. package/dist/lib/mcp/tools/template.d.ts +6 -0
  144. package/dist/lib/mcp/tools/template.js +107 -0
  145. package/dist/lib/mcp/tools/ticket.d.ts +6 -0
  146. package/dist/lib/mcp/tools/ticket.js +393 -0
  147. package/dist/lib/mcp/tools/view.d.ts +6 -0
  148. package/dist/lib/mcp/tools/view.js +76 -0
  149. package/dist/lib/mcp/tools/work.d.ts +6 -0
  150. package/dist/lib/mcp/tools/work.js +132 -0
  151. package/dist/lib/mcp/tools/workflow.d.ts +6 -0
  152. package/dist/lib/mcp/tools/workflow.js +95 -0
  153. package/dist/lib/mcp/types.d.ts +17 -0
  154. package/dist/lib/mcp/types.js +4 -0
  155. package/dist/lib/multiline-input.d.ts +63 -0
  156. package/dist/lib/multiline-input.js +360 -0
  157. package/dist/lib/prompt-json.d.ts +57 -6
  158. package/dist/lib/prompt-json.js +45 -0
  159. package/dist/lib/repos/git.d.ts +7 -0
  160. package/dist/lib/repos/git.js +20 -0
  161. package/oclif.manifest.json +3690 -4995
  162. package/package.json +6 -4
  163. package/dist/commands/agent/temp/index.d.ts +0 -14
  164. package/dist/commands/agent/temp/index.js +0 -85
  165. package/dist/commands/agent/temp/list.d.ts +0 -7
  166. package/dist/commands/agent/temp/list.js +0 -108
  167. package/dist/commands/epic/link/block.d.ts +0 -14
  168. package/dist/commands/epic/link/block.js +0 -81
  169. package/dist/commands/epic/link/duplicates.js +0 -68
  170. package/dist/commands/epic/link/index.d.ts +0 -19
  171. package/dist/commands/epic/link/index.js +0 -272
  172. package/dist/commands/epic/link/relates.js +0 -68
  173. package/dist/commands/epic/link/remove.js +0 -93
  174. package/dist/commands/phase/template/apply.d.ts +0 -17
  175. package/dist/commands/phase/template/apply.js +0 -108
  176. package/dist/commands/phase/template/create.d.ts +0 -17
  177. package/dist/commands/phase/template/create.js +0 -104
  178. package/dist/commands/phase/template/delete.d.ts +0 -17
  179. package/dist/commands/phase/template/delete.js +0 -100
  180. package/dist/commands/phase/template/index.d.ts +0 -15
  181. package/dist/commands/phase/template/index.js +0 -130
  182. package/dist/commands/phase/template/list.d.ts +0 -16
  183. package/dist/commands/phase/template/list.js +0 -97
  184. package/dist/commands/phase/template/update.js +0 -89
  185. package/dist/commands/spec/link/depends.d.ts +0 -14
  186. package/dist/commands/spec/link/depends.js +0 -64
  187. package/dist/commands/spec/link/duplicates.d.ts +0 -14
  188. package/dist/commands/spec/link/duplicates.js +0 -63
  189. package/dist/commands/spec/link/index.d.ts +0 -19
  190. package/dist/commands/spec/link/index.js +0 -207
  191. package/dist/commands/spec/link/relates.d.ts +0 -14
  192. package/dist/commands/spec/link/relates.js +0 -63
  193. package/dist/commands/spec/link/remove.js +0 -96
  194. package/dist/commands/template/phase/apply.d.ts +0 -14
  195. package/dist/commands/template/phase/apply.js +0 -43
  196. package/dist/commands/template/phase/create.d.ts +0 -13
  197. package/dist/commands/template/phase/create.js +0 -38
  198. package/dist/commands/template/phase/delete.js +0 -36
  199. package/dist/commands/template/phase/index.js +0 -63
  200. package/dist/commands/template/phase/list.d.ts +0 -11
  201. package/dist/commands/template/phase/list.js +0 -36
  202. package/dist/commands/template/phase/update.d.ts +0 -14
  203. package/dist/commands/template/phase/update.js +0 -43
  204. package/dist/commands/template/ticket/apply.d.ts +0 -17
  205. package/dist/commands/template/ticket/apply.js +0 -60
  206. package/dist/commands/template/ticket/create.d.ts +0 -20
  207. package/dist/commands/template/ticket/create.js +0 -89
  208. package/dist/commands/template/ticket/delete.d.ts +0 -13
  209. package/dist/commands/template/ticket/delete.js +0 -38
  210. package/dist/commands/template/ticket/index.js +0 -63
  211. package/dist/commands/template/ticket/list.d.ts +0 -11
  212. package/dist/commands/template/ticket/list.js +0 -36
  213. package/dist/commands/template/ticket/save.d.ts +0 -15
  214. package/dist/commands/template/ticket/save.js +0 -46
  215. package/dist/commands/ticket/link/block.d.ts +0 -14
  216. package/dist/commands/ticket/link/block.js +0 -96
  217. package/dist/commands/ticket/link/duplicates.d.ts +0 -14
  218. package/dist/commands/ticket/link/duplicates.js +0 -95
  219. package/dist/commands/ticket/link/index.d.ts +0 -19
  220. package/dist/commands/ticket/link/index.js +0 -256
  221. package/dist/commands/ticket/link/relates.d.ts +0 -14
  222. package/dist/commands/ticket/link/relates.js +0 -95
  223. package/dist/commands/ticket/link/remove.d.ts +0 -16
  224. package/dist/commands/ticket/link/remove.js +0 -132
  225. package/dist/commands/ticket/template/apply.js +0 -252
  226. package/dist/commands/ticket/template/create.js +0 -386
  227. package/dist/commands/ticket/template/delete.d.ts +0 -17
  228. package/dist/commands/ticket/template/delete.js +0 -94
  229. package/dist/commands/ticket/template/index.d.ts +0 -15
  230. package/dist/commands/ticket/template/index.js +0 -120
  231. package/dist/commands/ticket/template/list.d.ts +0 -16
  232. package/dist/commands/ticket/template/list.js +0 -112
  233. package/dist/commands/ticket/template/save.js +0 -163
  234. /package/dist/commands/{agent/staff → staff}/add.d.ts +0 -0
  235. /package/dist/commands/{agent/staff → staff}/list.d.ts +0 -0
@@ -1,386 +0,0 @@
1
- import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
- import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
4
- import { PRIORITIES, PRIORITY_LABELS, TICKET_CATEGORIES } from '../../../lib/pmo/types.js';
5
- import { styles } from '../../../lib/styles.js';
6
- import { shouldOutputJson, outputSuccessAsJson, outputPromptAsJson, buildFormPromptConfig, createMetadata, } from '../../../lib/prompt-json.js';
7
- export default class TicketTemplateCreate extends PMOCommand {
8
- static description = 'Create a new ticket template from scratch';
9
- static examples = [
10
- '<%= config.bin %> <%= command.id %> "Bug Report"',
11
- '<%= config.bin %> <%= command.id %> "Feature Request" -d "Template for new features"',
12
- '<%= config.bin %> <%= command.id %> "Task" --title-pattern "[TASK] " --priority P2',
13
- '<%= config.bin %> <%= command.id %> "Onboarding" --subtask "Setup environment" --subtask "Read docs"',
14
- '<%= config.bin %> <%= command.id %> "Bug" --ac "Bug is fixed" --ac "Tests pass" --category bug',
15
- ];
16
- static args = {
17
- name: Args.string({
18
- description: 'Template name',
19
- required: false,
20
- }),
21
- };
22
- static flags = {
23
- ...pmoBaseFlags,
24
- description: Flags.string({
25
- char: 'd',
26
- description: 'Template description',
27
- }),
28
- 'title-pattern': Flags.string({
29
- description: 'Default title prefix/pattern (e.g., "[BUG] ")',
30
- }),
31
- 'description-template': Flags.string({
32
- description: 'Default description template (markdown)',
33
- }),
34
- priority: Flags.string({
35
- char: 'p',
36
- description: 'Default priority',
37
- options: [...PRIORITIES],
38
- }),
39
- category: Flags.string({
40
- char: 'c',
41
- description: 'Default category',
42
- options: [...TICKET_CATEGORIES],
43
- }),
44
- subtask: Flags.string({
45
- description: 'Add a suggested subtask (can be used multiple times)',
46
- multiple: true,
47
- }),
48
- ac: Flags.string({
49
- description: 'Add an acceptance criterion pattern (can be used multiple times)',
50
- multiple: true,
51
- }),
52
- label: Flags.string({
53
- char: 'l',
54
- description: 'Add a default label (can be used multiple times)',
55
- multiple: true,
56
- }),
57
- json: Flags.boolean({
58
- char: 'm',
59
- aliases: ['machine'],
60
- description: 'Output prompt configuration as JSON (for AI agents/scripts)',
61
- default: false,
62
- }),
63
- };
64
- getPMOOptions() {
65
- return { promptIfMultiple: false };
66
- }
67
- async execute() {
68
- const { args, flags } = await this.parse(TicketTemplateCreate);
69
- const jsonMode = shouldOutputJson(flags);
70
- // Check if we have all required data via flags (non-interactive mode)
71
- const hasName = Boolean(args.name);
72
- const hasAllFlags = hasName; // Name is the only required field
73
- // In JSON mode with missing required data, output form prompt
74
- if (jsonMode && !hasAllFlags) {
75
- const fields = [];
76
- if (!hasName) {
77
- fields.push({
78
- type: 'input',
79
- name: 'name',
80
- message: 'Template name:',
81
- });
82
- }
83
- // Add optional fields that weren't provided
84
- if (flags.description === undefined) {
85
- fields.push({
86
- type: 'input',
87
- name: 'description',
88
- message: 'Template description (optional):',
89
- });
90
- }
91
- if (flags['title-pattern'] === undefined) {
92
- fields.push({
93
- type: 'input',
94
- name: 'titlePattern',
95
- message: 'Title prefix/pattern (optional, e.g., "[BUG] "):',
96
- });
97
- }
98
- if (flags.priority === undefined) {
99
- fields.push({
100
- type: 'list',
101
- name: 'priority',
102
- message: 'Default priority:',
103
- choices: [
104
- { name: 'None', value: '' },
105
- ...PRIORITIES.map(p => ({ name: PRIORITY_LABELS[p], value: p })),
106
- ],
107
- });
108
- }
109
- if (flags.category === undefined) {
110
- fields.push({
111
- type: 'list',
112
- name: 'category',
113
- message: 'Default category:',
114
- choices: [
115
- { name: 'None', value: '' },
116
- ...TICKET_CATEGORIES.map(c => ({ name: c, value: c })),
117
- ],
118
- });
119
- }
120
- outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('ticket template create', flags));
121
- return; // outputPromptAsJson exits, but TypeScript needs this
122
- }
123
- // Non-interactive mode: use flag values directly
124
- if (hasAllFlags && (jsonMode || this.hasNonDefaultFlags(flags))) {
125
- const name = args.name;
126
- const description = flags.description;
127
- const titlePattern = flags['title-pattern'];
128
- const priority = flags.priority;
129
- const category = flags.category;
130
- const subtasks = flags.subtask || [];
131
- const acs = flags.ac || [];
132
- const labels = flags.label || [];
133
- // Build description template with ACs if provided
134
- let descriptionTemplate = flags['description-template'];
135
- if (acs.length > 0 && !descriptionTemplate) {
136
- // Create a description template with acceptance criteria section
137
- descriptionTemplate = '## Description\n\n## Acceptance Criteria\n' +
138
- acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
139
- }
140
- else if (acs.length > 0 && descriptionTemplate) {
141
- // Append ACs to existing template if it doesn't have an AC section
142
- if (!descriptionTemplate.toLowerCase().includes('acceptance criteria')) {
143
- descriptionTemplate += '\n\n## Acceptance Criteria\n' +
144
- acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
145
- }
146
- }
147
- // Create the template
148
- const template = await this.storage.createTicketTemplate({
149
- name,
150
- description,
151
- titlePattern,
152
- defaultPriority: priority,
153
- defaultCategory: category,
154
- descriptionTemplate,
155
- suggestedSubtasks: subtasks.map(title => ({ title })),
156
- defaultLabels: labels,
157
- });
158
- if (jsonMode) {
159
- outputSuccessAsJson({
160
- template: {
161
- id: template.id,
162
- name: template.name,
163
- description: template.description,
164
- titlePattern: template.titlePattern,
165
- defaultPriority: template.defaultPriority,
166
- defaultCategory: template.defaultCategory,
167
- descriptionTemplate: template.descriptionTemplate,
168
- suggestedSubtasks: template.suggestedSubtasks,
169
- defaultLabels: template.defaultLabels,
170
- },
171
- }, createMetadata('ticket template create', flags));
172
- return;
173
- }
174
- this.log(styles.success(`\nCreated template "${styles.emphasis(template.name)}"`));
175
- this.log(styles.muted(` ID: ${template.id}`));
176
- this.log('');
177
- this.log(styles.muted(`Create ticket from template: prlt ticket template apply ${template.id}`));
178
- return;
179
- }
180
- // Interactive mode
181
- // Get template name
182
- let name = args.name;
183
- if (!name) {
184
- const { templateName } = await inquirer.prompt([{
185
- type: 'input',
186
- name: 'templateName',
187
- message: 'Template name:',
188
- validate: (input) => input.trim() ? true : 'Name cannot be empty',
189
- }]);
190
- name = templateName;
191
- }
192
- // Get description if not provided
193
- let description = flags.description;
194
- if (description === undefined) {
195
- const { templateDescription } = await inquirer.prompt([{
196
- type: 'input',
197
- name: 'templateDescription',
198
- message: 'Description (optional):',
199
- }]);
200
- description = templateDescription || undefined;
201
- }
202
- // Get title pattern
203
- let titlePattern = flags['title-pattern'];
204
- if (titlePattern === undefined) {
205
- const { pattern } = await inquirer.prompt([{
206
- type: 'input',
207
- name: 'pattern',
208
- message: 'Title prefix/pattern (optional, e.g., "[BUG] "):',
209
- }]);
210
- titlePattern = pattern || undefined;
211
- }
212
- // Get default priority
213
- let priority = flags.priority;
214
- if (priority === undefined) {
215
- const { selectedPriority } = await inquirer.prompt([{
216
- type: 'list',
217
- name: 'selectedPriority',
218
- message: 'Default priority:',
219
- choices: [
220
- { name: 'None', value: '' },
221
- ...PRIORITIES.map(p => ({ name: PRIORITY_LABELS[p], value: p })),
222
- ],
223
- }]);
224
- priority = selectedPriority || undefined;
225
- }
226
- // Get default category
227
- let category = flags.category;
228
- if (category === undefined) {
229
- const { selectedCategory } = await inquirer.prompt([{
230
- type: 'list',
231
- name: 'selectedCategory',
232
- message: 'Default category:',
233
- choices: [
234
- { name: 'None', value: '' },
235
- ...TICKET_CATEGORIES.map(c => ({ name: c, value: c })),
236
- ],
237
- }]);
238
- category = selectedCategory || undefined;
239
- }
240
- // Handle description template - use flag value or prompt
241
- let descriptionTemplate = flags['description-template'];
242
- if (descriptionTemplate === undefined) {
243
- const { wantDescriptionTemplate } = await inquirer.prompt([{
244
- type: 'list',
245
- name: 'wantDescriptionTemplate',
246
- message: 'Add a description template?',
247
- choices: [
248
- { name: 'No', value: false },
249
- { name: 'Yes', value: true },
250
- ],
251
- }]);
252
- if (wantDescriptionTemplate) {
253
- const { template } = await inquirer.prompt([{
254
- type: 'editor',
255
- name: 'template',
256
- message: 'Description template (opens editor):',
257
- default: `## Summary\n\n## Details\n\n## Acceptance Criteria\n- [ ] \n`,
258
- }]);
259
- descriptionTemplate = template || undefined;
260
- }
261
- }
262
- // Handle subtasks - use flag values or prompt
263
- const subtasks = flags.subtask ? [...flags.subtask] : [];
264
- if (subtasks.length === 0) {
265
- const { wantSubtasks } = await inquirer.prompt([{
266
- type: 'list',
267
- name: 'wantSubtasks',
268
- message: 'Add default subtasks?',
269
- choices: [
270
- { name: 'No', value: false },
271
- { name: 'Yes', value: true },
272
- ],
273
- }]);
274
- if (wantSubtasks) {
275
- let addMore = true;
276
- while (addMore) {
277
- // eslint-disable-next-line no-await-in-loop -- Interactive loop for subtask creation
278
- const { subtaskTitle } = await inquirer.prompt([{
279
- type: 'input',
280
- name: 'subtaskTitle',
281
- message: 'Subtask title:',
282
- validate: (input) => input.trim() ? true : 'Title cannot be empty',
283
- }]);
284
- subtasks.push(subtaskTitle);
285
- // eslint-disable-next-line no-await-in-loop -- Interactive loop continuation
286
- const { another } = await inquirer.prompt([{
287
- type: 'list',
288
- name: 'another',
289
- message: 'Add another subtask?',
290
- choices: [
291
- { name: 'No', value: false },
292
- { name: 'Yes', value: true },
293
- ],
294
- }]);
295
- addMore = another;
296
- }
297
- }
298
- }
299
- // Handle ACs - add to description template if provided via flag
300
- const acs = flags.ac || [];
301
- if (acs.length > 0) {
302
- if (!descriptionTemplate) {
303
- descriptionTemplate = '## Description\n\n## Acceptance Criteria\n' +
304
- acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
305
- }
306
- else if (!descriptionTemplate.toLowerCase().includes('acceptance criteria')) {
307
- descriptionTemplate += '\n\n## Acceptance Criteria\n' +
308
- acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
309
- }
310
- }
311
- // Handle labels
312
- const labels = flags.label ? [...flags.label] : [];
313
- // Show preview
314
- this.log(`\n${styles.emphasis('Template Preview:')}`);
315
- this.log(styles.muted(` Name: ${name}`));
316
- if (description) {
317
- this.log(styles.muted(` Description: ${description}`));
318
- }
319
- if (titlePattern) {
320
- this.log(styles.muted(` Title pattern: ${titlePattern}`));
321
- }
322
- if (priority) {
323
- this.log(styles.muted(` Default priority: ${PRIORITY_LABELS[priority] || priority}`));
324
- }
325
- if (category) {
326
- this.log(styles.muted(` Default category: ${category}`));
327
- }
328
- if (descriptionTemplate) {
329
- this.log(styles.muted(` Description template: (custom)`));
330
- }
331
- if (subtasks.length > 0) {
332
- this.log(styles.muted(` Default subtasks:`));
333
- for (const subtask of subtasks) {
334
- this.log(styles.muted(` - ${subtask}`));
335
- }
336
- }
337
- if (labels.length > 0) {
338
- this.log(styles.muted(` Default labels: ${labels.join(', ')}`));
339
- }
340
- // Confirm creation
341
- const { confirm } = await inquirer.prompt([{
342
- type: 'list',
343
- name: 'confirm',
344
- message: 'Create this template?',
345
- choices: [
346
- { name: 'Yes', value: true },
347
- { name: 'No', value: false },
348
- ],
349
- }]);
350
- if (!confirm) {
351
- this.log(styles.muted('Cancelled.'));
352
- return;
353
- }
354
- // Create the template
355
- const template = await this.storage.createTicketTemplate({
356
- name: name,
357
- description,
358
- titlePattern,
359
- defaultPriority: priority,
360
- defaultCategory: category,
361
- descriptionTemplate,
362
- suggestedSubtasks: subtasks.map(title => ({ title })),
363
- defaultLabels: labels,
364
- });
365
- this.log(styles.success(`\nCreated template "${styles.emphasis(template.name)}"`));
366
- this.log(styles.muted(` ID: ${template.id}`));
367
- this.log('');
368
- this.log(styles.muted(`Create ticket from template: prlt ticket template apply ${template.id}`));
369
- }
370
- /**
371
- * Check if any non-default flags were provided (indicating non-interactive intent)
372
- */
373
- hasNonDefaultFlags(flags) {
374
- const nonDefaultFlags = [
375
- 'description',
376
- 'title-pattern',
377
- 'description-template',
378
- 'priority',
379
- 'category',
380
- 'subtask',
381
- 'ac',
382
- 'label',
383
- ];
384
- return nonDefaultFlags.some(flag => flags[flag] !== undefined);
385
- }
386
- }
@@ -1,17 +0,0 @@
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 | undefined, Record<string, unknown>>;
7
- };
8
- static flags: {
9
- json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
- force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
- project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
- };
13
- protected getPMOOptions(): {
14
- promptIfMultiple: boolean;
15
- };
16
- execute(): Promise<void>;
17
- }
@@ -1,94 +0,0 @@
1
- import { Flags, Args } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
- import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
4
- import { styles } from '../../../lib/styles.js';
5
- import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../../lib/prompt-json.js';
6
- export default class TicketTemplateDelete extends PMOCommand {
7
- static description = 'Delete a ticket template';
8
- static examples = [
9
- '<%= config.bin %> <%= command.id %> my-template',
10
- '<%= config.bin %> <%= command.id %> my-template --force',
11
- ];
12
- static args = {
13
- id: Args.string({
14
- description: 'Template ID to delete',
15
- required: false,
16
- }),
17
- };
18
- static flags = {
19
- ...pmoBaseFlags,
20
- json: Flags.boolean({
21
- char: 'm',
22
- aliases: ['machine'],
23
- description: 'Output prompt configuration as JSON (for AI agents/scripts)',
24
- default: false,
25
- }),
26
- force: Flags.boolean({
27
- char: 'f',
28
- description: 'Skip confirmation',
29
- default: false,
30
- }),
31
- };
32
- getPMOOptions() {
33
- return { promptIfMultiple: false };
34
- }
35
- async execute() {
36
- const { args, flags } = await this.parse(TicketTemplateDelete);
37
- // Check if JSON output mode is active
38
- const jsonMode = shouldOutputJson(flags);
39
- // Helper to handle errors in JSON mode
40
- const handleError = (code, message) => {
41
- if (jsonMode) {
42
- outputErrorAsJson(code, message, createMetadata('ticket template delete', flags));
43
- this.exit(1);
44
- }
45
- this.error(message);
46
- };
47
- // Get template - prompt for selection if not provided
48
- let templateId = args.id;
49
- if (!templateId) {
50
- const templates = await this.storage.listTicketTemplates();
51
- const deletableTemplates = templates.filter(t => !t.isBuiltin);
52
- if (deletableTemplates.length === 0) {
53
- return handleError('NO_TEMPLATES', `No deletable ticket templates found (built-in templates cannot be deleted).`);
54
- }
55
- const { selectedTemplate } = await inquirer.prompt([{
56
- type: 'list',
57
- name: 'selectedTemplate',
58
- message: 'Select a template to delete:',
59
- choices: deletableTemplates.map(t => ({
60
- name: `${t.name}${t.description ? ` - ${t.description}` : ''}`,
61
- value: t.id,
62
- })),
63
- }]);
64
- templateId = selectedTemplate;
65
- }
66
- const template = await this.storage.getTicketTemplate(templateId);
67
- if (!template) {
68
- return handleError('TEMPLATE_NOT_FOUND', `Template "${templateId}" not found.\nRun 'prlt ticket template list' to see available templates.`);
69
- }
70
- if (template.isBuiltin) {
71
- return handleError('CANNOT_DELETE_BUILTIN', 'Cannot delete built-in templates.');
72
- }
73
- if (!flags.force) {
74
- const confirmChoices = [
75
- { id: 'no', name: 'No, cancel' },
76
- { id: 'yes', name: `Yes, delete "${template.name}"` },
77
- ];
78
- const confirm = await this.selectFromList({
79
- message: `Delete template "${template.name}"?`,
80
- items: confirmChoices,
81
- getName: (c) => c.name,
82
- getValue: (c) => c.id,
83
- getCommand: (c) => c.id === 'yes' ? `prlt ticket template delete ${templateId} --force` : '',
84
- jsonMode: jsonMode ? { flags, commandName: 'ticket template delete' } : null,
85
- });
86
- if (confirm !== 'yes') {
87
- this.log(styles.muted('Cancelled.'));
88
- return;
89
- }
90
- }
91
- await this.storage.deleteTicketTemplate(templateId);
92
- this.log(styles.success(`\nDeleted template "${template.name}"`));
93
- }
94
- }
@@ -1,15 +0,0 @@
1
- import { PMOCommand } from '../../../lib/pmo/index.js';
2
- export default class TicketTemplateIndex extends PMOCommand {
3
- static description: string;
4
- static aliases: string[];
5
- static examples: string[];
6
- static flags: {
7
- json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
- project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
- };
10
- protected getPMOOptions(): {
11
- promptIfMultiple: boolean;
12
- };
13
- execute(): Promise<void>;
14
- private selectTemplate;
15
- }
@@ -1,120 +0,0 @@
1
- import { Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
- import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
4
- import { styles } from '../../../lib/styles.js';
5
- import { shouldOutputJson } from '../../../lib/prompt-json.js';
6
- export default class TicketTemplateIndex extends PMOCommand {
7
- static description = 'Interactive menu for ticket template operations';
8
- static aliases = ['ticket:templates'];
9
- static examples = [
10
- '<%= config.bin %> <%= command.id %>',
11
- ];
12
- static flags = {
13
- ...pmoBaseFlags,
14
- json: Flags.boolean({
15
- char: 'm',
16
- aliases: ['machine'],
17
- description: 'Output prompt configuration as JSON (for AI agents/scripts)',
18
- default: false,
19
- }),
20
- };
21
- getPMOOptions() {
22
- return { promptIfMultiple: false };
23
- }
24
- async execute() {
25
- const { flags } = await this.parse(TicketTemplateIndex);
26
- // Check if JSON output mode is active
27
- const jsonMode = shouldOutputJson(flags);
28
- // Define choices once, use for both JSON and interactive modes
29
- const menuChoices = [
30
- { id: 'list', name: 'List available templates', command: 'prlt ticket template list --format json' },
31
- { id: 'create', name: 'Create new template', command: 'prlt ticket template create --json' },
32
- { id: 'apply', name: 'Create ticket from template', command: 'prlt ticket template apply --json' },
33
- { id: 'save', name: 'Save ticket as template', command: 'prlt ticket template save --json' },
34
- { id: 'delete', name: 'Delete template', command: 'prlt ticket template delete --json' },
35
- { id: 'cancel', name: 'Cancel', command: '' },
36
- ];
37
- const message = 'Ticket Templates - What would you like to do?';
38
- const action = await this.selectFromList({
39
- message: '📋 ' + message,
40
- items: menuChoices,
41
- getName: (c) => c.name,
42
- getValue: (c) => c.id,
43
- getCommand: (c) => c.command,
44
- jsonMode: jsonMode ? { flags, commandName: 'ticket template' } : null,
45
- });
46
- if (action === 'cancel' || !action) {
47
- return;
48
- }
49
- // Run the selected subcommand
50
- switch (action) {
51
- case 'list':
52
- await this.config.runCommand('ticket:template:list', []);
53
- break;
54
- case 'create':
55
- await this.config.runCommand('ticket:template:create', []);
56
- break;
57
- case 'apply': {
58
- const templateId = await this.selectTemplate('Select template to use:');
59
- if (templateId) {
60
- await this.config.runCommand('ticket:template:apply', [templateId, '--interactive']);
61
- }
62
- break;
63
- }
64
- case 'save': {
65
- // Prompt for ticket ID and template name
66
- const saveAnswers = await inquirer.prompt([
67
- {
68
- type: 'input',
69
- name: 'ticketId',
70
- message: 'Ticket ID to save as template:',
71
- validate: (input) => input.length > 0 || 'Ticket ID is required',
72
- },
73
- {
74
- type: 'input',
75
- name: 'name',
76
- message: 'Template name:',
77
- validate: (input) => input.length > 0 || 'Name is required',
78
- },
79
- ]);
80
- await this.config.runCommand('ticket:template:save', [saveAnswers.ticketId, saveAnswers.name]);
81
- break;
82
- }
83
- case 'delete': {
84
- const customTemplates = (await this.storage.listTicketTemplates()).filter(t => !t.isBuiltin);
85
- if (customTemplates.length === 0) {
86
- this.log(styles.muted('No custom templates to delete. Built-in templates cannot be deleted.'));
87
- return;
88
- }
89
- const templateId = await this.selectTemplate('Select template to delete:', true);
90
- if (templateId) {
91
- await this.config.runCommand('ticket:template:delete', [templateId]);
92
- }
93
- break;
94
- }
95
- }
96
- }
97
- async selectTemplate(message, customOnly = false) {
98
- let templates = await this.storage.listTicketTemplates();
99
- if (customOnly) {
100
- templates = templates.filter(t => !t.isBuiltin);
101
- }
102
- if (templates.length === 0) {
103
- this.log(styles.muted('No templates found.'));
104
- return null;
105
- }
106
- const templateChoices = templates.map(t => ({
107
- id: t.id,
108
- name: `${t.name} (${t.id})${t.isBuiltin ? '' : ' [custom]'}`,
109
- }));
110
- const selected = await this.selectFromList({
111
- message,
112
- items: templateChoices,
113
- getName: (t) => t.name,
114
- getValue: (t) => t.id,
115
- getCommand: (t) => `prlt ticket template apply ${t.id} --json`,
116
- allowCancel: true,
117
- });
118
- return selected;
119
- }
120
- }
@@ -1,16 +0,0 @@
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
- project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
- };
11
- protected getPMOOptions(): {
12
- promptIfMultiple: boolean;
13
- };
14
- execute(): Promise<void>;
15
- private printTemplate;
16
- }