@proletariat/cli 0.3.19 → 0.3.21

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 (81) hide show
  1. package/dist/commands/agent/login.js +2 -2
  2. package/dist/commands/agent/remove.d.ts +1 -0
  3. package/dist/commands/agent/remove.js +36 -28
  4. package/dist/commands/agent/shell.js +2 -2
  5. package/dist/commands/agent/staff/remove.d.ts +1 -0
  6. package/dist/commands/agent/staff/remove.js +36 -28
  7. package/dist/commands/agent/status.js +2 -2
  8. package/dist/commands/agent/temp/cleanup.js +10 -17
  9. package/dist/commands/agent/themes/add-names.d.ts +1 -0
  10. package/dist/commands/agent/themes/add-names.js +5 -1
  11. package/dist/commands/agent/visit.js +2 -2
  12. package/dist/commands/board/view.d.ts +15 -0
  13. package/dist/commands/board/view.js +136 -0
  14. package/dist/commands/config/index.js +6 -3
  15. package/dist/commands/epic/link/index.js +17 -0
  16. package/dist/commands/execution/config.d.ts +34 -0
  17. package/dist/commands/execution/config.js +433 -0
  18. package/dist/commands/execution/index.js +6 -1
  19. package/dist/commands/execution/kill.d.ts +12 -0
  20. package/dist/commands/execution/kill.js +17 -0
  21. package/dist/commands/execution/list.js +5 -4
  22. package/dist/commands/execution/logs.js +1 -0
  23. package/dist/commands/execution/view.d.ts +17 -0
  24. package/dist/commands/execution/view.js +288 -0
  25. package/dist/commands/phase/move.js +8 -0
  26. package/dist/commands/phase/template/apply.js +2 -2
  27. package/dist/commands/phase/template/create.js +67 -20
  28. package/dist/commands/phase/template/list.js +1 -1
  29. package/dist/commands/pr/index.js +6 -2
  30. package/dist/commands/pr/list.d.ts +17 -0
  31. package/dist/commands/pr/list.js +163 -0
  32. package/dist/commands/project/update.d.ts +19 -0
  33. package/dist/commands/project/update.js +163 -0
  34. package/dist/commands/roadmap/create.js +5 -0
  35. package/dist/commands/spec/delete.d.ts +18 -0
  36. package/dist/commands/spec/delete.js +111 -0
  37. package/dist/commands/spec/edit.d.ts +23 -0
  38. package/dist/commands/spec/edit.js +232 -0
  39. package/dist/commands/spec/index.js +5 -0
  40. package/dist/commands/status/create.js +38 -34
  41. package/dist/commands/status/list.js +5 -3
  42. package/dist/commands/template/phase/create.d.ts +1 -0
  43. package/dist/commands/template/phase/create.js +10 -1
  44. package/dist/commands/template/phase/index.js +4 -4
  45. package/dist/commands/template/ticket/create.d.ts +20 -0
  46. package/dist/commands/template/ticket/create.js +87 -0
  47. package/dist/commands/template/ticket/delete.d.ts +1 -1
  48. package/dist/commands/template/ticket/delete.js +4 -2
  49. package/dist/commands/template/ticket/save.d.ts +2 -0
  50. package/dist/commands/template/ticket/save.js +11 -0
  51. package/dist/commands/ticket/create.js +8 -1
  52. package/dist/commands/ticket/edit.js +1 -1
  53. package/dist/commands/ticket/list.d.ts +2 -0
  54. package/dist/commands/ticket/list.js +39 -2
  55. package/dist/commands/ticket/template/create.d.ts +9 -1
  56. package/dist/commands/ticket/template/create.js +224 -52
  57. package/dist/commands/ticket/template/save.d.ts +2 -1
  58. package/dist/commands/ticket/template/save.js +58 -7
  59. package/dist/commands/ticket/update.js +2 -2
  60. package/dist/commands/work/ready.js +8 -8
  61. package/dist/commands/work/spawn.js +32 -8
  62. package/dist/commands/work/watch.js +2 -0
  63. package/dist/lib/agents/commands.d.ts +7 -0
  64. package/dist/lib/agents/commands.js +11 -0
  65. package/dist/lib/agents/index.js +14 -4
  66. package/dist/lib/branch/index.js +24 -0
  67. package/dist/lib/execution/config.d.ts +2 -0
  68. package/dist/lib/execution/config.js +12 -0
  69. package/dist/lib/execution/runners.js +1 -2
  70. package/dist/lib/pmo/storage/epics.js +20 -10
  71. package/dist/lib/pmo/storage/helpers.d.ts +10 -0
  72. package/dist/lib/pmo/storage/helpers.js +59 -1
  73. package/dist/lib/pmo/storage/projects.js +20 -8
  74. package/dist/lib/pmo/storage/specs.js +23 -13
  75. package/dist/lib/pmo/storage/statuses.js +39 -18
  76. package/dist/lib/pmo/storage/subtasks.js +19 -8
  77. package/dist/lib/pmo/storage/tickets.js +27 -15
  78. package/dist/lib/pmo/utils.d.ts +4 -2
  79. package/dist/lib/pmo/utils.js +4 -2
  80. package/oclif.manifest.json +4037 -3234
  81. package/package.json +2 -4
@@ -88,40 +88,44 @@ export default class StatusCreate extends PMOCommand {
88
88
  default: flags.category || 'backlog',
89
89
  when: (ctx) => !ctx.flags.category || flags.interactive,
90
90
  });
91
- // Add color prompt
92
- resolver.addPrompt({
93
- flagName: 'color',
94
- type: 'input',
95
- message: 'Color (hex, optional):',
96
- default: flags.color,
97
- validate: (value) => {
98
- const v = value;
99
- if (!v)
100
- return true;
101
- return /^#[0-9A-Fa-f]{6}$/.test(v) || 'Invalid hex color (e.g., #FF0000)';
102
- },
103
- when: (ctx) => ctx.flags.color === undefined || flags.interactive,
104
- });
105
- // Add description prompt
106
- resolver.addPrompt({
107
- flagName: 'description',
108
- type: 'input',
109
- message: 'Description (optional):',
110
- default: flags.description,
111
- when: (ctx) => ctx.flags.description === undefined || flags.interactive,
112
- });
113
- // Add default prompt
114
- resolver.addPrompt({
115
- flagName: 'default',
116
- type: 'list',
117
- message: 'Set as default status for new tickets?',
118
- choices: () => [
119
- { name: 'No', value: false, command: 'prlt status create --json' },
120
- { name: 'Yes', value: true, command: 'prlt status create --default --json' },
121
- ],
122
- default: flags.default || false,
123
- when: (ctx) => ctx.flags.default === undefined || flags.interactive,
124
- });
91
+ // Optional prompts - only shown in interactive mode
92
+ // In JSON/machine mode, optional fields should be passed as flags or omitted
93
+ if (flags.interactive) {
94
+ // Add color prompt
95
+ resolver.addPrompt({
96
+ flagName: 'color',
97
+ type: 'input',
98
+ message: 'Color (hex, optional):',
99
+ default: flags.color,
100
+ validate: (value) => {
101
+ const v = value;
102
+ if (!v)
103
+ return true;
104
+ return /^#[0-9A-Fa-f]{6}$/.test(v) || 'Invalid hex color (e.g., #FF0000)';
105
+ },
106
+ when: (ctx) => ctx.flags.color === undefined,
107
+ });
108
+ // Add description prompt
109
+ resolver.addPrompt({
110
+ flagName: 'description',
111
+ type: 'input',
112
+ message: 'Description (optional):',
113
+ default: flags.description,
114
+ when: (ctx) => ctx.flags.description === undefined,
115
+ });
116
+ // Add default prompt
117
+ resolver.addPrompt({
118
+ flagName: 'default',
119
+ type: 'list',
120
+ message: 'Set as default status for new tickets?',
121
+ choices: () => [
122
+ { name: 'No', value: false, command: 'prlt status create --json' },
123
+ { name: 'Yes', value: true, command: 'prlt status create --default --json' },
124
+ ],
125
+ default: flags.default || false,
126
+ when: (ctx) => ctx.flags.default === undefined,
127
+ });
128
+ }
125
129
  // Resolve all flags
126
130
  const resolved = await resolver.resolve();
127
131
  const status = await this.storage.createStatus(projectId, {
@@ -35,7 +35,11 @@ export default class StatusList extends PMOCommand {
35
35
  if (!project?.workflowId) {
36
36
  this.error(`Project "${projectId}" has no workflow assigned.`);
37
37
  }
38
- const statuses = await this.storage.listStatuses(project.workflowId);
38
+ const allStatuses = await this.storage.listStatuses(project.workflowId);
39
+ // Apply category filter if specified
40
+ const statuses = flags.category
41
+ ? allStatuses.filter(s => s.category === flags.category)
42
+ : allStatuses;
39
43
  if (jsonMode) {
40
44
  this.log(JSON.stringify(statuses, null, 2));
41
45
  return;
@@ -59,8 +63,6 @@ export default class StatusList extends PMOCommand {
59
63
  canceled: '🚫',
60
64
  };
61
65
  for (const category of STATE_CATEGORY_ORDER) {
62
- if (flags.category && flags.category !== category)
63
- continue;
64
66
  const categoryStatuses = grouped.get(category);
65
67
  if (!categoryStatuses || categoryStatuses.length === 0)
66
68
  continue;
@@ -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 prompt configuration as JSON (for AI agents/scripts)',
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);
@@ -30,10 +30,10 @@ export default class TemplatePhase extends Command {
30
30
  message: 'What would you like to do?',
31
31
  choices: () => [
32
32
  { name: 'List phase templates', value: 'list', command: 'prlt template phase list --json' },
33
- { name: 'Apply a phase template to project', value: 'apply', command: 'prlt phase template apply --json' },
34
- { name: 'Create a new phase template', value: 'create', command: 'prlt phase template create --json' },
35
- { name: 'Update a phase template', value: 'update', command: 'prlt phase template update --json' },
36
- { name: 'Delete a phase template', value: 'delete', command: 'prlt phase template delete --json' },
33
+ { name: 'Apply a phase template to project', value: 'apply', command: 'prlt template phase apply --json' },
34
+ { name: 'Create a new phase template', value: 'create', command: 'prlt template phase create --json' },
35
+ { name: 'Update a phase template', value: 'update', command: 'prlt template phase update --json' },
36
+ { name: 'Delete a phase template', value: 'delete', command: 'prlt template phase delete --json' },
37
37
  ],
38
38
  });
39
39
  // In JSON mode, this outputs the prompt and exits
@@ -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
+ }
@@ -3,7 +3,7 @@ export default class TemplateTicketDelete extends Command {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {
6
- id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
6
+ id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
7
  };
8
8
  static flags: {
9
9
  force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -8,7 +8,7 @@ export default class TemplateTicketDelete extends Command {
8
8
  static args = {
9
9
  id: Args.string({
10
10
  description: 'Template ID to delete',
11
- required: true,
11
+ required: false,
12
12
  }),
13
13
  };
14
14
  static flags = {
@@ -24,7 +24,9 @@ export default class TemplateTicketDelete extends Command {
24
24
  };
25
25
  async run() {
26
26
  const { args, flags } = await this.parse(TemplateTicketDelete);
27
- const cmdArgs = [args.id];
27
+ const cmdArgs = [];
28
+ if (args.id)
29
+ cmdArgs.push(args.id);
28
30
  if (flags.force)
29
31
  cmdArgs.push('--force');
30
32
  if (flags.json)
@@ -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
  }
@@ -11,7 +11,7 @@ export default class TicketCreate extends PMOCommand {
11
11
  static examples = [
12
12
  '<%= config.bin %> <%= command.id %>',
13
13
  '<%= config.bin %> <%= command.id %> --title "Fix login bug" --column Backlog',
14
- '<%= config.bin %> <%= command.id %> -t "Add feature" -c "In Progress" -p HIGH',
14
+ '<%= config.bin %> <%= command.id %> -t "Add feature" -c "In Progress" -p P1',
15
15
  '<%= config.bin %> <%= command.id %> --project mobile-app -t "New feature"',
16
16
  '<%= config.bin %> <%= command.id %> --epic EPIC-001 -t "Implement auth flow"',
17
17
  '<%= config.bin %> <%= command.id %> --json # Output column choices as JSON',
@@ -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',
@@ -9,7 +9,7 @@ export default class TicketEdit extends PMOCommand {
9
9
  static examples = [
10
10
  '<%= config.bin %> <%= command.id %> TICK-001',
11
11
  '<%= config.bin %> <%= command.id %> TICK-001 --title "New title"',
12
- '<%= config.bin %> <%= command.id %> TICK-001 --priority HIGH --category bug',
12
+ '<%= config.bin %> <%= command.id %> TICK-001 --priority P1 --category bug',
13
13
  '<%= config.bin %> <%= command.id %> TICK-001 --add-subtask "Implement feature" --add-subtask "Write tests"',
14
14
  '<%= config.bin %> <%= command.id %> TICK-001 --owner "john" --assignee "agent-1"',
15
15
  '<%= config.bin %> <%= command.id %> # Interactive mode',
@@ -10,6 +10,8 @@ export default class TicketList extends Command {
10
10
  format: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
11
  all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
12
  'group-by': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
13
+ limit: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
+ offset: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
15
  machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
16
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
17
  project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -10,13 +10,15 @@ export default class TicketList extends Command {
10
10
  static examples = [
11
11
  '<%= config.bin %> <%= command.id %>',
12
12
  '<%= config.bin %> <%= command.id %> --column Backlog',
13
- '<%= config.bin %> <%= command.id %> --priority URGENT',
13
+ '<%= config.bin %> <%= command.id %> --priority P0',
14
14
  '<%= config.bin %> <%= command.id %> --category bug',
15
15
  '<%= config.bin %> <%= command.id %> --search "login"',
16
16
  '<%= config.bin %> <%= command.id %> --project mobile-app',
17
17
  '<%= config.bin %> <%= command.id %> --all',
18
18
  '<%= config.bin %> <%= command.id %> --all --group-by priority',
19
19
  '<%= config.bin %> <%= command.id %> -g priority',
20
+ '<%= config.bin %> <%= command.id %> --limit 10',
21
+ '<%= config.bin %> <%= command.id %> --limit 10 --offset 20',
20
22
  ];
21
23
  static flags = {
22
24
  ...pmoBaseFlags,
@@ -53,6 +55,15 @@ export default class TicketList extends Command {
53
55
  options: ['status', 'priority'],
54
56
  default: 'status',
55
57
  }),
58
+ limit: Flags.integer({
59
+ char: 'l',
60
+ description: 'Maximum number of tickets to display',
61
+ min: 1,
62
+ }),
63
+ offset: Flags.integer({
64
+ description: 'Skip first N tickets (for pagination)',
65
+ min: 0,
66
+ }),
56
67
  };
57
68
  async run() {
58
69
  const { flags } = await this.parse(TicketList);
@@ -85,7 +96,33 @@ export default class TicketList extends Command {
85
96
  }
86
97
  // Determine projectId for the query
87
98
  const projectId = flags.all ? undefined : (filter.projectId || undefined);
88
- const tickets = await pmoContext.storage.listTickets(projectId, filter);
99
+ // Validate project if specified (not in --all mode)
100
+ if (flags.project && !flags.all) {
101
+ const project = await pmoContext.storage.getProject(flags.project);
102
+ if (!project) {
103
+ const allProjects = await pmoContext.storage.listProjectSummaries();
104
+ const validProjectIds = allProjects.map(p => p.id);
105
+ this.error(`Project "${flags.project}" not found. Valid projects: ${validProjectIds.join(', ')}`);
106
+ }
107
+ }
108
+ // Validate column if specified (requires knowing the project)
109
+ if (flags.column && !flags.all) {
110
+ // Get the project board to validate the column
111
+ const targetProjectId = projectId || (await pmoContext.storage.listProjectSummaries())[0]?.id;
112
+ if (targetProjectId) {
113
+ const board = await pmoContext.storage.getBoard(targetProjectId);
114
+ const validColumns = board.columns.map(c => c.name);
115
+ if (!validColumns.includes(flags.column)) {
116
+ this.error(`Column "${flags.column}" not found. Valid columns: ${validColumns.join(', ')}`);
117
+ }
118
+ }
119
+ }
120
+ let tickets = await pmoContext.storage.listTickets(projectId, filter);
121
+ // Apply pagination
122
+ if (flags.offset)
123
+ tickets = tickets.slice(flags.offset);
124
+ if (flags.limit)
125
+ tickets = tickets.slice(0, flags.limit);
89
126
  if (tickets.length === 0) {
90
127
  this.log(styles.warning('No tickets found.'));
91
128
  return;
@@ -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
- machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
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
  }