@proletariat/cli 0.3.24 → 0.3.26

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 (134) hide show
  1. package/dist/commands/action/create.js +3 -3
  2. package/dist/commands/action/index.js +2 -2
  3. package/dist/commands/action/update.js +3 -3
  4. package/dist/commands/agent/auth.js +1 -1
  5. package/dist/commands/agent/cleanup.js +6 -6
  6. package/dist/commands/agent/discover.js +1 -1
  7. package/dist/commands/agent/remove.js +4 -4
  8. package/dist/commands/autocomplete/setup.d.ts +2 -2
  9. package/dist/commands/autocomplete/setup.js +5 -5
  10. package/dist/commands/branch/create.js +31 -30
  11. package/dist/commands/category/create.js +4 -5
  12. package/dist/commands/category/delete.js +2 -3
  13. package/dist/commands/category/rename.js +2 -3
  14. package/dist/commands/claude.d.ts +2 -8
  15. package/dist/commands/claude.js +26 -26
  16. package/dist/commands/commit.d.ts +2 -8
  17. package/dist/commands/commit.js +4 -26
  18. package/dist/commands/config/index.d.ts +2 -10
  19. package/dist/commands/config/index.js +8 -34
  20. package/dist/commands/docker/index.d.ts +2 -2
  21. package/dist/commands/docker/index.js +8 -8
  22. package/dist/commands/epic/activate.js +9 -17
  23. package/dist/commands/epic/archive.js +13 -24
  24. package/dist/commands/epic/create.js +7 -6
  25. package/dist/commands/epic/delete.js +4 -5
  26. package/dist/commands/epic/move.js +28 -47
  27. package/dist/commands/epic/progress.js +10 -14
  28. package/dist/commands/epic/project.js +42 -59
  29. package/dist/commands/epic/reorder.js +25 -30
  30. package/dist/commands/epic/spec.d.ts +1 -0
  31. package/dist/commands/epic/spec.js +39 -40
  32. package/dist/commands/epic/ticket.d.ts +2 -0
  33. package/dist/commands/epic/ticket.js +63 -37
  34. package/dist/commands/feedback/index.d.ts +10 -0
  35. package/dist/commands/feedback/index.js +60 -0
  36. package/dist/commands/feedback/list.d.ts +12 -0
  37. package/dist/commands/feedback/list.js +126 -0
  38. package/dist/commands/feedback/submit.d.ts +16 -0
  39. package/dist/commands/feedback/submit.js +220 -0
  40. package/dist/commands/feedback/view.d.ts +15 -0
  41. package/dist/commands/feedback/view.js +109 -0
  42. package/dist/commands/gh/index.js +4 -0
  43. package/dist/commands/link/index.js +2 -2
  44. package/dist/commands/pmo/init.d.ts +2 -2
  45. package/dist/commands/pmo/init.js +7 -7
  46. package/dist/commands/project/spec.js +6 -6
  47. package/dist/commands/repo/create.d.ts +38 -0
  48. package/dist/commands/repo/create.js +283 -0
  49. package/dist/commands/repo/index.js +7 -0
  50. package/dist/commands/roadmap/add-project.js +9 -22
  51. package/dist/commands/roadmap/create.d.ts +0 -1
  52. package/dist/commands/roadmap/create.js +46 -40
  53. package/dist/commands/roadmap/delete.js +10 -24
  54. package/dist/commands/roadmap/generate.d.ts +1 -0
  55. package/dist/commands/roadmap/generate.js +21 -22
  56. package/dist/commands/roadmap/remove-project.js +14 -34
  57. package/dist/commands/roadmap/reorder.js +19 -26
  58. package/dist/commands/roadmap/update.js +27 -26
  59. package/dist/commands/roadmap/view.js +5 -12
  60. package/dist/commands/session/attach.d.ts +1 -8
  61. package/dist/commands/session/attach.js +93 -59
  62. package/dist/commands/session/health.d.ts +29 -0
  63. package/dist/commands/session/health.js +495 -0
  64. package/dist/commands/session/index.js +4 -0
  65. package/dist/commands/session/list.d.ts +0 -8
  66. package/dist/commands/session/list.js +130 -81
  67. package/dist/commands/spec/create.js +1 -1
  68. package/dist/commands/spec/edit.js +64 -35
  69. package/dist/commands/staff/add.d.ts +2 -2
  70. package/dist/commands/staff/add.js +15 -14
  71. package/dist/commands/staff/index.js +2 -2
  72. package/dist/commands/staff/remove.js +4 -4
  73. package/dist/commands/status/index.js +6 -7
  74. package/dist/commands/support/book.d.ts +10 -0
  75. package/dist/commands/support/book.js +54 -0
  76. package/dist/commands/support/discord.d.ts +10 -0
  77. package/dist/commands/support/discord.js +54 -0
  78. package/dist/commands/support/docs.d.ts +10 -0
  79. package/dist/commands/support/docs.js +54 -0
  80. package/dist/commands/support/index.d.ts +19 -0
  81. package/dist/commands/support/index.js +81 -0
  82. package/dist/commands/support/issues.d.ts +11 -0
  83. package/dist/commands/support/issues.js +77 -0
  84. package/dist/commands/support/logs.d.ts +18 -0
  85. package/dist/commands/support/logs.js +247 -0
  86. package/dist/commands/template/apply.js +10 -11
  87. package/dist/commands/template/create.js +18 -17
  88. package/dist/commands/template/index.d.ts +2 -2
  89. package/dist/commands/template/index.js +6 -6
  90. package/dist/commands/template/save.js +8 -7
  91. package/dist/commands/template/update.js +6 -7
  92. package/dist/commands/terminal/title.d.ts +2 -26
  93. package/dist/commands/terminal/title.js +4 -33
  94. package/dist/commands/theme/index.d.ts +2 -2
  95. package/dist/commands/theme/index.js +19 -18
  96. package/dist/commands/theme/set.d.ts +2 -2
  97. package/dist/commands/theme/set.js +5 -5
  98. package/dist/commands/ticket/create.js +52 -26
  99. package/dist/commands/ticket/delete.js +15 -13
  100. package/dist/commands/ticket/edit.js +59 -20
  101. package/dist/commands/ticket/epic.js +12 -10
  102. package/dist/commands/ticket/move.d.ts +7 -0
  103. package/dist/commands/ticket/move.js +132 -0
  104. package/dist/commands/ticket/project.js +11 -9
  105. package/dist/commands/ticket/reassign.js +23 -19
  106. package/dist/commands/ticket/spec.js +7 -5
  107. package/dist/commands/ticket/update.js +55 -53
  108. package/dist/commands/whoami.js +1 -0
  109. package/dist/commands/work/ready.js +7 -7
  110. package/dist/commands/work/revise.js +13 -11
  111. package/dist/commands/work/spawn.d.ts +1 -0
  112. package/dist/commands/work/spawn.js +225 -64
  113. package/dist/commands/work/start.d.ts +1 -0
  114. package/dist/commands/work/start.js +301 -173
  115. package/dist/hooks/init.js +4 -0
  116. package/dist/lib/execution/runners.js +21 -17
  117. package/dist/lib/execution/session-utils.d.ts +60 -0
  118. package/dist/lib/execution/session-utils.js +162 -0
  119. package/dist/lib/execution/spawner.d.ts +2 -0
  120. package/dist/lib/execution/spawner.js +42 -0
  121. package/dist/lib/flags/resolver.d.ts +2 -2
  122. package/dist/lib/flags/resolver.js +15 -0
  123. package/dist/lib/init/index.js +18 -0
  124. package/dist/lib/multiline-input.d.ts +63 -0
  125. package/dist/lib/multiline-input.js +360 -0
  126. package/dist/lib/pr/index.d.ts +4 -0
  127. package/dist/lib/pr/index.js +32 -14
  128. package/dist/lib/prompt-command.d.ts +3 -0
  129. package/dist/lib/prompt-json.d.ts +77 -6
  130. package/dist/lib/prompt-json.js +46 -0
  131. package/dist/lib/repos/git.d.ts +7 -0
  132. package/dist/lib/repos/git.js +20 -0
  133. package/oclif.manifest.json +2913 -2246
  134. package/package.json +1 -1
@@ -1,5 +1,4 @@
1
1
  import { Flags, Args } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags, autoExportToBoard } from '../../lib/pmo/index.js';
4
3
  import { PRIORITIES, PRIORITY_LABELS } from '../../lib/pmo/types.js';
5
4
  import { styles } from '../../lib/styles.js';
@@ -92,7 +91,7 @@ export default class TemplateApply extends PMOCommand {
92
91
  ]), createMetadata('template apply', flags));
93
92
  return;
94
93
  }
95
- const { selectedType } = await inquirer.prompt([{
94
+ const { selectedType } = await this.prompt([{
96
95
  type: 'list',
97
96
  name: 'selectedType',
98
97
  message: 'What type of template?',
@@ -100,7 +99,7 @@ export default class TemplateApply extends PMOCommand {
100
99
  { name: 'Ticket template', value: 'ticket' },
101
100
  { name: 'Phase template', value: 'phase' },
102
101
  ],
103
- }]);
102
+ }], null);
104
103
  templateType = selectedType;
105
104
  }
106
105
  if (templateType === 'ticket') {
@@ -127,12 +126,12 @@ export default class TemplateApply extends PMOCommand {
127
126
  if (templates.length === 0) {
128
127
  return handleError('NO_TEMPLATES', 'No ticket templates. Create with: prlt template create --type ticket');
129
128
  }
130
- const { selected } = await inquirer.prompt([{
129
+ const { selected } = await this.prompt([{
131
130
  type: 'list',
132
131
  name: 'selected',
133
132
  message: 'Select template:',
134
133
  choices: templates.map(t => ({ name: `${t.name}${t.description ? ` - ${t.description}` : ''}`, value: t.id })),
135
- }]);
134
+ }], null);
136
135
  templateId = selected;
137
136
  }
138
137
  const template = await this.storage.getTicketTemplate(templateId);
@@ -159,10 +158,10 @@ export default class TemplateApply extends PMOCommand {
159
158
  outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('template apply', flags));
160
159
  return;
161
160
  }
162
- const answers = await inquirer.prompt(fields.map(f => ({
161
+ const answers = await this.prompt(fields.map(f => ({
163
162
  ...f,
164
163
  validate: f.name === 'title' ? ((i) => i.length > 0 || 'Required') : undefined,
165
- })));
164
+ })), null);
166
165
  title = answers.title;
167
166
  column = answers.column;
168
167
  priority = answers.priority || undefined;
@@ -215,12 +214,12 @@ export default class TemplateApply extends PMOCommand {
215
214
  if (templates.length === 0) {
216
215
  return handleError('NO_TEMPLATES', 'No phase templates. Create with: prlt template create --type phase');
217
216
  }
218
- const { selected } = await inquirer.prompt([{
217
+ const { selected } = await this.prompt([{
219
218
  type: 'list',
220
219
  name: 'selected',
221
220
  message: 'Select phase template:',
222
221
  choices: templates.map(t => ({ name: `${t.name}${t.description ? ` - ${t.description}` : ''}`, value: t.id })),
223
- }]);
222
+ }], null);
224
223
  templateId = selected;
225
224
  }
226
225
  const template = await this.storage.getPhaseTemplate(templateId);
@@ -238,7 +237,7 @@ export default class TemplateApply extends PMOCommand {
238
237
  return;
239
238
  }
240
239
  this.log(styles.warning(`\nThis will REPLACE ${existingPhases.length} existing phase(s).`));
241
- const { confirm } = await inquirer.prompt([{
240
+ const { confirm } = await this.prompt([{
242
241
  type: 'list',
243
242
  name: 'confirm',
244
243
  message: `Apply template "${template.name}"?`,
@@ -246,7 +245,7 @@ export default class TemplateApply extends PMOCommand {
246
245
  { name: 'No', value: false },
247
246
  { name: 'Yes', value: true },
248
247
  ],
249
- }]);
248
+ }], null);
250
249
  if (!confirm) {
251
250
  this.log(styles.muted('Cancelled'));
252
251
  return;
@@ -1,5 +1,4 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { PRIORITIES, PRIORITY_LABELS, TICKET_CATEGORIES } from '../../lib/pmo/types.js';
5
4
  import { styles } from '../../lib/styles.js';
@@ -82,15 +81,15 @@ export default class TemplateCreate extends PMOCommand {
82
81
  ]), createMetadata('template create', flags));
83
82
  return;
84
83
  }
85
- const { selectedType } = await inquirer.prompt([{
84
+ const { selectedType } = await this.prompt([{
86
85
  type: 'list',
87
86
  name: 'selectedType',
88
87
  message: 'What type of template?',
89
88
  choices: [
90
- { name: 'Ticket template', value: 'ticket' },
91
- { name: 'Phase template', value: 'phase' },
89
+ { name: 'Ticket template', value: 'ticket', command: 'prlt template create --type ticket --json' },
90
+ { name: 'Phase template', value: 'phase', command: 'prlt template create --type phase --json' },
92
91
  ],
93
- }]);
92
+ }], jsonMode ? { flags, commandName: 'template create' } : null);
94
93
  templateType = selectedType;
95
94
  }
96
95
  if (templateType === 'ticket') {
@@ -129,12 +128,13 @@ export default class TemplateCreate extends PMOCommand {
129
128
  outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('template create', flags));
130
129
  return;
131
130
  }
132
- const { templateName } = await inquirer.prompt([{
131
+ const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'template create' } : null;
132
+ const { templateName } = await this.prompt([{
133
133
  type: 'input',
134
134
  name: 'templateName',
135
135
  message: 'Template name:',
136
136
  validate: (input) => input.trim() ? true : 'Name required',
137
- }]);
137
+ }], jsonModeConfig);
138
138
  name = templateName;
139
139
  }
140
140
  // Get optional values
@@ -148,13 +148,13 @@ export default class TemplateCreate extends PMOCommand {
148
148
  let descriptionTemplate = flags['description-template'];
149
149
  // Interactive prompts for missing optional values
150
150
  if (!jsonMode && description === undefined) {
151
- const { desc } = await inquirer.prompt([{
151
+ const { desc } = await this.prompt([{
152
152
  type: 'input', name: 'desc', message: 'Description (optional):',
153
- }]);
153
+ }], null);
154
154
  description = desc || undefined;
155
155
  }
156
156
  if (!jsonMode && priority === undefined) {
157
- const { p } = await inquirer.prompt([{
157
+ const { p } = await this.prompt([{
158
158
  type: 'list',
159
159
  name: 'p',
160
160
  message: 'Default priority:',
@@ -162,11 +162,11 @@ export default class TemplateCreate extends PMOCommand {
162
162
  { name: 'None', value: '' },
163
163
  ...PRIORITIES.map(pr => ({ name: PRIORITY_LABELS[pr], value: pr })),
164
164
  ],
165
- }]);
165
+ }], null);
166
166
  priority = p || undefined;
167
167
  }
168
168
  if (!jsonMode && category === undefined) {
169
- const { c } = await inquirer.prompt([{
169
+ const { c } = await this.prompt([{
170
170
  type: 'list',
171
171
  name: 'c',
172
172
  message: 'Default category:',
@@ -174,7 +174,7 @@ export default class TemplateCreate extends PMOCommand {
174
174
  { name: 'None', value: '' },
175
175
  ...TICKET_CATEGORIES.map(cat => ({ name: cat, value: cat })),
176
176
  ],
177
- }]);
177
+ }], null);
178
178
  category = c || undefined;
179
179
  }
180
180
  // Build description template with ACs
@@ -207,19 +207,20 @@ export default class TemplateCreate extends PMOCommand {
207
207
  outputErrorAsJson('NAME_REQUIRED', 'Name required: prlt template create --type phase "Name"', createMetadata('template create', flags));
208
208
  return;
209
209
  }
210
- const { templateName } = await inquirer.prompt([{
210
+ const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'template create' } : null;
211
+ const { templateName } = await this.prompt([{
211
212
  type: 'input',
212
213
  name: 'templateName',
213
214
  message: 'Template name:',
214
215
  validate: (input) => input.trim() ? true : 'Name required',
215
- }]);
216
+ }], jsonModeConfig);
216
217
  name = templateName;
217
218
  }
218
219
  let description = flags.description;
219
220
  if (!jsonMode && description === undefined) {
220
- const { desc } = await inquirer.prompt([{
221
+ const { desc } = await this.prompt([{
221
222
  type: 'input', name: 'desc', message: 'Description (optional):',
222
- }]);
223
+ }], null);
223
224
  description = desc || undefined;
224
225
  }
225
226
  const template = await this.storage.savePhaseTemplate(name, description);
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class Template extends Command {
1
+ import { PromptCommand } from '../../lib/prompt-command.js';
2
+ export default class Template extends PromptCommand {
3
3
  static description: string;
4
4
  static aliases: string[];
5
5
  static examples: string[];
@@ -1,8 +1,8 @@
1
- import { Command, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
1
+ import { Flags } from '@oclif/core';
3
2
  import { styles } from '../../lib/styles.js';
4
3
  import { shouldOutputJson, outputPromptAsJson, buildPromptConfig, createMetadata } from '../../lib/prompt-json.js';
5
- export default class Template extends Command {
4
+ import { PromptCommand } from '../../lib/prompt-command.js';
5
+ export default class Template extends PromptCommand {
6
6
  static description = 'Manage templates (ticket and phase)';
7
7
  static aliases = ['templates'];
8
8
  static examples = [
@@ -37,12 +37,12 @@ export default class Template extends Command {
37
37
  }
38
38
  this.log(`\n${styles.emphasis('Templates')}`);
39
39
  this.log(styles.muted('Manage ticket and phase templates\n'));
40
- const { action } = await inquirer.prompt([{
40
+ const { action } = await this.prompt([{
41
41
  type: 'list',
42
42
  name: 'action',
43
43
  message: 'What would you like to do?',
44
- choices: menuChoices.map(c => ({ name: c.name, value: c.value })),
45
- }]);
44
+ choices: menuChoices.map(c => ({ name: c.name, value: c.value, command: c.command })),
45
+ }], null);
46
46
  if (action === 'cancel')
47
47
  return;
48
48
  switch (action) {
@@ -1,5 +1,4 @@
1
1
  import { Flags, Args } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputPromptAsJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
@@ -58,12 +57,13 @@ export default class TemplateSave extends PMOCommand {
58
57
  outputPromptAsJson(buildPromptConfig('list', 'ticket', 'Select ticket:', choices), createMetadata('template save', flags));
59
58
  return;
60
59
  }
61
- const { selected } = await inquirer.prompt([{
60
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'template save' } : null;
61
+ const { selected } = await this.prompt([{
62
62
  type: 'list',
63
63
  name: 'selected',
64
64
  message: 'Select ticket:',
65
- choices: tickets.slice(0, 20).map(t => ({ name: `${t.id} - ${t.title}`, value: t.id })),
66
- }]);
65
+ choices: tickets.slice(0, 20).map(t => ({ name: `${t.id} - ${t.title}`, value: t.id, command: `prlt template save ${t.id} --json` })),
66
+ }], jsonModeConfig);
67
67
  ticketId = selected;
68
68
  }
69
69
  const ticket = await this.storage.getTicket(ticketId);
@@ -77,19 +77,20 @@ export default class TemplateSave extends PMOCommand {
77
77
  outputPromptAsJson(buildPromptConfig('input', 'name', 'Template name:', undefined, ticket.category || ticket.title.split(' ')[0]), createMetadata('template save', flags));
78
78
  return;
79
79
  }
80
- const { name } = await inquirer.prompt([{
80
+ const jsonModeConfig2 = jsonMode ? { flags, commandName: 'template save' } : null;
81
+ const { name } = await this.prompt([{
81
82
  type: 'input',
82
83
  name: 'name',
83
84
  message: 'Template name:',
84
85
  default: ticket.category || ticket.title.split(' ')[0],
85
86
  validate: (i) => i.length > 0 || 'Required',
86
- }]);
87
+ }], jsonModeConfig2);
87
88
  templateName = name;
88
89
  }
89
90
  // Get description
90
91
  let description = flags.description;
91
92
  if (description === undefined && !jsonMode) {
92
- const { desc } = await inquirer.prompt([{ type: 'input', name: 'desc', message: 'Description (optional):' }]);
93
+ const { desc } = await this.prompt([{ type: 'input', name: 'desc', message: 'Description (optional):' }], null);
93
94
  description = desc || undefined;
94
95
  }
95
96
  const template = await this.storage.createTicketTemplateFromTicket(ticketId, templateName, description);
@@ -1,5 +1,4 @@
1
1
  import { Flags, Args } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { shouldOutputJson, outputPromptAsJson, outputSuccessAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
@@ -57,26 +56,26 @@ export default class TemplateUpdate extends PMOCommand {
57
56
  outputPromptAsJson(buildPromptConfig('list', 'id', 'Select template:', choices), createMetadata('template update', flags));
58
57
  return;
59
58
  }
60
- const { selected } = await inquirer.prompt([{
59
+ const { selected } = await this.prompt([{
61
60
  type: 'list',
62
61
  name: 'selected',
63
62
  message: 'Select template:',
64
63
  choices: editable.map(t => ({ name: `${t.name}${t.description ? ` - ${t.description}` : ''}`, value: t.id })),
65
- }]);
64
+ }], null);
66
65
  templateId = selected;
67
66
  }
68
67
  // Get updates
69
68
  let newName = flags.name;
70
69
  let newDescription = flags.description;
71
70
  if (!newName && newDescription === undefined && !jsonMode) {
72
- const { updateName } = await inquirer.prompt([{
71
+ const { updateName } = await this.prompt([{
73
72
  type: 'input', name: 'updateName', message: 'New name (leave empty to keep):',
74
- }]);
73
+ }], null);
75
74
  if (updateName)
76
75
  newName = updateName;
77
- const { updateDesc } = await inquirer.prompt([{
76
+ const { updateDesc } = await this.prompt([{
78
77
  type: 'input', name: 'updateDesc', message: 'New description (leave empty to keep):',
79
- }]);
78
+ }], null);
80
79
  if (updateDesc)
81
80
  newDescription = updateDesc;
82
81
  if (!newName && !newDescription) {
@@ -1,6 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- import { type JsonFlags } from '../../lib/prompt-json.js';
3
- export default class TerminalTitle extends Command {
1
+ import { PromptCommand } from '../../lib/prompt-command.js';
2
+ export default class TerminalTitle extends PromptCommand {
4
3
  static description: string;
5
4
  static examples: string[];
6
5
  static args: {
@@ -10,28 +9,5 @@ export default class TerminalTitle extends Command {
10
9
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
10
  reset: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
11
  };
13
- /**
14
- * Prompt wrapper - drop-in replacement for inquirer.prompt with JSON mode support.
15
- * Matches the pattern from PMOCommand.prompt().
16
- *
17
- * In JSON mode: outputs prompt config as JSON and exits
18
- * In interactive mode: shows normal inquirer prompt
19
- */
20
- protected prompt<T extends Record<string, unknown>>(questions: Array<{
21
- type: string;
22
- name: string;
23
- message: string;
24
- choices?: Array<string | {
25
- name: string;
26
- value: unknown;
27
- disabled?: boolean | string;
28
- command?: string;
29
- } | unknown>;
30
- default?: unknown;
31
- validate?: (input: unknown) => boolean | string;
32
- }>, jsonModeConfig?: {
33
- flags: JsonFlags & Record<string, unknown>;
34
- commandName: string;
35
- } | null): Promise<T>;
36
12
  run(): Promise<void>;
37
13
  }
@@ -1,10 +1,10 @@
1
- import { Args, Command, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
1
+ import { Args, Flags } from '@oclif/core';
3
2
  import { setTerminalTitle, resetTerminalTitle } from '../../lib/terminal.js';
4
3
  import { styles } from '../../lib/styles.js';
5
4
  import { machineOutputFlags } from '../../lib/pmo/base-command.js';
6
- import { isAgentMode, outputPromptAsJson, createMetadata, normalizeChoices, } from '../../lib/prompt-json.js';
7
- export default class TerminalTitle extends Command {
5
+ import { isAgentMode } from '../../lib/prompt-json.js';
6
+ import { PromptCommand } from '../../lib/prompt-command.js';
7
+ export default class TerminalTitle extends PromptCommand {
8
8
  static description = 'Set the terminal tab/window title';
9
9
  static examples = [
10
10
  '<%= config.bin %> <%= command.id %> "My Custom Name"',
@@ -26,35 +26,6 @@ export default class TerminalTitle extends Command {
26
26
  }),
27
27
  ...machineOutputFlags,
28
28
  };
29
- /**
30
- * Prompt wrapper - drop-in replacement for inquirer.prompt with JSON mode support.
31
- * Matches the pattern from PMOCommand.prompt().
32
- *
33
- * In JSON mode: outputs prompt config as JSON and exits
34
- * In interactive mode: shows normal inquirer prompt
35
- */
36
- async prompt(questions, jsonModeConfig) {
37
- // Check for JSON/agent mode
38
- if (jsonModeConfig && isAgentMode(jsonModeConfig.flags)) {
39
- const firstQuestion = questions[0];
40
- if (firstQuestion) {
41
- const choices = firstQuestion.choices
42
- ? normalizeChoices(firstQuestion.choices)
43
- : undefined;
44
- outputPromptAsJson({
45
- type: firstQuestion.type,
46
- name: firstQuestion.name,
47
- message: firstQuestion.message,
48
- choices,
49
- default: firstQuestion.default,
50
- }, createMetadata(jsonModeConfig.commandName, jsonModeConfig.flags));
51
- // outputPromptAsJson calls process.exit, never returns
52
- }
53
- return {};
54
- }
55
- // Interactive mode: just call inquirer
56
- return inquirer.prompt(questions);
57
- }
58
29
  async run() {
59
30
  const { args, flags } = await this.parse(TerminalTitle);
60
31
  // Handle reset flag
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class Theme extends Command {
1
+ import { PromptCommand } from '../../lib/prompt-command.js';
2
+ export default class Theme extends PromptCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
@@ -1,11 +1,12 @@
1
- import { Command, Flags } from '@oclif/core';
1
+ import { Flags } from '@oclif/core';
2
2
  import inquirer from 'inquirer';
3
3
  import chalk from 'chalk';
4
+ import { PromptCommand } from '../../lib/prompt-command.js';
4
5
  import { getWorkspaceInfo } from '../../lib/agents/commands.js';
5
6
  import { ensureBuiltinThemes } from '../../lib/themes.js';
6
7
  import { getThemes, getAvailableThemeNames } from '../../lib/database/index.js';
7
8
  import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
8
- export default class Theme extends Command {
9
+ export default class Theme extends PromptCommand {
9
10
  static description = 'Manage agent naming themes';
10
11
  static examples = [
11
12
  '<%= config.bin %> <%= command.id %> list',
@@ -44,7 +45,7 @@ export default class Theme extends Command {
44
45
  }
45
46
  this.log(chalk.bold('\nAgent Themes'));
46
47
  this.log(chalk.dim('Optional themed name pools for your agents.\n'));
47
- const { action } = await inquirer.prompt([{
48
+ const { action } = await this.prompt([{
48
49
  type: 'list',
49
50
  name: 'action',
50
51
  message,
@@ -53,7 +54,7 @@ export default class Theme extends Command {
53
54
  new inquirer.Separator(),
54
55
  { name: menuChoices[3].name, value: menuChoices[3].id }
55
56
  ]
56
- }]);
57
+ }], null);
57
58
  if (action === 'cancel') {
58
59
  this.log(chalk.dim('Cancelled.'));
59
60
  return;
@@ -68,7 +69,7 @@ export default class Theme extends Command {
68
69
  }
69
70
  case 'create': {
70
71
  // Prompt for theme name interactively
71
- const { themeName } = await inquirer.prompt([{
72
+ const { themeName } = await this.prompt([{
72
73
  type: 'input',
73
74
  name: 'themeName',
74
75
  message: 'Theme name:',
@@ -77,7 +78,7 @@ export default class Theme extends Command {
77
78
  return 'Theme name is required';
78
79
  return true;
79
80
  }
80
- }]);
81
+ }], null);
81
82
  // Normalize: lowercase, spaces to dashes
82
83
  const normalized = themeName.trim().toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
83
84
  if (themeName.trim() !== normalized) {
@@ -87,7 +88,7 @@ export default class Theme extends Command {
87
88
  const cmd = new CreateCommand([normalized], this.config);
88
89
  await cmd.run();
89
90
  // Prompt to add names immediately
90
- const { addNamesNow } = await inquirer.prompt([{
91
+ const { addNamesNow } = await this.prompt([{
91
92
  type: 'list',
92
93
  name: 'addNamesNow',
93
94
  message: 'Add names to this theme now?',
@@ -95,14 +96,14 @@ export default class Theme extends Command {
95
96
  { name: 'Yes', value: true },
96
97
  { name: 'No', value: false },
97
98
  ],
98
- }]);
99
+ }], null);
99
100
  if (addNamesNow) {
100
- const { names } = await inquirer.prompt([{
101
+ const { names } = await this.prompt([{
101
102
  type: 'input',
102
103
  name: 'names',
103
104
  message: 'Enter names (space-separated):',
104
105
  validate: (input) => input.trim() ? true : 'At least one name is required'
105
- }]);
106
+ }], null);
106
107
  const args = [normalized, ...names.trim().split(/\s+/)];
107
108
  const { default: AddNamesCommand } = await import('./add-names.js');
108
109
  const addCmd = new AddNamesCommand(args, this.config);
@@ -131,15 +132,15 @@ export default class Theme extends Command {
131
132
  // Add option to create new theme (using type assertion for mixed array)
132
133
  themeChoices.push(new inquirer.Separator());
133
134
  themeChoices.push({ name: chalk.green('+ Create new theme'), value: '__create_new__' });
134
- const { selectedTheme } = await inquirer.prompt([{
135
+ const { selectedTheme } = await this.prompt([{
135
136
  type: 'list',
136
137
  name: 'selectedTheme',
137
138
  message: 'Select theme to add names to:',
138
139
  choices: themeChoices
139
- }]);
140
+ }], null);
140
141
  // If they want to create a new theme first
141
142
  if (selectedTheme === '__create_new__') {
142
- const { themeName } = await inquirer.prompt([{
143
+ const { themeName } = await this.prompt([{
143
144
  type: 'input',
144
145
  name: 'themeName',
145
146
  message: 'Theme name:',
@@ -148,7 +149,7 @@ export default class Theme extends Command {
148
149
  return 'Theme name is required';
149
150
  return true;
150
151
  }
151
- }]);
152
+ }], null);
152
153
  // Normalize: lowercase, spaces to dashes
153
154
  const normalizedTheme = themeName.trim().toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
154
155
  if (themeName.trim() !== normalizedTheme) {
@@ -158,12 +159,12 @@ export default class Theme extends Command {
158
159
  const createCmd = new CreateCommand([normalizedTheme], this.config);
159
160
  await createCmd.run();
160
161
  // Now prompt for names to add to the new theme
161
- const { names } = await inquirer.prompt([{
162
+ const { names } = await this.prompt([{
162
163
  type: 'input',
163
164
  name: 'names',
164
165
  message: 'Names to add (space-separated):',
165
166
  validate: (input) => input.trim() ? true : 'At least one name is required'
166
- }]);
167
+ }], null);
167
168
  const args = [normalizedTheme, ...names.trim().split(/\s+/)];
168
169
  const { default: AddNamesCommand } = await import('./add-names.js');
169
170
  const cmd = new AddNamesCommand(args, this.config);
@@ -171,12 +172,12 @@ export default class Theme extends Command {
171
172
  }
172
173
  else {
173
174
  // Prompt for names to add
174
- const { names } = await inquirer.prompt([{
175
+ const { names } = await this.prompt([{
175
176
  type: 'input',
176
177
  name: 'names',
177
178
  message: 'Names to add (space-separated):',
178
179
  validate: (input) => input.trim() ? true : 'At least one name is required'
179
- }]);
180
+ }], null);
180
181
  const args = [selectedTheme, ...names.trim().split(/\s+/)];
181
182
  const { default: AddNamesCommand } = await import('./add-names.js');
182
183
  const cmd = new AddNamesCommand(args, this.config);
@@ -1,5 +1,5 @@
1
- import { Command } from '@oclif/core';
2
- export default class ThemeSet extends Command {
1
+ import { PromptCommand } from '../../lib/prompt-command.js';
2
+ export default class ThemeSet extends PromptCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {
@@ -1,11 +1,11 @@
1
- import { Command, Args, Flags } from '@oclif/core';
1
+ import { Args, Flags } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
- import inquirer from 'inquirer';
3
+ import { PromptCommand } from '../../lib/prompt-command.js';
4
4
  import { getWorkspaceInfo } from '../../lib/agents/commands.js';
5
5
  import { ensureBuiltinThemes } from '../../lib/themes.js';
6
6
  import { getThemes, getAvailableThemeNames, setActiveTheme, getActiveTheme } from '../../lib/database/index.js';
7
7
  import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
8
- export default class ThemeSet extends Command {
8
+ export default class ThemeSet extends PromptCommand {
9
9
  static description = 'Set the active theme for this workspace';
10
10
  static examples = [
11
11
  '<%= config.bin %> <%= command.id %> billionaires',
@@ -58,12 +58,12 @@ export default class ThemeSet extends Command {
58
58
  value: t.id
59
59
  };
60
60
  });
61
- const { selected } = await inquirer.prompt([{
61
+ const { selected } = await this.prompt([{
62
62
  type: 'list',
63
63
  name: 'selected',
64
64
  message: 'Select theme for this workspace:',
65
65
  choices
66
- }]);
66
+ }], null);
67
67
  themeId = selected;
68
68
  }
69
69
  setActiveTheme(workspaceInfo.path, themeId);