@proletariat/cli 0.3.25 → 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.
- package/dist/commands/action/index.js +2 -2
- 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/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/index.d.ts +2 -2
- package/dist/commands/docker/index.js +8 -8
- package/dist/commands/epic/delete.js +4 -5
- 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 +7 -7
- package/dist/commands/project/spec.js +6 -6
- package/dist/commands/session/health.d.ts +29 -0
- package/dist/commands/session/health.js +495 -0
- package/dist/commands/session/index.js +4 -0
- 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/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/set.d.ts +2 -2
- package/dist/commands/theme/set.js +5 -5
- package/dist/commands/ticket/create.js +34 -16
- package/dist/commands/ticket/delete.js +15 -13
- package/dist/commands/ticket/edit.js +20 -12
- package/dist/commands/ticket/epic.js +12 -10
- 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/whoami.js +1 -0
- package/dist/commands/work/ready.js +7 -7
- package/dist/commands/work/revise.js +13 -11
- package/dist/commands/work/spawn.js +154 -57
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +295 -173
- package/dist/hooks/init.js +4 -0
- package/dist/lib/pr/index.d.ts +4 -0
- package/dist/lib/pr/index.js +32 -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/oclif.manifest.json +1184 -1116
- package/package.json +1 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import
|
|
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
|
|
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
|
|
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);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { autoExportToBoard, PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
4
|
+
// Note: inquirer import kept for inquirer.Separator usage in interactive mode
|
|
4
5
|
import { styles } from '../../lib/styles.js';
|
|
5
6
|
import { updateEpicTicketsSection } from '../../lib/pmo/epic-files.js';
|
|
6
7
|
import { PRIORITIES, PRIORITY_LABELS } from '../../lib/pmo/types.js';
|
|
@@ -290,7 +291,7 @@ export default class TicketCreate extends PMOCommand {
|
|
|
290
291
|
if (!template && !flags.template) {
|
|
291
292
|
const templates = await storage.listTicketTemplates();
|
|
292
293
|
if (templates.length > 0) {
|
|
293
|
-
const { selectedTemplate } = await
|
|
294
|
+
const { selectedTemplate } = await this.prompt([
|
|
294
295
|
{
|
|
295
296
|
type: 'list',
|
|
296
297
|
name: 'selectedTemplate',
|
|
@@ -304,13 +305,14 @@ export default class TicketCreate extends PMOCommand {
|
|
|
304
305
|
})),
|
|
305
306
|
],
|
|
306
307
|
},
|
|
307
|
-
]);
|
|
308
|
+
], null);
|
|
308
309
|
if (selectedTemplate) {
|
|
309
310
|
template = templates.find(t => t.id === selectedTemplate) || null;
|
|
310
311
|
}
|
|
311
312
|
}
|
|
312
313
|
}
|
|
313
|
-
|
|
314
|
+
// Prompt for title
|
|
315
|
+
const { title: answerTitle } = await this.prompt([
|
|
314
316
|
{
|
|
315
317
|
type: 'input',
|
|
316
318
|
name: 'title',
|
|
@@ -318,13 +320,19 @@ export default class TicketCreate extends PMOCommand {
|
|
|
318
320
|
default: flags.title || template?.titlePattern,
|
|
319
321
|
validate: (input) => input.trim() ? true : 'Title cannot be empty',
|
|
320
322
|
},
|
|
323
|
+
], null);
|
|
324
|
+
// Prompt for column
|
|
325
|
+
const { column: answerColumn } = await this.prompt([
|
|
321
326
|
{
|
|
322
327
|
type: 'list',
|
|
323
328
|
name: 'column',
|
|
324
329
|
message: 'Column:',
|
|
325
|
-
choices: columns,
|
|
330
|
+
choices: columns.map(c => ({ name: c, value: c })),
|
|
326
331
|
default: flags.column || columns[0],
|
|
327
332
|
},
|
|
333
|
+
], null);
|
|
334
|
+
// Prompt for priority
|
|
335
|
+
const { priority: answerPriority } = await this.prompt([
|
|
328
336
|
{
|
|
329
337
|
type: 'list',
|
|
330
338
|
name: 'priority',
|
|
@@ -335,6 +343,9 @@ export default class TicketCreate extends PMOCommand {
|
|
|
335
343
|
],
|
|
336
344
|
default: flags.priority || template?.defaultPriority,
|
|
337
345
|
},
|
|
346
|
+
], null);
|
|
347
|
+
// Prompt for category
|
|
348
|
+
const { categoryChoice } = await this.prompt([
|
|
338
349
|
{
|
|
339
350
|
type: 'list',
|
|
340
351
|
name: 'categoryChoice',
|
|
@@ -366,14 +377,19 @@ export default class TicketCreate extends PMOCommand {
|
|
|
366
377
|
],
|
|
367
378
|
default: flags.category || template?.defaultCategory || '',
|
|
368
379
|
},
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
380
|
+
], null);
|
|
381
|
+
// Custom category prompt if needed
|
|
382
|
+
let customCategory;
|
|
383
|
+
if (categoryChoice === '__custom__') {
|
|
384
|
+
const result = await this.prompt([{
|
|
385
|
+
type: 'input',
|
|
386
|
+
name: 'customCategory',
|
|
387
|
+
message: 'Enter custom category:',
|
|
388
|
+
validate: (input) => input.trim() ? true : 'Category cannot be empty',
|
|
389
|
+
}], null);
|
|
390
|
+
customCategory = result.customCategory;
|
|
391
|
+
}
|
|
392
|
+
const answers = { title: answerTitle, column: answerColumn, priority: answerPriority, categoryChoice, customCategory };
|
|
377
393
|
// Resolve category from choice or custom input
|
|
378
394
|
const category = answers.categoryChoice === '__custom__'
|
|
379
395
|
? answers.customCategory
|
|
@@ -402,14 +418,14 @@ export default class TicketCreate extends PMOCommand {
|
|
|
402
418
|
}
|
|
403
419
|
this.log(styles.muted('\n─── Ticket Description (for agent execution) ───'));
|
|
404
420
|
// Prompt for "What" - the main outcome
|
|
405
|
-
const { what } = await
|
|
421
|
+
const { what } = await this.prompt([
|
|
406
422
|
{
|
|
407
423
|
type: 'input',
|
|
408
424
|
name: 'what',
|
|
409
425
|
message: 'What is the concrete outcome? (one sentence):',
|
|
410
426
|
validate: (input) => input.trim() ? true : 'Outcome cannot be empty - what does success look like?',
|
|
411
427
|
},
|
|
412
|
-
]);
|
|
428
|
+
], null);
|
|
413
429
|
// Prompt for acceptance criteria using multiline input
|
|
414
430
|
const doneWhenResult = await multiLineInput({
|
|
415
431
|
message: 'Done when (acceptance criteria):',
|
|
@@ -419,20 +435,22 @@ export default class TicketCreate extends PMOCommand {
|
|
|
419
435
|
throw new Error('Ticket creation cancelled');
|
|
420
436
|
}
|
|
421
437
|
// Continue with remaining prompts
|
|
422
|
-
const { context
|
|
438
|
+
const { context } = await this.prompt([
|
|
423
439
|
{
|
|
424
440
|
type: 'input',
|
|
425
441
|
name: 'context',
|
|
426
442
|
message: 'Context (files, patterns, hints - optional):',
|
|
427
443
|
default: '',
|
|
428
444
|
},
|
|
445
|
+
], null);
|
|
446
|
+
const { notInScope } = await this.prompt([
|
|
429
447
|
{
|
|
430
448
|
type: 'input',
|
|
431
449
|
name: 'notInScope',
|
|
432
450
|
message: 'Not in scope (explicit exclusions - optional):',
|
|
433
451
|
default: '',
|
|
434
452
|
},
|
|
435
|
-
]);
|
|
453
|
+
], null);
|
|
436
454
|
// Build structured description
|
|
437
455
|
const parts = [];
|
|
438
456
|
parts.push(`## What\n${what}`);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
2
|
import { autoExportToBoard, PMOCommand, pmoBaseFlags, } from '../../lib/pmo/index.js';
|
|
4
3
|
import { styles } from '../../lib/styles.js';
|
|
5
4
|
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
@@ -57,7 +56,7 @@ export default class TicketDelete extends PMOCommand {
|
|
|
57
56
|
}
|
|
58
57
|
// Bulk mode
|
|
59
58
|
if (flags.bulk) {
|
|
60
|
-
await this.executeBulk(allTickets, flags.force);
|
|
59
|
+
await this.executeBulk(allTickets, flags.force, flags);
|
|
61
60
|
return;
|
|
62
61
|
}
|
|
63
62
|
// Single ticket mode
|
|
@@ -90,16 +89,17 @@ export default class TicketDelete extends PMOCommand {
|
|
|
90
89
|
this.log(` Title: ${ticket.title}`);
|
|
91
90
|
this.log(` Project: ${board.name}`);
|
|
92
91
|
this.log(` Status: ${ticket.statusName}`);
|
|
93
|
-
const {
|
|
92
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'ticket delete' } : null;
|
|
93
|
+
const { confirmed } = await this.prompt([{
|
|
94
94
|
type: 'list',
|
|
95
95
|
name: 'confirmed',
|
|
96
96
|
message: 'Are you sure?',
|
|
97
97
|
choices: [
|
|
98
|
-
{ name: 'No, cancel', value: false },
|
|
99
|
-
{ name: 'Yes, delete', value: true },
|
|
98
|
+
{ name: 'No, cancel', value: false, command: '' },
|
|
99
|
+
{ name: 'Yes, delete', value: true, command: `prlt ticket delete ${ticketId} --force --json` },
|
|
100
100
|
],
|
|
101
101
|
default: 0,
|
|
102
|
-
}]);
|
|
102
|
+
}], jsonModeConfig);
|
|
103
103
|
if (!confirmed) {
|
|
104
104
|
this.log(styles.warning('Deletion cancelled.'));
|
|
105
105
|
return;
|
|
@@ -112,10 +112,12 @@ export default class TicketDelete extends PMOCommand {
|
|
|
112
112
|
this.log(styles.success(`\n✅ Ticket ${styles.emphasis(ticketId)} deleted`));
|
|
113
113
|
this.log(styles.muted(' Removed from database and board'));
|
|
114
114
|
}
|
|
115
|
-
async executeBulk(allTickets, force) {
|
|
115
|
+
async executeBulk(allTickets, force, flags) {
|
|
116
|
+
const jsonMode = flags ? shouldOutputJson(flags) : false;
|
|
117
|
+
const jsonModeConfig = jsonMode ? { flags: flags, commandName: 'ticket delete' } : null;
|
|
116
118
|
this.log(styles.emphasis('🗑️ Delete Multiple Tickets\n'));
|
|
117
119
|
// Select tickets to delete
|
|
118
|
-
const { selectedTickets } = await
|
|
120
|
+
const { selectedTickets } = await this.prompt([{
|
|
119
121
|
type: 'checkbox',
|
|
120
122
|
name: 'selectedTickets',
|
|
121
123
|
message: 'Select tickets to DELETE:',
|
|
@@ -123,7 +125,7 @@ export default class TicketDelete extends PMOCommand {
|
|
|
123
125
|
name: `${t.id} - ${t.title} (${t.statusName})`,
|
|
124
126
|
value: t.id,
|
|
125
127
|
})),
|
|
126
|
-
}]);
|
|
128
|
+
}], jsonModeConfig);
|
|
127
129
|
if (selectedTickets.length === 0) {
|
|
128
130
|
this.log(styles.muted('No tickets selected.'));
|
|
129
131
|
return;
|
|
@@ -136,16 +138,16 @@ export default class TicketDelete extends PMOCommand {
|
|
|
136
138
|
this.log(styles.primary(` • ${ticketId}: ${ticket?.title}`));
|
|
137
139
|
}
|
|
138
140
|
this.log('');
|
|
139
|
-
const { confirm } = await
|
|
141
|
+
const { confirm } = await this.prompt([{
|
|
140
142
|
type: 'list',
|
|
141
143
|
name: 'confirm',
|
|
142
144
|
message: 'Are you sure? This cannot be undone.',
|
|
143
145
|
choices: [
|
|
144
|
-
{ name: 'No, cancel', value: false },
|
|
145
|
-
{ name: 'Yes, DELETE tickets', value: true }
|
|
146
|
+
{ name: 'No, cancel', value: false, command: '' },
|
|
147
|
+
{ name: 'Yes, DELETE tickets', value: true, command: 'prlt ticket delete --bulk --force --json' }
|
|
146
148
|
],
|
|
147
149
|
default: 0
|
|
148
|
-
}]);
|
|
150
|
+
}], jsonModeConfig);
|
|
149
151
|
if (!confirm) {
|
|
150
152
|
this.log(styles.muted('Deletion cancelled.'));
|
|
151
153
|
return;
|
|
@@ -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;
|
|
@@ -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
|