@proletariat/cli 0.3.18 → 0.3.20
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/LICENSE +21 -0
- package/bin/dev.js +0 -0
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +34 -26
- package/dist/commands/agent/temp/cleanup.js +10 -17
- package/dist/commands/board/view.d.ts +15 -0
- package/dist/commands/board/view.js +136 -0
- package/dist/commands/config/index.js +6 -3
- package/dist/commands/execution/config.d.ts +34 -0
- package/dist/commands/execution/config.js +411 -0
- package/dist/commands/execution/index.js +6 -1
- package/dist/commands/execution/kill.d.ts +9 -0
- package/dist/commands/execution/kill.js +16 -0
- package/dist/commands/execution/view.d.ts +17 -0
- package/dist/commands/execution/view.js +288 -0
- package/dist/commands/phase/template/create.js +67 -20
- package/dist/commands/pr/index.js +6 -2
- package/dist/commands/pr/list.d.ts +17 -0
- package/dist/commands/pr/list.js +163 -0
- package/dist/commands/project/update.d.ts +19 -0
- package/dist/commands/project/update.js +163 -0
- package/dist/commands/roadmap/create.js +5 -0
- package/dist/commands/spec/delete.d.ts +18 -0
- package/dist/commands/spec/delete.js +111 -0
- package/dist/commands/spec/edit.d.ts +23 -0
- package/dist/commands/spec/edit.js +232 -0
- package/dist/commands/spec/index.js +5 -0
- package/dist/commands/status/create.js +38 -34
- package/dist/commands/template/phase/create.d.ts +1 -0
- package/dist/commands/template/phase/create.js +10 -1
- package/dist/commands/template/ticket/create.d.ts +20 -0
- package/dist/commands/template/ticket/create.js +87 -0
- package/dist/commands/template/ticket/save.d.ts +2 -0
- package/dist/commands/template/ticket/save.js +11 -0
- package/dist/commands/ticket/create.js +7 -0
- package/dist/commands/ticket/template/create.d.ts +9 -1
- package/dist/commands/ticket/template/create.js +224 -52
- package/dist/commands/ticket/template/save.d.ts +2 -1
- package/dist/commands/ticket/template/save.js +58 -7
- package/dist/commands/work/ready.js +8 -8
- package/dist/lib/agents/index.js +14 -4
- package/dist/lib/branch/index.js +24 -0
- package/dist/lib/execution/config.d.ts +2 -0
- package/dist/lib/execution/config.js +12 -0
- package/dist/lib/pmo/utils.d.ts +4 -2
- package/dist/lib/pmo/utils.js +4 -2
- package/oclif.manifest.json +2555 -1781
- package/package.json +5 -6
|
@@ -7,6 +7,7 @@ export default class TemplatePhaseCreate extends Command {
|
|
|
7
7
|
};
|
|
8
8
|
static flags: {
|
|
9
9
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
11
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
};
|
|
12
13
|
run(): Promise<void>;
|
|
@@ -4,6 +4,7 @@ export default class TemplatePhaseCreate extends Command {
|
|
|
4
4
|
static examples = [
|
|
5
5
|
'<%= config.bin %> <%= command.id %> "My Phases"',
|
|
6
6
|
'<%= config.bin %> <%= command.id %> "Sprint Phases" --description "Agile sprint phases"',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> "My Phases" --description "Custom phases" --json',
|
|
7
8
|
];
|
|
8
9
|
static args = {
|
|
9
10
|
name: Args.string({
|
|
@@ -16,9 +17,15 @@ export default class TemplatePhaseCreate extends Command {
|
|
|
16
17
|
char: 'd',
|
|
17
18
|
description: 'Template description',
|
|
18
19
|
}),
|
|
20
|
+
machine: Flags.boolean({
|
|
21
|
+
char: 'm',
|
|
22
|
+
description: 'Output as JSON for AI agents/scripts (machine-readable mode)',
|
|
23
|
+
default: false,
|
|
24
|
+
}),
|
|
19
25
|
json: Flags.boolean({
|
|
20
|
-
description: 'Output
|
|
26
|
+
description: 'Output as JSON (deprecated, use --machine)',
|
|
21
27
|
default: false,
|
|
28
|
+
hidden: true,
|
|
22
29
|
}),
|
|
23
30
|
};
|
|
24
31
|
async run() {
|
|
@@ -28,6 +35,8 @@ export default class TemplatePhaseCreate extends Command {
|
|
|
28
35
|
cmdArgs.push(args.name);
|
|
29
36
|
if (flags.description)
|
|
30
37
|
cmdArgs.push('--description', flags.description);
|
|
38
|
+
if (flags.machine)
|
|
39
|
+
cmdArgs.push('--machine');
|
|
31
40
|
if (flags.json)
|
|
32
41
|
cmdArgs.push('--json');
|
|
33
42
|
await this.config.runCommand('phase:template:create', cmdArgs);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Command } from '@oclif/core';
|
|
2
|
+
export default class TemplateTicketCreate extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
|
+
'title-pattern': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'description-template': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
subtask: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
ac: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
label: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
run(): Promise<void>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
export default class TemplateTicketCreate extends Command {
|
|
3
|
+
static description = 'Create a new ticket template from scratch';
|
|
4
|
+
static examples = [
|
|
5
|
+
'<%= config.bin %> <%= command.id %> "Bug Report"',
|
|
6
|
+
'<%= config.bin %> <%= command.id %> "Feature Request" -d "Template for new features"',
|
|
7
|
+
'<%= config.bin %> <%= command.id %> "Task" --title-pattern "[TASK] " --priority P2',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> "Onboarding" --subtask "Setup environment" --subtask "Read docs" --ac "Complete all subtasks"',
|
|
9
|
+
];
|
|
10
|
+
static args = {
|
|
11
|
+
name: Args.string({
|
|
12
|
+
description: 'Template name',
|
|
13
|
+
required: false,
|
|
14
|
+
}),
|
|
15
|
+
};
|
|
16
|
+
static flags = {
|
|
17
|
+
description: Flags.string({
|
|
18
|
+
char: 'd',
|
|
19
|
+
description: 'Template description',
|
|
20
|
+
}),
|
|
21
|
+
'title-pattern': Flags.string({
|
|
22
|
+
description: 'Default title prefix/pattern (e.g., "[BUG] ")',
|
|
23
|
+
}),
|
|
24
|
+
'description-template': Flags.string({
|
|
25
|
+
description: 'Default description template (markdown)',
|
|
26
|
+
}),
|
|
27
|
+
priority: Flags.string({
|
|
28
|
+
char: 'p',
|
|
29
|
+
description: 'Default priority (P0, P1, P2, P3)',
|
|
30
|
+
}),
|
|
31
|
+
category: Flags.string({
|
|
32
|
+
char: 'c',
|
|
33
|
+
description: 'Default category (bug, feature, etc.)',
|
|
34
|
+
}),
|
|
35
|
+
subtask: Flags.string({
|
|
36
|
+
description: 'Add a suggested subtask (can be used multiple times)',
|
|
37
|
+
multiple: true,
|
|
38
|
+
}),
|
|
39
|
+
ac: Flags.string({
|
|
40
|
+
description: 'Add an acceptance criterion pattern (can be used multiple times)',
|
|
41
|
+
multiple: true,
|
|
42
|
+
}),
|
|
43
|
+
label: Flags.string({
|
|
44
|
+
char: 'l',
|
|
45
|
+
description: 'Add a default label (can be used multiple times)',
|
|
46
|
+
multiple: true,
|
|
47
|
+
}),
|
|
48
|
+
json: Flags.boolean({
|
|
49
|
+
description: 'Output prompt configuration as JSON (for AI agents/scripts)',
|
|
50
|
+
default: false,
|
|
51
|
+
}),
|
|
52
|
+
};
|
|
53
|
+
async run() {
|
|
54
|
+
const { args, flags } = await this.parse(TemplateTicketCreate);
|
|
55
|
+
const cmdArgs = [];
|
|
56
|
+
if (args.name)
|
|
57
|
+
cmdArgs.push(args.name);
|
|
58
|
+
if (flags.description)
|
|
59
|
+
cmdArgs.push('--description', flags.description);
|
|
60
|
+
if (flags['title-pattern'])
|
|
61
|
+
cmdArgs.push('--title-pattern', flags['title-pattern']);
|
|
62
|
+
if (flags['description-template'])
|
|
63
|
+
cmdArgs.push('--description-template', flags['description-template']);
|
|
64
|
+
if (flags.priority)
|
|
65
|
+
cmdArgs.push('--priority', flags.priority);
|
|
66
|
+
if (flags.category)
|
|
67
|
+
cmdArgs.push('--category', flags.category);
|
|
68
|
+
if (flags.subtask) {
|
|
69
|
+
for (const subtask of flags.subtask) {
|
|
70
|
+
cmdArgs.push('--subtask', subtask);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (flags.ac) {
|
|
74
|
+
for (const ac of flags.ac) {
|
|
75
|
+
cmdArgs.push('--ac', ac);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (flags.label) {
|
|
79
|
+
for (const label of flags.label) {
|
|
80
|
+
cmdArgs.push('--label', label);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (flags.json)
|
|
84
|
+
cmdArgs.push('--json');
|
|
85
|
+
await this.config.runCommand('ticket:template:create', cmdArgs);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -7,8 +7,10 @@ export default class TemplateTicketSave extends Command {
|
|
|
7
7
|
name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
8
|
};
|
|
9
9
|
static flags: {
|
|
10
|
+
'template-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
14
|
};
|
|
13
15
|
run(): Promise<void>;
|
|
14
16
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
|
+
import { machineOutputFlags } from '../../../lib/pmo/base-command.js';
|
|
2
3
|
export default class TemplateTicketSave extends Command {
|
|
3
4
|
static description = 'Create a template from an existing ticket';
|
|
4
5
|
static examples = [
|
|
5
6
|
'<%= config.bin %> <%= command.id %> TKT-001 "Bug Report Template"',
|
|
6
7
|
'<%= config.bin %> <%= command.id %> TKT-042 "Feature Request" --description "Standard feature request template"',
|
|
8
|
+
'<%= config.bin %> <%= command.id %> TKT-001 --template-name "My Template" --json',
|
|
7
9
|
];
|
|
8
10
|
static args = {
|
|
9
11
|
ticket: Args.string({
|
|
@@ -16,6 +18,11 @@ export default class TemplateTicketSave extends Command {
|
|
|
16
18
|
}),
|
|
17
19
|
};
|
|
18
20
|
static flags = {
|
|
21
|
+
...machineOutputFlags,
|
|
22
|
+
'template-name': Flags.string({
|
|
23
|
+
char: 'n',
|
|
24
|
+
description: 'Template name (alternative to positional arg, required in non-TTY/JSON mode)',
|
|
25
|
+
}),
|
|
19
26
|
description: Flags.string({
|
|
20
27
|
char: 'd',
|
|
21
28
|
description: 'Template description',
|
|
@@ -32,10 +39,14 @@ export default class TemplateTicketSave extends Command {
|
|
|
32
39
|
cmdArgs.push(args.ticket);
|
|
33
40
|
if (args.name)
|
|
34
41
|
cmdArgs.push(args.name);
|
|
42
|
+
if (flags['template-name'])
|
|
43
|
+
cmdArgs.push('--template-name', flags['template-name']);
|
|
35
44
|
if (flags.description)
|
|
36
45
|
cmdArgs.push('--description', flags.description);
|
|
37
46
|
if (flags.json)
|
|
38
47
|
cmdArgs.push('--json');
|
|
48
|
+
if (flags.machine)
|
|
49
|
+
cmdArgs.push('--machine');
|
|
39
50
|
await this.config.runCommand('ticket:template:save', cmdArgs);
|
|
40
51
|
}
|
|
41
52
|
}
|
|
@@ -110,6 +110,13 @@ export default class TicketCreate extends PMOCommand {
|
|
|
110
110
|
// Use FlagResolver to handle both JSON mode and interactive prompts
|
|
111
111
|
// This unifies the two code paths into one pattern
|
|
112
112
|
if (!flags.interactive) {
|
|
113
|
+
// In JSON mode, default column to first backlog status if not provided
|
|
114
|
+
// This prevents prompting for column in non-interactive mode
|
|
115
|
+
if (jsonMode && !flags.column) {
|
|
116
|
+
// Prefer "Backlog" column, fall back to first column
|
|
117
|
+
const backlogColumn = columns.find(c => c.toLowerCase() === 'backlog') || columns[0];
|
|
118
|
+
flags.column = backlogColumn;
|
|
119
|
+
}
|
|
113
120
|
const resolver = new FlagResolver({
|
|
114
121
|
commandName: 'ticket create',
|
|
115
122
|
baseCommand: 'prlt ticket create',
|
|
@@ -8,14 +8,22 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
8
8
|
static flags: {
|
|
9
9
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
10
|
'title-pattern': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'description-template': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
12
|
priority: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
13
|
category: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
-
|
|
14
|
+
subtask: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
ac: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
label: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
17
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
19
|
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
20
|
};
|
|
17
21
|
protected getPMOOptions(): {
|
|
18
22
|
promptIfMultiple: boolean;
|
|
19
23
|
};
|
|
20
24
|
execute(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Check if any non-default flags were provided (indicating non-interactive intent)
|
|
27
|
+
*/
|
|
28
|
+
private hasNonDefaultFlags;
|
|
21
29
|
}
|
|
@@ -3,12 +3,15 @@ import inquirer from 'inquirer';
|
|
|
3
3
|
import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
|
|
4
4
|
import { PRIORITIES, PRIORITY_LABELS, TICKET_CATEGORIES } from '../../../lib/pmo/types.js';
|
|
5
5
|
import { styles } from '../../../lib/styles.js';
|
|
6
|
+
import { shouldOutputJson, outputSuccessAsJson, outputPromptAsJson, buildFormPromptConfig, createMetadata, } from '../../../lib/prompt-json.js';
|
|
6
7
|
export default class TicketTemplateCreate extends PMOCommand {
|
|
7
8
|
static description = 'Create a new ticket template from scratch';
|
|
8
9
|
static examples = [
|
|
9
10
|
'<%= config.bin %> <%= command.id %> "Bug Report"',
|
|
10
11
|
'<%= config.bin %> <%= command.id %> "Feature Request" -d "Template for new features"',
|
|
11
12
|
'<%= config.bin %> <%= command.id %> "Task" --title-pattern "[TASK] " --priority P2',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> "Onboarding" --subtask "Setup environment" --subtask "Read docs"',
|
|
14
|
+
'<%= config.bin %> <%= command.id %> "Bug" --ac "Bug is fixed" --ac "Tests pass" --category bug',
|
|
12
15
|
];
|
|
13
16
|
static args = {
|
|
14
17
|
name: Args.string({
|
|
@@ -25,6 +28,9 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
25
28
|
'title-pattern': Flags.string({
|
|
26
29
|
description: 'Default title prefix/pattern (e.g., "[BUG] ")',
|
|
27
30
|
}),
|
|
31
|
+
'description-template': Flags.string({
|
|
32
|
+
description: 'Default description template (markdown)',
|
|
33
|
+
}),
|
|
28
34
|
priority: Flags.string({
|
|
29
35
|
char: 'p',
|
|
30
36
|
description: 'Default priority',
|
|
@@ -35,12 +41,141 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
35
41
|
description: 'Default category',
|
|
36
42
|
options: [...TICKET_CATEGORIES],
|
|
37
43
|
}),
|
|
44
|
+
subtask: Flags.string({
|
|
45
|
+
description: 'Add a suggested subtask (can be used multiple times)',
|
|
46
|
+
multiple: true,
|
|
47
|
+
}),
|
|
48
|
+
ac: Flags.string({
|
|
49
|
+
description: 'Add an acceptance criterion pattern (can be used multiple times)',
|
|
50
|
+
multiple: true,
|
|
51
|
+
}),
|
|
52
|
+
label: Flags.string({
|
|
53
|
+
char: 'l',
|
|
54
|
+
description: 'Add a default label (can be used multiple times)',
|
|
55
|
+
multiple: true,
|
|
56
|
+
}),
|
|
57
|
+
json: Flags.boolean({
|
|
58
|
+
description: 'Output prompt configuration as JSON (for AI agents/scripts)',
|
|
59
|
+
default: false,
|
|
60
|
+
}),
|
|
38
61
|
};
|
|
39
62
|
getPMOOptions() {
|
|
40
63
|
return { promptIfMultiple: false };
|
|
41
64
|
}
|
|
42
65
|
async execute() {
|
|
43
66
|
const { args, flags } = await this.parse(TicketTemplateCreate);
|
|
67
|
+
const jsonMode = shouldOutputJson(flags);
|
|
68
|
+
// Check if we have all required data via flags (non-interactive mode)
|
|
69
|
+
const hasName = Boolean(args.name);
|
|
70
|
+
const hasAllFlags = hasName; // Name is the only required field
|
|
71
|
+
// In JSON mode with missing required data, output form prompt
|
|
72
|
+
if (jsonMode && !hasAllFlags) {
|
|
73
|
+
const fields = [];
|
|
74
|
+
if (!hasName) {
|
|
75
|
+
fields.push({
|
|
76
|
+
type: 'input',
|
|
77
|
+
name: 'name',
|
|
78
|
+
message: 'Template name:',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Add optional fields that weren't provided
|
|
82
|
+
if (flags.description === undefined) {
|
|
83
|
+
fields.push({
|
|
84
|
+
type: 'input',
|
|
85
|
+
name: 'description',
|
|
86
|
+
message: 'Template description (optional):',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (flags['title-pattern'] === undefined) {
|
|
90
|
+
fields.push({
|
|
91
|
+
type: 'input',
|
|
92
|
+
name: 'titlePattern',
|
|
93
|
+
message: 'Title prefix/pattern (optional, e.g., "[BUG] "):',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (flags.priority === undefined) {
|
|
97
|
+
fields.push({
|
|
98
|
+
type: 'list',
|
|
99
|
+
name: 'priority',
|
|
100
|
+
message: 'Default priority:',
|
|
101
|
+
choices: [
|
|
102
|
+
{ name: 'None', value: '' },
|
|
103
|
+
...PRIORITIES.map(p => ({ name: PRIORITY_LABELS[p], value: p })),
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
if (flags.category === undefined) {
|
|
108
|
+
fields.push({
|
|
109
|
+
type: 'list',
|
|
110
|
+
name: 'category',
|
|
111
|
+
message: 'Default category:',
|
|
112
|
+
choices: [
|
|
113
|
+
{ name: 'None', value: '' },
|
|
114
|
+
...TICKET_CATEGORIES.map(c => ({ name: c, value: c })),
|
|
115
|
+
],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('ticket template create', flags));
|
|
119
|
+
return; // outputPromptAsJson exits, but TypeScript needs this
|
|
120
|
+
}
|
|
121
|
+
// Non-interactive mode: use flag values directly
|
|
122
|
+
if (hasAllFlags && (jsonMode || this.hasNonDefaultFlags(flags))) {
|
|
123
|
+
const name = args.name;
|
|
124
|
+
const description = flags.description;
|
|
125
|
+
const titlePattern = flags['title-pattern'];
|
|
126
|
+
const priority = flags.priority;
|
|
127
|
+
const category = flags.category;
|
|
128
|
+
const subtasks = flags.subtask || [];
|
|
129
|
+
const acs = flags.ac || [];
|
|
130
|
+
const labels = flags.label || [];
|
|
131
|
+
// Build description template with ACs if provided
|
|
132
|
+
let descriptionTemplate = flags['description-template'];
|
|
133
|
+
if (acs.length > 0 && !descriptionTemplate) {
|
|
134
|
+
// Create a description template with acceptance criteria section
|
|
135
|
+
descriptionTemplate = '## Description\n\n## Acceptance Criteria\n' +
|
|
136
|
+
acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
|
|
137
|
+
}
|
|
138
|
+
else if (acs.length > 0 && descriptionTemplate) {
|
|
139
|
+
// Append ACs to existing template if it doesn't have an AC section
|
|
140
|
+
if (!descriptionTemplate.toLowerCase().includes('acceptance criteria')) {
|
|
141
|
+
descriptionTemplate += '\n\n## Acceptance Criteria\n' +
|
|
142
|
+
acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Create the template
|
|
146
|
+
const template = await this.storage.createTicketTemplate({
|
|
147
|
+
name,
|
|
148
|
+
description,
|
|
149
|
+
titlePattern,
|
|
150
|
+
defaultPriority: priority,
|
|
151
|
+
defaultCategory: category,
|
|
152
|
+
descriptionTemplate,
|
|
153
|
+
suggestedSubtasks: subtasks.map(title => ({ title })),
|
|
154
|
+
defaultLabels: labels,
|
|
155
|
+
});
|
|
156
|
+
if (jsonMode) {
|
|
157
|
+
outputSuccessAsJson({
|
|
158
|
+
template: {
|
|
159
|
+
id: template.id,
|
|
160
|
+
name: template.name,
|
|
161
|
+
description: template.description,
|
|
162
|
+
titlePattern: template.titlePattern,
|
|
163
|
+
defaultPriority: template.defaultPriority,
|
|
164
|
+
defaultCategory: template.defaultCategory,
|
|
165
|
+
descriptionTemplate: template.descriptionTemplate,
|
|
166
|
+
suggestedSubtasks: template.suggestedSubtasks,
|
|
167
|
+
defaultLabels: template.defaultLabels,
|
|
168
|
+
},
|
|
169
|
+
}, createMetadata('ticket template create', flags));
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
this.log(styles.success(`\nCreated template "${styles.emphasis(template.name)}"`));
|
|
173
|
+
this.log(styles.muted(` ID: ${template.id}`));
|
|
174
|
+
this.log('');
|
|
175
|
+
this.log(styles.muted(`Create ticket from template: prlt ticket template apply ${template.id}`));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Interactive mode
|
|
44
179
|
// Get template name
|
|
45
180
|
let name = args.name;
|
|
46
181
|
if (!name) {
|
|
@@ -100,61 +235,79 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
100
235
|
}]);
|
|
101
236
|
category = selectedCategory || undefined;
|
|
102
237
|
}
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (wantDescriptionTemplate) {
|
|
115
|
-
const { template } = await inquirer.prompt([{
|
|
116
|
-
type: 'editor',
|
|
117
|
-
name: 'template',
|
|
118
|
-
message: 'Description template (opens editor):',
|
|
119
|
-
default: `## Summary\n\n## Details\n\n## Acceptance Criteria\n- [ ] \n`,
|
|
238
|
+
// Handle description template - use flag value or prompt
|
|
239
|
+
let descriptionTemplate = flags['description-template'];
|
|
240
|
+
if (descriptionTemplate === undefined) {
|
|
241
|
+
const { wantDescriptionTemplate } = await inquirer.prompt([{
|
|
242
|
+
type: 'list',
|
|
243
|
+
name: 'wantDescriptionTemplate',
|
|
244
|
+
message: 'Add a description template?',
|
|
245
|
+
choices: [
|
|
246
|
+
{ name: 'No', value: false },
|
|
247
|
+
{ name: 'Yes', value: true },
|
|
248
|
+
],
|
|
120
249
|
}]);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
name: 'wantSubtasks',
|
|
128
|
-
message: 'Add default subtasks?',
|
|
129
|
-
choices: [
|
|
130
|
-
{ name: 'No', value: false },
|
|
131
|
-
{ name: 'Yes', value: true },
|
|
132
|
-
],
|
|
133
|
-
}]);
|
|
134
|
-
if (wantSubtasks) {
|
|
135
|
-
let addMore = true;
|
|
136
|
-
while (addMore) {
|
|
137
|
-
// eslint-disable-next-line no-await-in-loop -- Interactive loop for subtask creation
|
|
138
|
-
const { subtaskTitle } = await inquirer.prompt([{
|
|
139
|
-
type: 'input',
|
|
140
|
-
name: 'subtaskTitle',
|
|
141
|
-
message: 'Subtask title:',
|
|
142
|
-
validate: (input) => input.length > 0 || 'Title is required',
|
|
143
|
-
}]);
|
|
144
|
-
subtasks.push(subtaskTitle);
|
|
145
|
-
// eslint-disable-next-line no-await-in-loop -- Interactive loop continuation
|
|
146
|
-
const { another } = await inquirer.prompt([{
|
|
147
|
-
type: 'list',
|
|
148
|
-
name: 'another',
|
|
149
|
-
message: 'Add another subtask?',
|
|
150
|
-
choices: [
|
|
151
|
-
{ name: 'No', value: false },
|
|
152
|
-
{ name: 'Yes', value: true },
|
|
153
|
-
],
|
|
250
|
+
if (wantDescriptionTemplate) {
|
|
251
|
+
const { template } = await inquirer.prompt([{
|
|
252
|
+
type: 'editor',
|
|
253
|
+
name: 'template',
|
|
254
|
+
message: 'Description template (opens editor):',
|
|
255
|
+
default: `## Summary\n\n## Details\n\n## Acceptance Criteria\n- [ ] \n`,
|
|
154
256
|
}]);
|
|
155
|
-
|
|
257
|
+
descriptionTemplate = template || undefined;
|
|
156
258
|
}
|
|
157
259
|
}
|
|
260
|
+
// Handle subtasks - use flag values or prompt
|
|
261
|
+
const subtasks = flags.subtask ? [...flags.subtask] : [];
|
|
262
|
+
if (subtasks.length === 0) {
|
|
263
|
+
const { wantSubtasks } = await inquirer.prompt([{
|
|
264
|
+
type: 'list',
|
|
265
|
+
name: 'wantSubtasks',
|
|
266
|
+
message: 'Add default subtasks?',
|
|
267
|
+
choices: [
|
|
268
|
+
{ name: 'No', value: false },
|
|
269
|
+
{ name: 'Yes', value: true },
|
|
270
|
+
],
|
|
271
|
+
}]);
|
|
272
|
+
if (wantSubtasks) {
|
|
273
|
+
let addMore = true;
|
|
274
|
+
while (addMore) {
|
|
275
|
+
// eslint-disable-next-line no-await-in-loop -- Interactive loop for subtask creation
|
|
276
|
+
const { subtaskTitle } = await inquirer.prompt([{
|
|
277
|
+
type: 'input',
|
|
278
|
+
name: 'subtaskTitle',
|
|
279
|
+
message: 'Subtask title:',
|
|
280
|
+
validate: (input) => input.length > 0 || 'Title is required',
|
|
281
|
+
}]);
|
|
282
|
+
subtasks.push(subtaskTitle);
|
|
283
|
+
// eslint-disable-next-line no-await-in-loop -- Interactive loop continuation
|
|
284
|
+
const { another } = await inquirer.prompt([{
|
|
285
|
+
type: 'list',
|
|
286
|
+
name: 'another',
|
|
287
|
+
message: 'Add another subtask?',
|
|
288
|
+
choices: [
|
|
289
|
+
{ name: 'No', value: false },
|
|
290
|
+
{ name: 'Yes', value: true },
|
|
291
|
+
],
|
|
292
|
+
}]);
|
|
293
|
+
addMore = another;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Handle ACs - add to description template if provided via flag
|
|
298
|
+
const acs = flags.ac || [];
|
|
299
|
+
if (acs.length > 0) {
|
|
300
|
+
if (!descriptionTemplate) {
|
|
301
|
+
descriptionTemplate = '## Description\n\n## Acceptance Criteria\n' +
|
|
302
|
+
acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
|
|
303
|
+
}
|
|
304
|
+
else if (!descriptionTemplate.toLowerCase().includes('acceptance criteria')) {
|
|
305
|
+
descriptionTemplate += '\n\n## Acceptance Criteria\n' +
|
|
306
|
+
acs.map(ac => `- [ ] ${ac}`).join('\n') + '\n';
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// Handle labels
|
|
310
|
+
const labels = flags.label ? [...flags.label] : [];
|
|
158
311
|
// Show preview
|
|
159
312
|
this.log(`\n${styles.emphasis('Template Preview:')}`);
|
|
160
313
|
this.log(styles.muted(` Name: ${name}`));
|
|
@@ -179,6 +332,9 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
179
332
|
this.log(styles.muted(` - ${subtask}`));
|
|
180
333
|
}
|
|
181
334
|
}
|
|
335
|
+
if (labels.length > 0) {
|
|
336
|
+
this.log(styles.muted(` Default labels: ${labels.join(', ')}`));
|
|
337
|
+
}
|
|
182
338
|
// Confirm creation
|
|
183
339
|
const { confirm } = await inquirer.prompt([{
|
|
184
340
|
type: 'list',
|
|
@@ -202,11 +358,27 @@ export default class TicketTemplateCreate extends PMOCommand {
|
|
|
202
358
|
defaultCategory: category,
|
|
203
359
|
descriptionTemplate,
|
|
204
360
|
suggestedSubtasks: subtasks.map(title => ({ title })),
|
|
205
|
-
defaultLabels:
|
|
361
|
+
defaultLabels: labels,
|
|
206
362
|
});
|
|
207
363
|
this.log(styles.success(`\nCreated template "${styles.emphasis(template.name)}"`));
|
|
208
364
|
this.log(styles.muted(` ID: ${template.id}`));
|
|
209
365
|
this.log('');
|
|
210
366
|
this.log(styles.muted(`Create ticket from template: prlt ticket template apply ${template.id}`));
|
|
211
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Check if any non-default flags were provided (indicating non-interactive intent)
|
|
370
|
+
*/
|
|
371
|
+
hasNonDefaultFlags(flags) {
|
|
372
|
+
const nonDefaultFlags = [
|
|
373
|
+
'description',
|
|
374
|
+
'title-pattern',
|
|
375
|
+
'description-template',
|
|
376
|
+
'priority',
|
|
377
|
+
'category',
|
|
378
|
+
'subtask',
|
|
379
|
+
'ac',
|
|
380
|
+
'label',
|
|
381
|
+
];
|
|
382
|
+
return nonDefaultFlags.some(flag => flags[flag] !== undefined);
|
|
383
|
+
}
|
|
212
384
|
}
|
|
@@ -7,9 +7,10 @@ export default class TicketTemplateSave extends PMOCommand {
|
|
|
7
7
|
name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
8
|
};
|
|
9
9
|
static flags: {
|
|
10
|
+
'template-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
10
11
|
description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
-
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
12
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
14
|
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
15
|
};
|
|
15
16
|
execute(): Promise<void>;
|