@proletariat/cli 0.3.24 → 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 (75) hide show
  1. package/dist/commands/action/create.js +3 -3
  2. package/dist/commands/action/update.js +3 -3
  3. package/dist/commands/epic/activate.js +9 -17
  4. package/dist/commands/epic/archive.js +13 -24
  5. package/dist/commands/epic/create.js +7 -6
  6. package/dist/commands/epic/move.js +28 -47
  7. package/dist/commands/epic/progress.js +10 -14
  8. package/dist/commands/epic/project.js +42 -59
  9. package/dist/commands/epic/reorder.js +25 -30
  10. package/dist/commands/epic/spec.d.ts +1 -0
  11. package/dist/commands/epic/spec.js +39 -40
  12. package/dist/commands/epic/ticket.d.ts +2 -0
  13. package/dist/commands/epic/ticket.js +63 -37
  14. package/dist/commands/feedback/index.d.ts +10 -0
  15. package/dist/commands/feedback/index.js +60 -0
  16. package/dist/commands/feedback/list.d.ts +12 -0
  17. package/dist/commands/feedback/list.js +126 -0
  18. package/dist/commands/feedback/submit.d.ts +16 -0
  19. package/dist/commands/feedback/submit.js +220 -0
  20. package/dist/commands/feedback/view.d.ts +15 -0
  21. package/dist/commands/feedback/view.js +109 -0
  22. package/dist/commands/gh/index.js +4 -0
  23. package/dist/commands/repo/create.d.ts +38 -0
  24. package/dist/commands/repo/create.js +283 -0
  25. package/dist/commands/repo/index.js +7 -0
  26. package/dist/commands/roadmap/add-project.js +9 -22
  27. package/dist/commands/roadmap/create.d.ts +0 -1
  28. package/dist/commands/roadmap/create.js +46 -40
  29. package/dist/commands/roadmap/delete.js +10 -24
  30. package/dist/commands/roadmap/generate.d.ts +1 -0
  31. package/dist/commands/roadmap/generate.js +21 -22
  32. package/dist/commands/roadmap/remove-project.js +14 -34
  33. package/dist/commands/roadmap/reorder.js +19 -26
  34. package/dist/commands/roadmap/update.js +27 -26
  35. package/dist/commands/roadmap/view.js +5 -12
  36. package/dist/commands/session/attach.d.ts +1 -8
  37. package/dist/commands/session/attach.js +93 -59
  38. package/dist/commands/session/list.d.ts +0 -8
  39. package/dist/commands/session/list.js +130 -81
  40. package/dist/commands/spec/create.js +1 -1
  41. package/dist/commands/spec/edit.js +63 -33
  42. package/dist/commands/support/book.d.ts +10 -0
  43. package/dist/commands/support/book.js +54 -0
  44. package/dist/commands/support/discord.d.ts +10 -0
  45. package/dist/commands/support/discord.js +54 -0
  46. package/dist/commands/support/docs.d.ts +10 -0
  47. package/dist/commands/support/docs.js +54 -0
  48. package/dist/commands/support/index.d.ts +19 -0
  49. package/dist/commands/support/index.js +81 -0
  50. package/dist/commands/support/issues.d.ts +11 -0
  51. package/dist/commands/support/issues.js +77 -0
  52. package/dist/commands/support/logs.d.ts +18 -0
  53. package/dist/commands/support/logs.js +247 -0
  54. package/dist/commands/ticket/create.js +21 -13
  55. package/dist/commands/ticket/edit.js +44 -13
  56. package/dist/commands/ticket/move.d.ts +7 -0
  57. package/dist/commands/ticket/move.js +132 -0
  58. package/dist/commands/work/spawn.d.ts +1 -0
  59. package/dist/commands/work/spawn.js +71 -7
  60. package/dist/commands/work/start.js +6 -0
  61. package/dist/lib/execution/runners.js +21 -17
  62. package/dist/lib/execution/session-utils.d.ts +60 -0
  63. package/dist/lib/execution/session-utils.js +162 -0
  64. package/dist/lib/execution/spawner.d.ts +2 -0
  65. package/dist/lib/execution/spawner.js +42 -0
  66. package/dist/lib/flags/resolver.d.ts +2 -2
  67. package/dist/lib/flags/resolver.js +15 -0
  68. package/dist/lib/init/index.js +18 -0
  69. package/dist/lib/multiline-input.d.ts +63 -0
  70. package/dist/lib/multiline-input.js +360 -0
  71. package/dist/lib/prompt-json.d.ts +5 -5
  72. package/dist/lib/repos/git.d.ts +7 -0
  73. package/dist/lib/repos/git.js +20 -0
  74. package/oclif.manifest.json +2206 -1607
  75. package/package.json +1 -1
@@ -85,11 +85,11 @@ export default class ActionCreate extends PMOCommand {
85
85
  requiredFields: ['name (as first argument)', '--prompt'],
86
86
  },
87
87
  });
88
- // Prompt input (editor type in interactive, but input for JSON mode context)
88
+ // Prompt input (multiline for inline text input)
89
89
  resolver.addPrompt({
90
90
  flagName: 'prompt',
91
- type: 'editor',
92
- message: 'Prompt (opens editor):',
91
+ type: 'multiline',
92
+ message: 'Prompt (agent instructions):',
93
93
  default: prompt || 'Enter the prompt that will be sent to the agent...',
94
94
  when: (ctx) => !ctx.flags.prompt && ctx.flags.name !== undefined,
95
95
  validate: (value) => value.trim() ? true : 'Prompt is required',
@@ -113,11 +113,11 @@ export default class ActionUpdate extends PMOCommand {
113
113
  currentValue: existingAction.description || '',
114
114
  },
115
115
  });
116
- // Prompt input (editor)
116
+ // Prompt input (multiline)
117
117
  resolver.addPrompt({
118
118
  flagName: 'prompt',
119
- type: 'editor',
120
- message: 'Prompt (opens editor):',
119
+ type: 'multiline',
120
+ message: 'Prompt (agent instructions):',
121
121
  default: existingAction.prompt,
122
122
  when: (ctx) => ctx.flags.name !== undefined && ctx.flags.description !== undefined,
123
123
  context: {
@@ -1,9 +1,8 @@
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 { styles } from '../../lib/styles.js';
5
4
  import { moveEpicFile, getRelativeEpicPath } from '../../lib/pmo/epic-files.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
5
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
7
6
  export default class EpicActivate extends PMOCommand {
8
7
  static description = 'Activate a draft or archived epic';
9
8
  static examples = [
@@ -76,26 +75,19 @@ export default class EpicActivate extends PMOCommand {
76
75
  if (epic.status === 'complete') {
77
76
  const tickets = await this.storage.getTicketsForEpic(projectId, epicId);
78
77
  const doneTickets = tickets.filter((t) => t.status === 'done').length;
79
- // In JSON mode, output confirmation prompt
80
- if (jsonMode) {
81
- const confirmChoices = [
82
- { name: 'No', value: 'false' },
83
- { name: 'Yes', value: 'true' },
84
- ];
85
- outputPromptAsJson(buildPromptConfig('list', 'confirm', `This epic was previously completed (${doneTickets}/${tickets.length} tickets done). Reactivate this epic?`, confirmChoices), createMetadata('epic activate', flags));
86
- return;
78
+ if (!jsonMode) {
79
+ this.log(styles.warning(`\n⚠️ This epic was previously completed (${doneTickets}/${tickets.length} tickets done)`));
87
80
  }
88
- this.log(styles.warning(`\n⚠️ This epic was previously completed (${doneTickets}/${tickets.length} tickets done)`));
89
- const { confirm } = await inquirer.prompt([{
81
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic activate' } : null;
82
+ const { confirm } = await this.prompt([{
90
83
  type: 'list',
91
84
  name: 'confirm',
92
- message: 'Reactivate this epic?',
85
+ message: `This epic was previously completed (${doneTickets}/${tickets.length} tickets done). Reactivate this epic?`,
93
86
  choices: [
94
- { name: 'No', value: false },
95
- { name: 'Yes', value: true },
87
+ { name: 'No', value: false, command: '' },
88
+ { name: 'Yes', value: true, command: `prlt epic activate ${epicId} --json` },
96
89
  ],
97
- default: false,
98
- }]);
90
+ }], jsonModeConfig);
99
91
  if (!confirm) {
100
92
  this.log(styles.muted('Cancelled.'));
101
93
  return;
@@ -1,9 +1,8 @@
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 { styles } from '../../lib/styles.js';
5
4
  import { moveEpicFile, getRelativeEpicPath } from '../../lib/pmo/epic-files.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
5
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
7
6
  export default class EpicArchive extends PMOCommand {
8
7
  static description = 'Archive a completed epic';
9
8
  static examples = [
@@ -64,19 +63,16 @@ export default class EpicArchive extends PMOCommand {
64
63
  return {
65
64
  name: `${e.id} ${e.title} (${e.status}) [${done}/${tickets.length} tickets complete]${complete ? ' ✅' : ''}`,
66
65
  value: e.id,
66
+ command: `prlt epic archive ${e.id} --json`,
67
67
  };
68
68
  }));
69
- // In JSON mode, output epic selection prompt
70
- if (jsonMode) {
71
- outputPromptAsJson(buildPromptConfig('list', 'id', 'Select epic to archive:', choices), createMetadata('epic archive', flags));
72
- return;
73
- }
74
- const { selected } = await inquirer.prompt([{
69
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic archive' } : null;
70
+ const { selected } = await this.prompt([{
75
71
  type: 'list',
76
72
  name: 'selected',
77
73
  message: 'Select epic to archive:',
78
74
  choices,
79
- }]);
75
+ }], jsonModeConfig);
80
76
  epicId = selected;
81
77
  }
82
78
  const epic = await this.storage.getEpic(epicId);
@@ -92,26 +88,19 @@ export default class EpicArchive extends PMOCommand {
92
88
  const doneTickets = tickets.filter((t) => t.status === 'done').length;
93
89
  const allComplete = doneTickets === tickets.length;
94
90
  if (!allComplete && !flags.force) {
95
- // In JSON mode, output confirmation prompt
96
- if (jsonMode) {
97
- const confirmChoices = [
98
- { name: 'No', value: 'false' },
99
- { name: 'Yes', value: 'true' },
100
- ];
101
- outputPromptAsJson(buildPromptConfig('list', 'confirm', `Not all tickets are complete (${doneTickets}/${tickets.length} done). Continue archiving anyway?`, confirmChoices), createMetadata('epic archive', flags));
102
- return;
91
+ if (!jsonMode) {
92
+ this.log(styles.warning(`\n⚠️ Not all tickets are complete (${doneTickets}/${tickets.length} done)`));
103
93
  }
104
- this.log(styles.warning(`\n⚠️ Not all tickets are complete (${doneTickets}/${tickets.length} done)`));
105
- const { confirm } = await inquirer.prompt([{
94
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic archive' } : null;
95
+ const { confirm } = await this.prompt([{
106
96
  type: 'list',
107
97
  name: 'confirm',
108
- message: 'Continue archiving anyway?',
98
+ message: `Not all tickets are complete (${doneTickets}/${tickets.length} done). Continue archiving anyway?`,
109
99
  choices: [
110
- { name: 'No', value: false },
111
- { name: 'Yes', value: true },
100
+ { name: 'No', value: false, command: '' },
101
+ { name: 'Yes', value: true, command: `prlt epic archive ${epicId} --force --json` },
112
102
  ],
113
- default: false,
114
- }]);
103
+ }], jsonModeConfig);
115
104
  if (!confirm) {
116
105
  this.log(styles.muted('Cancelled.'));
117
106
  return;
@@ -1,5 +1,4 @@
1
1
  import { Flags } 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 { createEpicFile, getRelativeEpicPath } from '../../lib/pmo/epic-files.js';
@@ -81,7 +80,7 @@ export default class EpicCreate extends PMOCommand {
81
80
  if (jsonMode) {
82
81
  outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('epic create', flags));
83
82
  }
84
- epicData = await this.promptEpicData(fields, specChoices.length > 1);
83
+ epicData = await this.promptEpicData(fields, specChoices.length > 1, jsonMode ? { flags, commandName: 'epic create' } : null);
85
84
  }
86
85
  else {
87
86
  epicData = {
@@ -157,15 +156,17 @@ export default class EpicCreate extends PMOCommand {
157
156
  this.log(styles.muted(` prlt ticket create --epic ${epic.id} "Design auth flow"`));
158
157
  this.log(styles.muted(` 3. View progress: prlt epic progress ${epic.id}`));
159
158
  }
160
- async promptEpicData(fields, hasSpecs) {
159
+ async promptEpicData(fields, hasSpecs, jsonModeConfig) {
161
160
  // Build inquirer prompts from fields, adding validators and conditionals
162
- const answers = await inquirer.prompt(fields.map(field => ({
161
+ const promptFields = fields
162
+ .filter(field => field.name !== 'specId' || hasSpecs)
163
+ .map(field => ({
163
164
  ...field,
164
165
  validate: field.name === 'title'
165
166
  ? ((input) => input.trim() ? true : 'Title cannot be empty')
166
167
  : undefined,
167
- when: field.name === 'specId' ? () => hasSpecs : undefined,
168
- })));
168
+ }));
169
+ const answers = await this.prompt(promptFields, jsonModeConfig);
169
170
  return {
170
171
  title: answers.title,
171
172
  status: answers.status,
@@ -1,9 +1,8 @@
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 { styles } from '../../lib/styles.js';
5
4
  import { moveEpicFile, getRelativeEpicPath } from '../../lib/pmo/epic-files.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
5
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
7
6
  const STATUS_CHOICES = [
8
7
  { name: 'active (currently working on)', value: 'active' },
9
8
  { name: 'draft (planning phase)', value: 'draft' },
@@ -75,19 +74,16 @@ export default class EpicMove extends PMOCommand {
75
74
  return {
76
75
  name: `${e.id} ${e.title} (${e.status}) [${done}/${tickets.length} complete]`,
77
76
  value: e.id,
77
+ command: `prlt epic move ${e.id} --json`,
78
78
  };
79
79
  }));
80
- // In JSON mode, output epic selection prompt
81
- if (jsonMode) {
82
- outputPromptAsJson(buildPromptConfig('list', 'id', 'Select epic to move:', choices), createMetadata('epic move', flags));
83
- return;
84
- }
85
- const { selected } = await inquirer.prompt([{
80
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic move' } : null;
81
+ const { selected } = await this.prompt([{
86
82
  type: 'list',
87
83
  name: 'selected',
88
84
  message: 'Select epic to move:',
89
85
  choices,
90
- }]);
86
+ }], jsonModeConfig);
91
87
  epicId = selected;
92
88
  }
93
89
  const epic = await this.storage.getEpic(epicId);
@@ -96,18 +92,17 @@ export default class EpicMove extends PMOCommand {
96
92
  }
97
93
  // If no status provided, prompt for selection
98
94
  if (!targetStatus) {
99
- const statusChoices = STATUS_CHOICES.filter(c => c.value !== epic.status);
100
- // In JSON mode, output status selection prompt
101
- if (jsonMode) {
102
- outputPromptAsJson(buildPromptConfig('list', 'status', 'Move to which status?', statusChoices), createMetadata('epic move', flags));
103
- return;
104
- }
105
- const { selected } = await inquirer.prompt([{
95
+ const statusChoices = STATUS_CHOICES.filter(c => c.value !== epic.status).map(c => ({
96
+ ...c,
97
+ command: `prlt epic move ${epicId} ${c.value} --json`,
98
+ }));
99
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic move' } : null;
100
+ const { selected } = await this.prompt([{
106
101
  type: 'list',
107
102
  name: 'selected',
108
103
  message: 'Move to which status?',
109
104
  choices: statusChoices,
110
- }]);
105
+ }], jsonModeConfig);
111
106
  targetStatus = selected;
112
107
  }
113
108
  if (targetStatus === epic.status) {
@@ -120,26 +115,19 @@ export default class EpicMove extends PMOCommand {
120
115
  const allComplete = doneTickets === tickets.length;
121
116
  // Moving to complete - check ticket completion
122
117
  if (targetStatus === 'complete' && !allComplete && !flags.force) {
123
- // In JSON mode, output confirmation prompt
124
- if (jsonMode) {
125
- const confirmChoices = [
126
- { name: 'No', value: 'false' },
127
- { name: 'Yes', value: 'true' },
128
- ];
129
- outputPromptAsJson(buildPromptConfig('list', 'confirm', `Not all tickets are complete (${doneTickets}/${tickets.length} done). Continue moving to complete anyway?`, confirmChoices), createMetadata('epic move', flags));
130
- return;
118
+ if (!jsonMode) {
119
+ this.log(styles.warning(`\n⚠️ Not all tickets are complete (${doneTickets}/${tickets.length} done)`));
131
120
  }
132
- this.log(styles.warning(`\n⚠️ Not all tickets are complete (${doneTickets}/${tickets.length} done)`));
133
- const { confirm } = await inquirer.prompt([{
121
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic move' } : null;
122
+ const { confirm } = await this.prompt([{
134
123
  type: 'list',
135
124
  name: 'confirm',
136
- message: 'Continue moving to complete anyway?',
125
+ message: `Not all tickets are complete (${doneTickets}/${tickets.length} done). Continue moving to complete anyway?`,
137
126
  choices: [
138
- { name: 'No', value: false },
139
- { name: 'Yes', value: true },
127
+ { name: 'No', value: false, command: '' },
128
+ { name: 'Yes', value: true, command: `prlt epic move ${epicId} complete --force --json` },
140
129
  ],
141
- default: false,
142
- }]);
130
+ }], jsonModeConfig);
143
131
  if (!confirm) {
144
132
  this.log(styles.muted('Cancelled.'));
145
133
  return;
@@ -147,26 +135,19 @@ export default class EpicMove extends PMOCommand {
147
135
  }
148
136
  // Moving to dropped - confirm cancellation
149
137
  if (targetStatus === 'dropped' && !flags.force) {
150
- // In JSON mode, output confirmation prompt
151
- if (jsonMode) {
152
- const confirmChoices = [
153
- { name: 'No', value: 'false' },
154
- { name: 'Yes', value: 'true' },
155
- ];
156
- outputPromptAsJson(buildPromptConfig('list', 'confirmDrop', 'This will mark the epic as dropped/cancelled. Continue?', confirmChoices), createMetadata('epic move', flags));
157
- return;
138
+ if (!jsonMode) {
139
+ this.log(styles.warning('\n⚠️ This will mark the epic as dropped/cancelled'));
158
140
  }
159
- this.log(styles.warning('\n⚠️ This will mark the epic as dropped/cancelled'));
160
- const { confirm } = await inquirer.prompt([{
141
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic move' } : null;
142
+ const { confirm } = await this.prompt([{
161
143
  type: 'list',
162
144
  name: 'confirm',
163
- message: 'Continue?',
145
+ message: 'This will mark the epic as dropped/cancelled. Continue?',
164
146
  choices: [
165
- { name: 'No', value: false },
166
- { name: 'Yes', value: true },
147
+ { name: 'No', value: false, command: '' },
148
+ { name: 'Yes', value: true, command: `prlt epic move ${epicId} dropped --force --json` },
167
149
  ],
168
- default: false,
169
- }]);
150
+ }], jsonModeConfig);
170
151
  if (!confirm) {
171
152
  this.log(styles.muted('Cancelled.'));
172
153
  return;
@@ -1,9 +1,8 @@
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 { styles } from '../../lib/styles.js';
5
4
  import { getRelativeEpicPath } from '../../lib/pmo/epic-files.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
5
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
7
6
  // Progress bar helper
8
7
  function progressBar(percent, width = 20) {
9
8
  const filled = Math.round((percent / 100) * width);
@@ -57,21 +56,18 @@ export default class EpicProgress extends PMOCommand {
57
56
  this.log(styles.muted('\nNo epics found.'));
58
57
  return;
59
58
  }
60
- // In JSON mode, output epic selection prompt
61
- if (jsonMode) {
62
- const epicChoices = epics.map(e => ({ name: `${e.id} ${e.title} (${e.status})`, value: e.id }));
63
- outputPromptAsJson(buildPromptConfig('list', 'id', 'Select epic to view progress:', epicChoices), createMetadata('epic progress', flags));
64
- return;
65
- }
66
- const { selected } = await inquirer.prompt([{
59
+ const epicChoices = epics.map(e => ({
60
+ name: `${e.id} ${e.title} (${e.status})`,
61
+ value: e.id,
62
+ command: `prlt epic progress ${e.id} --json`,
63
+ }));
64
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic progress' } : null;
65
+ const { selected } = await this.prompt([{
67
66
  type: 'list',
68
67
  name: 'selected',
69
68
  message: 'Select epic to view progress:',
70
- choices: epics.map(e => ({
71
- name: `${e.id} ${e.title} (${e.status})`,
72
- value: e.id,
73
- })),
74
- }]);
69
+ choices: epicChoices,
70
+ }], jsonModeConfig);
75
71
  epicId = selected;
76
72
  }
77
73
  await this.showSingleProgress(projectId, epicId);
@@ -1,8 +1,7 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
- import inquirer from 'inquirer';
3
2
  import { PMOCommand, pmoBaseFlags, autoExportToBoard } from '../../lib/pmo/index.js';
4
3
  import { styles } from '../../lib/styles.js';
5
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
4
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
6
5
  export default class EpicProject extends PMOCommand {
7
6
  static description = 'Move an epic to a different project (optionally with its tickets)';
8
7
  static examples = [
@@ -60,21 +59,18 @@ export default class EpicProject extends PMOCommand {
60
59
  this.log(styles.muted('\nNo epics found in this project.'));
61
60
  return;
62
61
  }
63
- // In JSON mode, output epic selection prompt
64
- if (jsonMode) {
65
- const epicChoices = epics.map(e => ({ name: `${e.id} - ${e.title} (${e.status})`, value: e.id }));
66
- outputPromptAsJson(buildPromptConfig('list', 'epicId', 'Select epic to move:', epicChoices), createMetadata('epic project', flags));
67
- return;
68
- }
69
- const { selected } = await inquirer.prompt([{
62
+ const epicChoices = epics.map(e => ({
63
+ name: `${e.id} - ${e.title} (${e.status})`,
64
+ value: e.id,
65
+ command: `prlt epic project ${e.id} --json`,
66
+ }));
67
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic project' } : null;
68
+ const { selected } = await this.prompt([{
70
69
  type: 'list',
71
70
  name: 'selected',
72
71
  message: 'Select epic to move:',
73
- choices: epics.map(e => ({
74
- name: `${e.id} - ${e.title} (${e.status})`,
75
- value: e.id,
76
- })),
77
- }]);
72
+ choices: epicChoices,
73
+ }], jsonModeConfig);
78
74
  epicId = selected;
79
75
  }
80
76
  // Get epic details
@@ -86,24 +82,20 @@ export default class EpicProject extends PMOCommand {
86
82
  const projects = await this.storage.listProjects();
87
83
  const otherProjects = projects.filter(p => p.id !== sourceProjectId);
88
84
  if (otherProjects.length === 0) {
89
- if (jsonMode) {
90
- const actionChoices = [
91
- { name: 'Create a new project', value: 'create' },
92
- { name: 'Cancel', value: 'cancel' },
93
- ];
94
- outputPromptAsJson(buildPromptConfig('list', 'action', 'No other projects to move to. What would you like to do?', actionChoices), createMetadata('epic project', flags));
95
- return;
85
+ if (!jsonMode) {
86
+ this.log(styles.muted('\nNo other projects to move to.'));
96
87
  }
97
- this.log(styles.muted('\nNo other projects to move to.'));
98
- const { action } = await inquirer.prompt([{
88
+ const actionChoices = [
89
+ { name: 'Create a new project', value: 'create', command: 'prlt project create --json' },
90
+ { name: 'Cancel', value: 'cancel', command: '' },
91
+ ];
92
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic project' } : null;
93
+ const { action } = await this.prompt([{
99
94
  type: 'list',
100
95
  name: 'action',
101
- message: 'What would you like to do?',
102
- choices: [
103
- { name: 'Create a new project', value: 'create' },
104
- { name: 'Cancel', value: 'cancel' },
105
- ],
106
- }]);
96
+ message: 'No other projects to move to. What would you like to do?',
97
+ choices: actionChoices,
98
+ }], jsonModeConfig);
107
99
  if (action === 'create') {
108
100
  await this.config.runCommand('project:create', []);
109
101
  }
@@ -112,21 +104,18 @@ export default class EpicProject extends PMOCommand {
112
104
  // Get target project
113
105
  let targetProjectId = args.targetProject;
114
106
  if (!targetProjectId) {
115
- // In JSON mode, output project selection prompt
116
- if (jsonMode) {
117
- const projectChoices = otherProjects.map(p => ({ name: `${p.id} - ${p.name} (${p.status})`, value: p.id }));
118
- outputPromptAsJson(buildPromptConfig('list', 'targetProject', 'Select target project:', projectChoices), createMetadata('epic project', flags));
119
- return;
120
- }
121
- const { selected } = await inquirer.prompt([{
107
+ const projectChoices = otherProjects.map(p => ({
108
+ name: `${p.id} - ${p.name} (${p.status})`,
109
+ value: p.id,
110
+ command: `prlt epic project ${epicId} ${p.id} --json`,
111
+ }));
112
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic project' } : null;
113
+ const { selected } = await this.prompt([{
122
114
  type: 'list',
123
115
  name: 'selected',
124
116
  message: 'Select target project:',
125
- choices: otherProjects.map(p => ({
126
- name: `${p.id} - ${p.name} (${p.status})`,
127
- value: p.id,
128
- })),
129
- }]);
117
+ choices: projectChoices,
118
+ }], jsonModeConfig);
130
119
  targetProjectId = selected;
131
120
  }
132
121
  // Validate target project
@@ -145,27 +134,21 @@ export default class EpicProject extends PMOCommand {
145
134
  // Handle tickets
146
135
  let moveTickets = flags['with-tickets'];
147
136
  if (epicTickets.length > 0 && !flags['with-tickets']) {
148
- // In JSON mode, output ticket handling prompt
149
- if (jsonMode) {
150
- const ticketActionChoices = [
151
- { name: 'Move tickets with epic', value: 'move' },
152
- { name: 'Keep tickets in source project (unlink from epic)', value: 'unlink' },
153
- { name: 'Cancel', value: 'cancel' },
154
- ];
155
- outputPromptAsJson(buildPromptConfig('list', 'ticketAction', `Epic has ${epicTickets.length} ticket(s) assigned. How to handle tickets?`, ticketActionChoices), createMetadata('epic project', flags));
156
- return;
137
+ if (!jsonMode) {
138
+ this.log(styles.warning(`\nEpic has ${epicTickets.length} ticket(s) assigned.`));
157
139
  }
158
- this.log(styles.warning(`\nEpic has ${epicTickets.length} ticket(s) assigned.`));
159
- const { action } = await inquirer.prompt([{
140
+ const ticketActionChoices = [
141
+ { name: 'Move tickets with epic', value: 'move', command: `prlt epic project ${epicId} ${targetProjectId} --with-tickets --json` },
142
+ { name: 'Keep tickets in source project (unlink from epic)', value: 'unlink', command: `prlt epic project ${epicId} ${targetProjectId} --json` },
143
+ { name: 'Cancel', value: 'cancel', command: '' },
144
+ ];
145
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic project' } : null;
146
+ const { action } = await this.prompt([{
160
147
  type: 'list',
161
148
  name: 'action',
162
- message: 'How to handle tickets?',
163
- choices: [
164
- { name: 'Move tickets with epic', value: 'move' },
165
- { name: 'Keep tickets in source project (unlink from epic)', value: 'unlink' },
166
- { name: 'Cancel', value: 'cancel' },
167
- ],
168
- }]);
149
+ message: `Epic has ${epicTickets.length} ticket(s) assigned. How to handle tickets?`,
150
+ choices: ticketActionChoices,
151
+ }], jsonModeConfig);
169
152
  if (action === 'cancel') {
170
153
  return;
171
154
  }
@@ -1,8 +1,7 @@
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 { styles } from '../../lib/styles.js';
5
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
4
+ import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
6
5
  export default class EpicReorder extends PMOCommand {
7
6
  static description = 'Reorder epic priority/rank';
8
7
  static examples = [
@@ -74,18 +73,15 @@ export default class EpicReorder extends PMOCommand {
74
73
  const choices = epics.map((e, i) => ({
75
74
  name: `#${i + 1} ${e.id} - ${e.title}`,
76
75
  value: e.id,
76
+ command: `prlt epic reorder ${e.id} --json`,
77
77
  }));
78
- // In JSON mode, output epic selection prompt
79
- if (jsonMode) {
80
- outputPromptAsJson(buildPromptConfig('list', 'id', 'Select epic to reorder:', choices), createMetadata('epic reorder', flags));
81
- return;
82
- }
83
- const { selected } = await inquirer.prompt([{
78
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic reorder' } : null;
79
+ const { selected } = await this.prompt([{
84
80
  type: 'list',
85
81
  name: 'selected',
86
82
  message: 'Select epic to reorder:',
87
83
  choices,
88
- }]);
84
+ }], jsonModeConfig);
89
85
  epicId = selected;
90
86
  }
91
87
  const epic = await this.storage.getEpic(epicId);
@@ -123,30 +119,29 @@ export default class EpicReorder extends PMOCommand {
123
119
  newPosition = epics.length - 1;
124
120
  }
125
121
  else {
126
- // In JSON mode, output rank input prompt
127
- if (jsonMode) {
128
- outputPromptAsJson(buildPromptConfig('input', 'rank', `New rank for ${epicId} (1-${epics.length}):`, undefined, String(epic.position + 1)), createMetadata('epic reorder', flags));
129
- return;
130
- }
131
122
  // Interactive: show current order and ask for new position
132
- this.log(`\nCurrent order:`);
133
- epics.forEach((e, i) => {
134
- const marker = e.id === epicId ? ' ◀' : '';
135
- this.log(` #${i + 1} ${e.id} - ${e.title}${marker}`);
136
- });
137
- const { rank } = await inquirer.prompt([{
138
- type: 'number',
123
+ if (!jsonMode) {
124
+ this.log(`\nCurrent order:`);
125
+ epics.forEach((e, i) => {
126
+ const marker = e.id === epicId ? ' ◀' : '';
127
+ this.log(` #${i + 1} ${e.id} - ${e.title}${marker}`);
128
+ });
129
+ }
130
+ // Build position choices for rank selection
131
+ const rankChoices = epics.map((e, i) => ({
132
+ name: `#${i + 1}${e.id === epicId ? ' (current)' : ` - before ${e.title}`}`,
133
+ value: String(i + 1),
134
+ command: `prlt epic reorder ${epicId} ${i + 1} --json`,
135
+ }));
136
+ const jsonModeConfig = jsonMode ? { flags, commandName: 'epic reorder' } : null;
137
+ const { rank } = await this.prompt([{
138
+ type: 'list',
139
139
  name: 'rank',
140
140
  message: `New rank for ${epicId} (1-${epics.length}):`,
141
- default: epic.position + 1,
142
- validate: (input) => {
143
- if (input < 1 || input > epics.length) {
144
- return `Please enter a number between 1 and ${epics.length}`;
145
- }
146
- return true;
147
- },
148
- }]);
149
- newPosition = rank - 1;
141
+ choices: rankChoices,
142
+ default: String(epic.position + 1),
143
+ }], jsonModeConfig);
144
+ newPosition = parseInt(rank, 10) - 1;
150
145
  }
151
146
  // Perform reorder
152
147
  await this.storage.reorderEpic(projectId, epicId, newPosition);
@@ -9,6 +9,7 @@ export default class EpicSpec extends PMOCommand {
9
9
  static flags: {
10
10
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  unlink: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ 'align-tickets': import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
13
  project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
14
  };
14
15
  execute(): Promise<void>;