@proletariat/cli 0.3.25 → 0.3.27
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.
- package/dist/commands/action/index.js +2 -2
- package/dist/commands/action/show.js +7 -1
- package/dist/commands/agent/auth.js +1 -1
- package/dist/commands/agent/cleanup.js +6 -6
- package/dist/commands/agent/discover.js +1 -1
- package/dist/commands/agent/remove.js +4 -4
- package/dist/commands/autocomplete/setup.d.ts +2 -2
- package/dist/commands/autocomplete/setup.js +5 -5
- package/dist/commands/branch/create.js +31 -30
- package/dist/commands/branch/list.js +14 -11
- package/dist/commands/branch/validate.js +10 -1
- package/dist/commands/category/create.js +4 -5
- package/dist/commands/category/delete.js +2 -3
- package/dist/commands/category/rename.js +2 -3
- package/dist/commands/claude.d.ts +2 -8
- package/dist/commands/claude.js +26 -26
- package/dist/commands/commit.d.ts +2 -8
- package/dist/commands/commit.js +4 -26
- package/dist/commands/config/index.d.ts +2 -10
- package/dist/commands/config/index.js +8 -34
- package/dist/commands/docker/clean.js +7 -9
- package/dist/commands/docker/index.d.ts +2 -2
- package/dist/commands/docker/index.js +13 -12
- package/dist/commands/docker/list.d.ts +1 -0
- package/dist/commands/docker/list.js +31 -17
- package/dist/commands/docker/status.d.ts +3 -1
- package/dist/commands/docker/status.js +28 -2
- package/dist/commands/docker/sync.js +7 -6
- package/dist/commands/epic/delete.js +4 -5
- package/dist/commands/epic/list.js +17 -2
- package/dist/commands/execution/list.js +25 -17
- package/dist/commands/feedback/submit.d.ts +2 -2
- package/dist/commands/feedback/submit.js +9 -9
- package/dist/commands/link/index.js +2 -2
- package/dist/commands/pmo/init.d.ts +2 -2
- package/dist/commands/pmo/init.js +29 -10
- package/dist/commands/project/spec.js +6 -6
- package/dist/commands/repo/list.js +14 -8
- package/dist/commands/repo/view.js +2 -1
- package/dist/commands/roadmap/list.js +16 -1
- package/dist/commands/session/health.d.ts +29 -0
- package/dist/commands/session/health.js +496 -0
- package/dist/commands/session/index.js +4 -0
- package/dist/commands/session/list.js +15 -8
- package/dist/commands/spec/edit.js +2 -3
- package/dist/commands/staff/add.d.ts +2 -2
- package/dist/commands/staff/add.js +15 -14
- package/dist/commands/staff/index.js +2 -2
- package/dist/commands/staff/list.d.ts +3 -1
- package/dist/commands/staff/list.js +15 -1
- package/dist/commands/staff/remove.js +4 -4
- package/dist/commands/status/index.js +6 -7
- package/dist/commands/template/apply.js +10 -11
- package/dist/commands/template/create.js +18 -17
- package/dist/commands/template/index.d.ts +2 -2
- package/dist/commands/template/index.js +6 -6
- package/dist/commands/template/save.js +8 -7
- package/dist/commands/template/update.js +6 -7
- package/dist/commands/terminal/title.d.ts +2 -26
- package/dist/commands/terminal/title.js +4 -33
- package/dist/commands/theme/index.d.ts +2 -2
- package/dist/commands/theme/index.js +19 -18
- package/dist/commands/theme/list.d.ts +3 -0
- package/dist/commands/theme/list.js +25 -0
- package/dist/commands/theme/set.d.ts +2 -2
- package/dist/commands/theme/set.js +5 -5
- package/dist/commands/ticket/complete.js +4 -1
- package/dist/commands/ticket/create.d.ts +1 -0
- package/dist/commands/ticket/create.js +64 -16
- package/dist/commands/ticket/delete.js +18 -16
- package/dist/commands/ticket/edit.js +22 -14
- package/dist/commands/ticket/epic.js +12 -10
- package/dist/commands/ticket/list.js +24 -5
- package/dist/commands/ticket/move.js +4 -1
- package/dist/commands/ticket/project.js +11 -9
- package/dist/commands/ticket/reassign.js +23 -19
- package/dist/commands/ticket/spec.js +7 -5
- package/dist/commands/ticket/update.js +55 -53
- package/dist/commands/ticket/view.js +4 -2
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +22 -4
- package/dist/commands/work/complete.js +2 -2
- package/dist/commands/work/ready.js +9 -9
- package/dist/commands/work/revise.js +15 -13
- package/dist/commands/work/spawn.js +154 -57
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +299 -177
- package/dist/commands/workspace/prune.d.ts +3 -2
- package/dist/commands/workspace/prune.js +70 -10
- package/dist/hooks/init.js +4 -0
- package/dist/lib/agents/commands.js +4 -0
- package/dist/lib/agents/index.js +12 -0
- package/dist/lib/execution/devcontainer.d.ts +4 -0
- package/dist/lib/execution/devcontainer.js +63 -0
- package/dist/lib/mcp/helpers.d.ts +15 -0
- package/dist/lib/mcp/helpers.js +15 -0
- package/dist/lib/mcp/tools/action.js +5 -5
- package/dist/lib/mcp/tools/board.js +7 -7
- package/dist/lib/mcp/tools/category.js +5 -5
- package/dist/lib/mcp/tools/cli-passthrough.js +30 -30
- package/dist/lib/mcp/tools/epic.js +8 -8
- package/dist/lib/mcp/tools/phase.js +7 -7
- package/dist/lib/mcp/tools/project.js +10 -10
- package/dist/lib/mcp/tools/roadmap.js +7 -7
- package/dist/lib/mcp/tools/spec.js +9 -9
- package/dist/lib/mcp/tools/status.js +6 -6
- package/dist/lib/mcp/tools/template.js +6 -6
- package/dist/lib/mcp/tools/ticket.js +19 -19
- package/dist/lib/mcp/tools/view.js +4 -4
- package/dist/lib/mcp/tools/work.js +6 -6
- package/dist/lib/mcp/tools/workflow.js +5 -5
- package/dist/lib/pmo/index.js +4 -0
- package/dist/lib/pmo/storage/base.js +49 -0
- package/dist/lib/pr/index.d.ts +9 -0
- package/dist/lib/pr/index.js +101 -14
- package/dist/lib/prompt-command.d.ts +3 -0
- package/dist/lib/prompt-json.d.ts +72 -1
- package/dist/lib/prompt-json.js +46 -0
- package/dist/lib/repos/index.js +4 -0
- package/dist/lib/string-utils.d.ts +10 -0
- package/dist/lib/string-utils.js +16 -0
- package/oclif.manifest.json +594 -449
- package/package.json +3 -2
|
@@ -153,8 +153,8 @@ export default class TicketEdit extends PMOCommand {
|
|
|
153
153
|
return; // outputPromptAsJson exits, but TypeScript doesn't know
|
|
154
154
|
}
|
|
155
155
|
// Interactive mode - prompt for all editable fields
|
|
156
|
-
const board = await this.storage.
|
|
157
|
-
const columns = board.columns.map(col => col.name);
|
|
156
|
+
const board = ticket.projectId ? await this.storage.getProjectBoard(ticket.projectId) : null;
|
|
157
|
+
const columns = board ? board.columns.map(col => col.name) : [];
|
|
158
158
|
updates = await this.promptForEdits(ticket, columns);
|
|
159
159
|
}
|
|
160
160
|
else {
|
|
@@ -269,7 +269,7 @@ export default class TicketEdit extends PMOCommand {
|
|
|
269
269
|
}
|
|
270
270
|
async promptForEdits(ticket, _columns) {
|
|
271
271
|
// First prompt for title
|
|
272
|
-
const { title } = await
|
|
272
|
+
const { title } = await this.prompt([
|
|
273
273
|
{
|
|
274
274
|
type: 'input',
|
|
275
275
|
name: 'title',
|
|
@@ -277,7 +277,7 @@ export default class TicketEdit extends PMOCommand {
|
|
|
277
277
|
default: ticket.title,
|
|
278
278
|
validate: (input) => input.trim() ? true : 'Title cannot be empty',
|
|
279
279
|
},
|
|
280
|
-
]);
|
|
280
|
+
], null);
|
|
281
281
|
// Prompt for description using inline multiline input
|
|
282
282
|
const descResult = await multiLineInput({
|
|
283
283
|
message: 'Description:',
|
|
@@ -287,8 +287,8 @@ export default class TicketEdit extends PMOCommand {
|
|
|
287
287
|
if (descResult.cancelled) {
|
|
288
288
|
throw new Error('Edit cancelled');
|
|
289
289
|
}
|
|
290
|
-
// Continue with remaining prompts
|
|
291
|
-
const
|
|
290
|
+
// Continue with remaining prompts - priority first
|
|
291
|
+
const { priority } = await this.prompt([
|
|
292
292
|
{
|
|
293
293
|
type: 'list',
|
|
294
294
|
name: 'priority',
|
|
@@ -299,6 +299,9 @@ export default class TicketEdit extends PMOCommand {
|
|
|
299
299
|
],
|
|
300
300
|
default: ticket.priority || '',
|
|
301
301
|
},
|
|
302
|
+
], null);
|
|
303
|
+
// Then category
|
|
304
|
+
const { categoryChoice } = await this.prompt([
|
|
302
305
|
{
|
|
303
306
|
type: 'list',
|
|
304
307
|
name: 'categoryChoice',
|
|
@@ -330,14 +333,19 @@ export default class TicketEdit extends PMOCommand {
|
|
|
330
333
|
],
|
|
331
334
|
default: ticket.category || '',
|
|
332
335
|
},
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
336
|
+
], null);
|
|
337
|
+
// Custom category prompt if needed
|
|
338
|
+
let customCategory;
|
|
339
|
+
if (categoryChoice === '__custom__') {
|
|
340
|
+
const result = await this.prompt([{
|
|
341
|
+
type: 'input',
|
|
342
|
+
name: 'customCategory',
|
|
343
|
+
message: 'Enter custom category:',
|
|
344
|
+
validate: (input) => input.trim() ? true : 'Category cannot be empty',
|
|
345
|
+
}], null);
|
|
346
|
+
customCategory = result.customCategory;
|
|
347
|
+
}
|
|
348
|
+
const answers = { priority, categoryChoice, customCategory };
|
|
341
349
|
// Build updates object with only changed fields
|
|
342
350
|
const updates = {};
|
|
343
351
|
if (title !== ticket.title) {
|
|
@@ -1,5 +1,4 @@
|
|
|
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
4
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
@@ -198,6 +197,8 @@ export default class TicketEpic extends PMOCommand {
|
|
|
198
197
|
this.log(styles.muted(` Epic: ${epic.title}`));
|
|
199
198
|
}
|
|
200
199
|
async executeBulk(flags) {
|
|
200
|
+
const jsonMode = shouldOutputJson(flags);
|
|
201
|
+
const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'ticket epic' } : null;
|
|
201
202
|
this.log(styles.emphasis('🔗 Link Tickets to Epic\n'));
|
|
202
203
|
// Get project first
|
|
203
204
|
const projectId = await this.requireProject();
|
|
@@ -238,7 +239,7 @@ export default class TicketEpic extends PMOCommand {
|
|
|
238
239
|
ticketEpics.set(ticket.id, row?.epic_id || null);
|
|
239
240
|
}
|
|
240
241
|
// Select tickets to link
|
|
241
|
-
const { selectedTickets } = await
|
|
242
|
+
const { selectedTickets } = await this.prompt([{
|
|
242
243
|
type: 'checkbox',
|
|
243
244
|
name: 'selectedTickets',
|
|
244
245
|
message: 'Select tickets to link:',
|
|
@@ -250,7 +251,7 @@ export default class TicketEpic extends PMOCommand {
|
|
|
250
251
|
value: t.id,
|
|
251
252
|
};
|
|
252
253
|
}),
|
|
253
|
-
}]);
|
|
254
|
+
}], jsonModeConfig);
|
|
254
255
|
if (selectedTickets.length === 0) {
|
|
255
256
|
this.log(styles.muted('No tickets selected.'));
|
|
256
257
|
return;
|
|
@@ -258,18 +259,19 @@ export default class TicketEpic extends PMOCommand {
|
|
|
258
259
|
// Select target epic
|
|
259
260
|
let targetEpic = flags['to-epic'];
|
|
260
261
|
if (targetEpic === undefined) {
|
|
261
|
-
const { epic } = await
|
|
262
|
+
const { epic } = await this.prompt([{
|
|
262
263
|
type: 'list',
|
|
263
264
|
name: 'epic',
|
|
264
265
|
message: 'Link to which epic?',
|
|
265
266
|
choices: [
|
|
266
|
-
{ name: 'None (remove epic link)', value: null },
|
|
267
|
+
{ name: 'None (remove epic link)', value: null, command: 'prlt ticket epic --bulk --unlink --json' },
|
|
267
268
|
...epics.map(e => ({
|
|
268
269
|
name: `${e.title} (${e.status})`,
|
|
269
270
|
value: e.id,
|
|
271
|
+
command: `prlt ticket epic --bulk --to-epic ${e.id} --json`,
|
|
270
272
|
})),
|
|
271
273
|
],
|
|
272
|
-
}]);
|
|
274
|
+
}], jsonModeConfig);
|
|
273
275
|
targetEpic = epic;
|
|
274
276
|
}
|
|
275
277
|
// Confirmation
|
|
@@ -285,16 +287,16 @@ export default class TicketEpic extends PMOCommand {
|
|
|
285
287
|
this.log(styles.primary(` • ${ticketId}: ${ticket?.title}`));
|
|
286
288
|
}
|
|
287
289
|
this.log('');
|
|
288
|
-
const { confirm } = await
|
|
290
|
+
const { confirm } = await this.prompt([{
|
|
289
291
|
type: 'list',
|
|
290
292
|
name: 'confirm',
|
|
291
293
|
message: 'Continue?',
|
|
292
294
|
choices: [
|
|
293
|
-
{ name: 'No, cancel', value: false },
|
|
294
|
-
{ name: 'Yes, link tickets', value: true }
|
|
295
|
+
{ name: 'No, cancel', value: false, command: '' },
|
|
296
|
+
{ name: 'Yes, link tickets', value: true, command: `prlt ticket epic --bulk --to-epic ${targetEpic || 'none'} --force --json` }
|
|
295
297
|
],
|
|
296
298
|
default: 0
|
|
297
|
-
}]);
|
|
299
|
+
}], jsonModeConfig);
|
|
298
300
|
if (!confirm) {
|
|
299
301
|
this.log(styles.muted('Operation cancelled.'));
|
|
300
302
|
return;
|
|
@@ -3,6 +3,7 @@ import { pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
|
3
3
|
import { PRIORITIES } from '../../lib/pmo/types.js';
|
|
4
4
|
import { getPMOContext } from '../../lib/pmo/pmo-context.js';
|
|
5
5
|
import { styles, formatPriority, formatCategory, getColumnStyle, getColumnEmoji, divider, getPriorityStyle, } from '../../lib/styles.js';
|
|
6
|
+
import { isNonTTY } from '../../lib/prompt-json.js';
|
|
6
7
|
// Priority order for grouping: P0, P1, P2, P3, None
|
|
7
8
|
const PRIORITY_ORDER = ['P0', 'P1', 'P2', 'P3', 'None'];
|
|
8
9
|
export default class TicketList extends Command {
|
|
@@ -67,6 +68,10 @@ export default class TicketList extends Command {
|
|
|
67
68
|
};
|
|
68
69
|
async run() {
|
|
69
70
|
const { flags } = await this.parse(TicketList);
|
|
71
|
+
// Default format to 'json' in non-TTY environments (piped output, CI, agents)
|
|
72
|
+
if (flags.format === 'table' && isNonTTY()) {
|
|
73
|
+
flags.format = 'json';
|
|
74
|
+
}
|
|
70
75
|
// When --all is set, we don't need to select a specific project
|
|
71
76
|
// Otherwise, use the normal project selection flow
|
|
72
77
|
// Get PMO context - no project selection needed
|
|
@@ -110,10 +115,12 @@ export default class TicketList extends Command {
|
|
|
110
115
|
// Get the project board to validate the column
|
|
111
116
|
const targetProjectId = projectId || (await pmoContext.storage.listProjectSummaries())[0]?.id;
|
|
112
117
|
if (targetProjectId) {
|
|
113
|
-
const board = await pmoContext.storage.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
118
|
+
const board = await pmoContext.storage.getProjectBoard(targetProjectId);
|
|
119
|
+
if (board) {
|
|
120
|
+
const validColumns = board.columns.map(c => c.name);
|
|
121
|
+
if (!validColumns.includes(flags.column)) {
|
|
122
|
+
this.error(`Column "${flags.column}" not found. Valid columns: ${validColumns.join(', ')}`);
|
|
123
|
+
}
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
126
|
}
|
|
@@ -149,7 +156,19 @@ export default class TicketList extends Command {
|
|
|
149
156
|
this.log(styles.warning('No project found.'));
|
|
150
157
|
return;
|
|
151
158
|
}
|
|
152
|
-
const board = await pmoContext.storage.
|
|
159
|
+
const board = await pmoContext.storage.getProjectBoard(actualProjectId);
|
|
160
|
+
if (!board) {
|
|
161
|
+
// Project doesn't exist (orphaned tickets) - fall back to cross-project view
|
|
162
|
+
this.log(styles.warning(`Project "${actualProjectId}" not found. Showing tickets without board layout.`));
|
|
163
|
+
switch (flags.format) {
|
|
164
|
+
case 'json':
|
|
165
|
+
this.log(JSON.stringify(tickets, null, 2));
|
|
166
|
+
break;
|
|
167
|
+
default:
|
|
168
|
+
this.outputCrossProjectTable(tickets, groupBy);
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
153
172
|
const columns = board.columns.map(col => col.name);
|
|
154
173
|
switch (flags.format) {
|
|
155
174
|
case 'json':
|
|
@@ -216,7 +216,10 @@ export default class TicketMove extends PMOCommand {
|
|
|
216
216
|
this.log(styles.emphasis('📦 Move Multiple Tickets\n'));
|
|
217
217
|
}
|
|
218
218
|
// Get columns
|
|
219
|
-
const board = await this.storage.
|
|
219
|
+
const board = await this.storage.getProjectBoard(projectId);
|
|
220
|
+
if (!board) {
|
|
221
|
+
this.error(`Project "${projectId}" not found. The ticket may belong to an orphaned project.`);
|
|
222
|
+
}
|
|
220
223
|
const columns = board.columns.map(col => col.name);
|
|
221
224
|
// Agent mode config for prompts
|
|
222
225
|
const jsonModeConfig = flags.json ? { flags, commandName: 'ticket move --bulk' } : null;
|
|
@@ -1,5 +1,4 @@
|
|
|
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
4
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
@@ -166,6 +165,8 @@ export default class TicketProject extends PMOCommand {
|
|
|
166
165
|
this.log(styles.muted(`\nView ticket: prlt ticket view ${ticketId}`));
|
|
167
166
|
}
|
|
168
167
|
async executeBulk(flags) {
|
|
168
|
+
const jsonMode = shouldOutputJson(flags);
|
|
169
|
+
const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'ticket project' } : null;
|
|
169
170
|
this.log(styles.emphasis('📁 Bulk Move Tickets to Project\n'));
|
|
170
171
|
// Get source project ID
|
|
171
172
|
const sourceProjectId = await this.requireProject();
|
|
@@ -176,7 +177,7 @@ export default class TicketProject extends PMOCommand {
|
|
|
176
177
|
return;
|
|
177
178
|
}
|
|
178
179
|
// Select tickets
|
|
179
|
-
const { selectedTickets } = await
|
|
180
|
+
const { selectedTickets } = await this.prompt([{
|
|
180
181
|
type: 'checkbox',
|
|
181
182
|
name: 'selectedTickets',
|
|
182
183
|
message: 'Select tickets to move:',
|
|
@@ -187,7 +188,7 @@ export default class TicketProject extends PMOCommand {
|
|
|
187
188
|
value: t.id,
|
|
188
189
|
};
|
|
189
190
|
}),
|
|
190
|
-
}]);
|
|
191
|
+
}], jsonModeConfig);
|
|
191
192
|
if (selectedTickets.length === 0) {
|
|
192
193
|
this.log(styles.muted('No tickets selected.'));
|
|
193
194
|
return;
|
|
@@ -201,15 +202,16 @@ export default class TicketProject extends PMOCommand {
|
|
|
201
202
|
}
|
|
202
203
|
let targetProjectId = flags.target;
|
|
203
204
|
if (!targetProjectId) {
|
|
204
|
-
const { selected } = await
|
|
205
|
+
const { selected } = await this.prompt([{
|
|
205
206
|
type: 'list',
|
|
206
207
|
name: 'selected',
|
|
207
208
|
message: 'Select target project:',
|
|
208
209
|
choices: otherProjects.map(p => ({
|
|
209
210
|
name: `${p.id} - ${p.name}`,
|
|
210
211
|
value: p.id,
|
|
212
|
+
command: `prlt ticket project --bulk --target ${p.id} --json`,
|
|
211
213
|
})),
|
|
212
|
-
}]);
|
|
214
|
+
}], jsonModeConfig);
|
|
213
215
|
targetProjectId = selected;
|
|
214
216
|
}
|
|
215
217
|
// Validate target project
|
|
@@ -224,15 +226,15 @@ export default class TicketProject extends PMOCommand {
|
|
|
224
226
|
});
|
|
225
227
|
if (ticketsWithEpics.length > 0) {
|
|
226
228
|
this.log(styles.warning(`\n${ticketsWithEpics.length} ticket(s) are assigned to epics.`));
|
|
227
|
-
const { action } = await
|
|
229
|
+
const { action } = await this.prompt([{
|
|
228
230
|
type: 'list',
|
|
229
231
|
name: 'action',
|
|
230
232
|
message: 'How to handle epic assignments?',
|
|
231
233
|
choices: [
|
|
232
|
-
{ name: 'Unlink from epics and move', value: 'unlink' },
|
|
233
|
-
{ name: 'Cancel', value: 'cancel' },
|
|
234
|
+
{ name: 'Unlink from epics and move', value: 'unlink', command: `prlt ticket project --bulk --target ${targetProjectId} --json` },
|
|
235
|
+
{ name: 'Cancel', value: 'cancel', command: '' },
|
|
234
236
|
],
|
|
235
|
-
}]);
|
|
237
|
+
}], jsonModeConfig);
|
|
236
238
|
if (action === 'cancel') {
|
|
237
239
|
return;
|
|
238
240
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
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
4
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
@@ -110,26 +109,28 @@ export default class TicketReassign extends PMOCommand {
|
|
|
110
109
|
// Get target assignee
|
|
111
110
|
let targetAssignee = args.assignee || flags.to;
|
|
112
111
|
if (!targetAssignee) {
|
|
113
|
-
const {
|
|
112
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'ticket reassign' } : null;
|
|
113
|
+
const { assignee } = await this.prompt([{
|
|
114
114
|
type: 'list',
|
|
115
115
|
name: 'assignee',
|
|
116
116
|
message: `Reassign ${ticketId} to:`,
|
|
117
117
|
choices: [
|
|
118
|
-
{ name: 'None (unassign)', value: '__none__' },
|
|
118
|
+
{ name: 'None (unassign)', value: '__none__', command: `prlt ticket reassign ${ticketId} none${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
119
119
|
...Array.from(assignees).sort().map(a => ({
|
|
120
120
|
name: a === ticket.assignee ? `${a} (current)` : a,
|
|
121
121
|
value: a,
|
|
122
|
+
command: `prlt ticket reassign ${ticketId} ${a}${projectId ? ` -P ${projectId}` : ''} --json`,
|
|
122
123
|
})),
|
|
123
|
-
{ name: '── Enter custom name ──', value: '__custom__' },
|
|
124
|
+
{ name: '── Enter custom name ──', value: '__custom__', command: `prlt ticket reassign ${ticketId} <name>${projectId ? ` -P ${projectId}` : ''} --json` },
|
|
124
125
|
],
|
|
125
|
-
}]);
|
|
126
|
+
}], jsonModeConfig);
|
|
126
127
|
if (assignee === '__custom__') {
|
|
127
|
-
const { customAssignee } = await
|
|
128
|
+
const { customAssignee } = await this.prompt([{
|
|
128
129
|
type: 'input',
|
|
129
130
|
name: 'customAssignee',
|
|
130
131
|
message: 'Enter agent/assignee name:',
|
|
131
132
|
validate: (input) => input.length > 0 || 'Name is required',
|
|
132
|
-
}]);
|
|
133
|
+
}], jsonModeConfig);
|
|
133
134
|
targetAssignee = customAssignee;
|
|
134
135
|
}
|
|
135
136
|
else if (assignee === '__none__') {
|
|
@@ -173,6 +174,7 @@ export default class TicketReassign extends PMOCommand {
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
async executeBulk(allTickets, assigneesList, flags) {
|
|
177
|
+
const jsonMode = shouldOutputJson(flags);
|
|
176
178
|
this.log(styles.emphasis('👤 Reassign Tickets\n'));
|
|
177
179
|
// Filter tickets if --from specified
|
|
178
180
|
let filteredTickets = allTickets;
|
|
@@ -189,7 +191,8 @@ export default class TicketReassign extends PMOCommand {
|
|
|
189
191
|
return;
|
|
190
192
|
}
|
|
191
193
|
// Select tickets to reassign
|
|
192
|
-
const {
|
|
194
|
+
const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'ticket reassign' } : null;
|
|
195
|
+
const { selectedTickets } = await this.prompt([{
|
|
193
196
|
type: 'checkbox',
|
|
194
197
|
name: 'selectedTickets',
|
|
195
198
|
message: 'Select tickets to reassign:',
|
|
@@ -197,7 +200,7 @@ export default class TicketReassign extends PMOCommand {
|
|
|
197
200
|
name: `${t.id} - ${t.title} [Assignee: ${t.assignee || '(none)'}]`,
|
|
198
201
|
value: t.id,
|
|
199
202
|
})),
|
|
200
|
-
}]);
|
|
203
|
+
}], jsonModeConfig);
|
|
201
204
|
if (selectedTickets.length === 0) {
|
|
202
205
|
this.log(styles.muted('No tickets selected.'));
|
|
203
206
|
return;
|
|
@@ -205,26 +208,27 @@ export default class TicketReassign extends PMOCommand {
|
|
|
205
208
|
// Select target assignee
|
|
206
209
|
let targetAssignee = flags.to;
|
|
207
210
|
if (targetAssignee === undefined) {
|
|
208
|
-
const { assignee } = await
|
|
211
|
+
const { assignee } = await this.prompt([{
|
|
209
212
|
type: 'list',
|
|
210
213
|
name: 'assignee',
|
|
211
214
|
message: 'Reassign to which agent?',
|
|
212
215
|
choices: [
|
|
213
|
-
{ name: 'None (unassign)', value: '__none__' },
|
|
216
|
+
{ name: 'None (unassign)', value: '__none__', command: '' },
|
|
214
217
|
...assigneesList.sort().map(a => ({
|
|
215
218
|
name: a,
|
|
216
219
|
value: a,
|
|
220
|
+
command: `prlt ticket reassign --bulk --to ${a} --json`,
|
|
217
221
|
})),
|
|
218
|
-
{ name: '── Enter custom name ──', value: '__custom__' },
|
|
222
|
+
{ name: '── Enter custom name ──', value: '__custom__', command: '' },
|
|
219
223
|
],
|
|
220
|
-
}]);
|
|
224
|
+
}], jsonModeConfig);
|
|
221
225
|
if (assignee === '__custom__') {
|
|
222
|
-
const { customAssignee } = await
|
|
226
|
+
const { customAssignee } = await this.prompt([{
|
|
223
227
|
type: 'input',
|
|
224
228
|
name: 'customAssignee',
|
|
225
229
|
message: 'Enter agent/assignee name:',
|
|
226
230
|
validate: (input) => input.length > 0 || 'Name is required',
|
|
227
|
-
}]);
|
|
231
|
+
}], jsonModeConfig);
|
|
228
232
|
targetAssignee = customAssignee;
|
|
229
233
|
}
|
|
230
234
|
else if (assignee === '__none__') {
|
|
@@ -262,16 +266,16 @@ export default class TicketReassign extends PMOCommand {
|
|
|
262
266
|
this.log(styles.primary(` • ${ticketId}: ${ticket?.title}`));
|
|
263
267
|
}
|
|
264
268
|
this.log('');
|
|
265
|
-
const { confirm } = await
|
|
269
|
+
const { confirm } = await this.prompt([{
|
|
266
270
|
type: 'list',
|
|
267
271
|
name: 'confirm',
|
|
268
272
|
message: 'Continue?',
|
|
269
273
|
choices: [
|
|
270
|
-
{ name: 'No, cancel', value: false },
|
|
271
|
-
{ name: 'Yes, reassign tickets', value: true }
|
|
274
|
+
{ name: 'No, cancel', value: false, command: '' },
|
|
275
|
+
{ name: 'Yes, reassign tickets', value: true, command: `prlt ticket reassign --bulk --to ${targetAssignee || 'none'} --force --json` }
|
|
272
276
|
],
|
|
273
277
|
default: 0
|
|
274
|
-
}]);
|
|
278
|
+
}], jsonModeConfig);
|
|
275
279
|
if (!confirm) {
|
|
276
280
|
this.log(styles.muted('Operation cancelled.'));
|
|
277
281
|
return;
|
|
@@ -1,5 +1,4 @@
|
|
|
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
4
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
@@ -192,6 +191,8 @@ export default class TicketSpec extends PMOCommand {
|
|
|
192
191
|
this.log(styles.muted(`\nView ticket: prlt ticket view ${ticketId}`));
|
|
193
192
|
}
|
|
194
193
|
async executeBulk(flags, projectId) {
|
|
194
|
+
const jsonMode = shouldOutputJson(flags);
|
|
195
|
+
const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'ticket spec' } : null;
|
|
195
196
|
this.log(styles.emphasis('📄 Bulk Assign Spec to Tickets\n'));
|
|
196
197
|
// Get all tickets
|
|
197
198
|
const tickets = await this.storage.listTickets(projectId);
|
|
@@ -200,7 +201,7 @@ export default class TicketSpec extends PMOCommand {
|
|
|
200
201
|
return;
|
|
201
202
|
}
|
|
202
203
|
// Select tickets
|
|
203
|
-
const { selectedTickets } = await
|
|
204
|
+
const { selectedTickets } = await this.prompt([{
|
|
204
205
|
type: 'checkbox',
|
|
205
206
|
name: 'selectedTickets',
|
|
206
207
|
message: 'Select tickets to update:',
|
|
@@ -211,7 +212,7 @@ export default class TicketSpec extends PMOCommand {
|
|
|
211
212
|
value: t.id,
|
|
212
213
|
};
|
|
213
214
|
}),
|
|
214
|
-
}]);
|
|
215
|
+
}], jsonModeConfig);
|
|
215
216
|
if (selectedTickets.length === 0) {
|
|
216
217
|
this.log(styles.muted('No tickets selected.'));
|
|
217
218
|
return;
|
|
@@ -235,15 +236,16 @@ export default class TicketSpec extends PMOCommand {
|
|
|
235
236
|
this.log(styles.muted('\nNo specs found. Create one with: prlt spec create'));
|
|
236
237
|
return;
|
|
237
238
|
}
|
|
238
|
-
const { selected } = await
|
|
239
|
+
const { selected } = await this.prompt([{
|
|
239
240
|
type: 'list',
|
|
240
241
|
name: 'selected',
|
|
241
242
|
message: 'Select spec to assign:',
|
|
242
243
|
choices: specs.map(s => ({
|
|
243
244
|
name: `${s.id} - ${s.title} (${s.status})`,
|
|
244
245
|
value: s.id,
|
|
246
|
+
command: `prlt ticket spec --bulk --spec ${s.id} --json`,
|
|
245
247
|
})),
|
|
246
|
-
}]);
|
|
248
|
+
}], jsonModeConfig);
|
|
247
249
|
specId = selected;
|
|
248
250
|
}
|
|
249
251
|
// Validate spec
|