@proletariat/cli 0.3.34 → 0.3.35

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 (118) hide show
  1. package/dist/commands/agent/auth.d.ts +3 -1
  2. package/dist/commands/agent/auth.js +8 -11
  3. package/dist/commands/agent/index.js +11 -2
  4. package/dist/commands/agent/staff/add.d.ts +1 -0
  5. package/dist/commands/agent/staff/add.js +1 -0
  6. package/dist/commands/agent/staff/index.d.ts +15 -0
  7. package/dist/commands/agent/staff/index.js +83 -0
  8. package/dist/commands/agent/staff/list.d.ts +1 -0
  9. package/dist/commands/agent/staff/list.js +1 -0
  10. package/dist/commands/agent/staff/remove.d.ts +1 -0
  11. package/dist/commands/agent/staff/remove.js +1 -0
  12. package/dist/commands/agent/themes/add-names.d.ts +1 -0
  13. package/dist/commands/agent/themes/add-names.js +1 -0
  14. package/dist/commands/agent/themes/create.d.ts +1 -0
  15. package/dist/commands/agent/themes/create.js +1 -0
  16. package/dist/commands/agent/themes/index.d.ts +10 -0
  17. package/dist/commands/agent/themes/index.js +144 -0
  18. package/dist/commands/agent/themes/list.d.ts +1 -0
  19. package/dist/commands/agent/themes/list.js +1 -0
  20. package/dist/commands/agent/themes/set.d.ts +1 -0
  21. package/dist/commands/agent/themes/set.js +1 -0
  22. package/dist/commands/agents/themes/add-names.d.ts +1 -0
  23. package/dist/commands/agents/themes/add-names.js +1 -0
  24. package/dist/commands/agents/themes/create.d.ts +1 -0
  25. package/dist/commands/agents/themes/create.js +1 -0
  26. package/dist/commands/agents/themes/list.d.ts +1 -0
  27. package/dist/commands/agents/themes/list.js +1 -0
  28. package/dist/commands/category/list.js +1 -1
  29. package/dist/commands/label/create.d.ts +20 -0
  30. package/dist/commands/label/create.js +56 -0
  31. package/dist/commands/label/delete.d.ts +17 -0
  32. package/dist/commands/label/delete.js +31 -0
  33. package/dist/commands/label/group/create.d.ts +20 -0
  34. package/dist/commands/label/group/create.js +54 -0
  35. package/dist/commands/label/group/list.d.ts +14 -0
  36. package/dist/commands/label/group/list.js +51 -0
  37. package/dist/commands/label/index.d.ts +15 -0
  38. package/dist/commands/label/index.js +58 -0
  39. package/dist/commands/label/list.d.ts +16 -0
  40. package/dist/commands/label/list.js +82 -0
  41. package/dist/commands/link/list.js +3 -2
  42. package/dist/commands/mcp-server.js +2 -1
  43. package/dist/commands/phase/template/apply.d.ts +26 -0
  44. package/dist/commands/phase/template/apply.js +14 -0
  45. package/dist/commands/phase/template/create.d.ts +23 -0
  46. package/dist/commands/phase/template/create.js +14 -0
  47. package/dist/commands/phase/template/delete.d.ts +18 -0
  48. package/dist/commands/phase/template/delete.js +61 -0
  49. package/dist/commands/phase/template/list.d.ts +17 -0
  50. package/dist/commands/phase/template/list.js +88 -0
  51. package/dist/commands/phase/template/update.d.ts +1 -0
  52. package/dist/commands/phase/template/update.js +1 -0
  53. package/dist/commands/priority/add.js +1 -1
  54. package/dist/commands/project/update.js +0 -2
  55. package/dist/commands/roadmap/generate.js +1 -2
  56. package/dist/commands/session/health.js +1 -1
  57. package/dist/commands/spec/link/depends.d.ts +18 -0
  58. package/dist/commands/spec/link/depends.js +86 -0
  59. package/dist/commands/spec/link/index.d.ts +17 -0
  60. package/dist/commands/spec/link/index.js +92 -0
  61. package/dist/commands/spec/link/remove.d.ts +18 -0
  62. package/dist/commands/spec/link/remove.js +90 -0
  63. package/dist/commands/support/logs.js +2 -2
  64. package/dist/commands/template/apply.js +5 -4
  65. package/dist/commands/template/create.js +1 -1
  66. package/dist/commands/ticket/link/block.d.ts +15 -0
  67. package/dist/commands/ticket/link/block.js +95 -0
  68. package/dist/commands/ticket/link/index.d.ts +14 -0
  69. package/dist/commands/ticket/link/index.js +96 -0
  70. package/dist/commands/ticket/list.d.ts +1 -0
  71. package/dist/commands/ticket/list.js +6 -0
  72. package/dist/commands/ticket/resolve.js +1 -1
  73. package/dist/commands/ticket/template/apply.d.ts +26 -0
  74. package/dist/commands/ticket/template/apply.js +14 -0
  75. package/dist/commands/ticket/template/delete.d.ts +18 -0
  76. package/dist/commands/ticket/template/delete.js +61 -0
  77. package/dist/commands/ticket/template/list.d.ts +17 -0
  78. package/dist/commands/ticket/template/list.js +77 -0
  79. package/dist/commands/ticket/template/save.d.ts +17 -0
  80. package/dist/commands/ticket/template/save.js +97 -0
  81. package/dist/commands/ticket/view.d.ts +1 -0
  82. package/dist/commands/ticket/view.js +1 -0
  83. package/dist/commands/work/ready.js +17 -0
  84. package/dist/commands/work/resolve.js +1 -1
  85. package/dist/commands/work/spawn.js +4 -4
  86. package/dist/commands/work/start.d.ts +1 -0
  87. package/dist/commands/work/start.js +52 -17
  88. package/dist/lib/database/index.d.ts +1 -1
  89. package/dist/lib/database/index.js +20 -0
  90. package/dist/lib/execution/devcontainer.js +3 -1
  91. package/dist/lib/execution/runners.d.ts +7 -2
  92. package/dist/lib/execution/runners.js +18 -10
  93. package/dist/lib/execution/types.d.ts +1 -0
  94. package/dist/lib/flags/resolver.js +1 -0
  95. package/dist/lib/mcp/helpers.d.ts +1 -2
  96. package/dist/lib/mcp/tools/diet.js +1 -0
  97. package/dist/lib/mcp/tools/index.d.ts +1 -0
  98. package/dist/lib/mcp/tools/index.js +1 -0
  99. package/dist/lib/mcp/tools/label.d.ts +6 -0
  100. package/dist/lib/mcp/tools/label.js +338 -0
  101. package/dist/lib/mcp/tools/ticket.js +53 -17
  102. package/dist/lib/multiline-input.js +6 -18
  103. package/dist/lib/pmo/base-command.d.ts +0 -1
  104. package/dist/lib/pmo/base-command.js +0 -1
  105. package/dist/lib/pmo/schema.d.ts +6 -0
  106. package/dist/lib/pmo/schema.js +44 -0
  107. package/dist/lib/pmo/storage/base.d.ts +6 -0
  108. package/dist/lib/pmo/storage/base.js +116 -2
  109. package/dist/lib/pmo/storage/index.d.ts +23 -1
  110. package/dist/lib/pmo/storage/index.js +59 -1
  111. package/dist/lib/pmo/storage/labels.d.ts +55 -0
  112. package/dist/lib/pmo/storage/labels.js +346 -0
  113. package/dist/lib/pmo/storage/tickets.js +17 -0
  114. package/dist/lib/pmo/storage/types.d.ts +24 -0
  115. package/dist/lib/pmo/types.d.ts +44 -0
  116. package/dist/lib/pmo/utils.js +1 -1
  117. package/oclif.manifest.json +5702 -3660
  118. package/package.json +1 -1
@@ -17,7 +17,9 @@ export default class Auth extends Command {
17
17
  */
18
18
  private createVolume;
19
19
  /**
20
- * Check if valid credentials exist in the volume
20
+ * Check if valid credentials exist in the volume.
21
+ * Don't check expiration - access tokens are short-lived but Claude Code
22
+ * handles token refresh internally using stored refresh tokens.
21
23
  */
22
24
  private credentialsExist;
23
25
  /**
@@ -47,19 +47,16 @@ export default class Auth extends Command {
47
47
  }
48
48
  }
49
49
  /**
50
- * Check if valid credentials exist in the volume
50
+ * Check if valid credentials exist in the volume.
51
+ * Don't check expiration - access tokens are short-lived but Claude Code
52
+ * handles token refresh internally using stored refresh tokens.
51
53
  */
52
54
  credentialsExist() {
53
55
  try {
54
56
  const result = execSync(`docker run --rm -v ${CLAUDE_CREDENTIALS_VOLUME}:/data alpine cat /data/.credentials.json 2>/dev/null`, { stdio: 'pipe', encoding: 'utf-8' });
55
- // Parse and validate the credentials
56
57
  const creds = JSON.parse(result);
57
- if (creds.claudeAiOauth?.accessToken && creds.claudeAiOauth?.expiresAt) {
58
- // Check if expired
59
- const expiresAt = creds.claudeAiOauth.expiresAt;
60
- if (expiresAt > Date.now()) {
61
- return true;
62
- }
58
+ if (creds.claudeAiOauth?.accessToken) {
59
+ return true;
63
60
  }
64
61
  return false;
65
62
  }
@@ -93,8 +90,7 @@ export default class Auth extends Command {
93
90
  this.log(colors.primary('🔐 Starting Claude Code authentication...'));
94
91
  this.log('');
95
92
  this.log(colors.text('A temporary container will start with Claude Code.'));
96
- this.log(colors.text('When prompted, type: /login'));
97
- this.log(colors.text('Then complete the browser authentication.'));
93
+ this.log(colors.text('Complete the browser authentication when prompted.'));
98
94
  this.log('');
99
95
  this.log(colors.textSecondary('Press Ctrl+C to cancel.'));
100
96
  this.log('');
@@ -108,7 +104,8 @@ export default class Auth extends Command {
108
104
  'node:20',
109
105
  'bash', '-c',
110
106
  // Install as root, then run claude as node user (so credentials have correct ownership)
111
- 'npm install -g @anthropic-ai/claude-code@latest --silent 2>/dev/null && chown -R node:node /home/node/.claude && echo "" && echo "Type: /login" && echo "" && su -s /bin/bash -c "HOME=/home/node CLAUDE_CONFIG_DIR=/home/node/.claude claude" node'
107
+ // Pass "/login" as initial prompt so user doesn't have to type it manually
108
+ 'npm install -g @anthropic-ai/claude-code@latest --silent 2>/dev/null && chown -R node:node /home/node/.claude && su -s /bin/bash -c "HOME=/home/node CLAUDE_CONFIG_DIR=/home/node/.claude claude \\"/login\\"" node'
112
109
  ], { stdio: 'inherit' });
113
110
  return result.status === 0;
114
111
  }
@@ -45,6 +45,7 @@ export default class Agent extends PMOCommand {
45
45
  { name: '🗑️ Remove agent', value: 'remove', command: 'prlt agent remove --machine' },
46
46
  // Management group
47
47
  { name: '👔 Manage staff agents', value: 'staff', command: 'prlt agent staff --machine' },
48
+ { name: '⏱️ Manage temp agents', value: 'temp', command: 'prlt agent temp --machine' },
48
49
  { name: '🧹 Cleanup agents', value: 'cleanup', command: 'prlt agent cleanup --machine' },
49
50
  { name: '🎨 Manage themes', value: 'themes', command: 'prlt agent themes --machine' },
50
51
  // Operations group
@@ -89,11 +90,19 @@ export default class Agent extends PMOCommand {
89
90
  break;
90
91
  }
91
92
  case 'staff': {
92
- const { default: StaffCommand } = await import('../staff/index.js');
93
+ const { default: StaffCommand } = await import('./staff/index.js');
93
94
  const cmd = new StaffCommand([], this.config);
94
95
  await cmd.run();
95
96
  break;
96
97
  }
98
+ case 'temp': {
99
+ // @ts-expect-error -- temp subcommand not yet implemented
100
+ // eslint-disable-next-line import/no-unresolved -- temp subcommand not yet implemented
101
+ const { default: TempCommand } = await import('./temp/index.js');
102
+ const cmd = new TempCommand([], this.config);
103
+ await cmd.run();
104
+ break;
105
+ }
97
106
  case 'cleanup': {
98
107
  const { default: CleanupCommand } = await import('./cleanup.js');
99
108
  const cmd = new CleanupCommand([], this.config);
@@ -101,7 +110,7 @@ export default class Agent extends PMOCommand {
101
110
  break;
102
111
  }
103
112
  case 'themes': {
104
- const { default: ThemeCommand } = await import('../theme/index.js');
113
+ const { default: ThemeCommand } = await import('./themes/index.js');
105
114
  const cmd = new ThemeCommand([], this.config);
106
115
  await cmd.run();
107
116
  break;
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/add.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/add.js';
@@ -0,0 +1,15 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class AgentStaff extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ 'no-interactive': import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ protected getPMOOptions(): {
12
+ promptIfMultiple: boolean;
13
+ };
14
+ execute(): Promise<void>;
15
+ }
@@ -0,0 +1,83 @@
1
+ import { Flags } from '@oclif/core';
2
+ import inquirer from 'inquirer';
3
+ import { colors } from '../../../lib/colors.js';
4
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
5
+ import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
6
+ export default class AgentStaff extends PMOCommand {
7
+ static description = 'Manage staff (persistent) agents';
8
+ static examples = [
9
+ '<%= config.bin %> <%= command.id %> list',
10
+ '<%= config.bin %> <%= command.id %> add',
11
+ '<%= config.bin %> <%= command.id %> remove camry',
12
+ ];
13
+ static flags = {
14
+ ...pmoBaseFlags,
15
+ 'no-interactive': Flags.boolean({
16
+ description: 'Alias for --json flag',
17
+ default: false,
18
+ }),
19
+ };
20
+ getPMOOptions() {
21
+ return { promptIfMultiple: false };
22
+ }
23
+ async execute() {
24
+ const { flags } = await this.parse(AgentStaff);
25
+ const jsonMode = shouldOutputJson(flags);
26
+ const menuChoices = [
27
+ { name: 'List staff agents', value: 'list', command: 'prlt agent staff list --machine' },
28
+ { name: 'Add staff agent', value: 'add', command: 'prlt agent staff add --machine' },
29
+ { name: 'Remove staff agent', value: 'remove', command: 'prlt agent staff remove --machine' },
30
+ { name: 'Cancel', value: 'cancel', command: '' },
31
+ ];
32
+ const message = 'What would you like to do?';
33
+ if (jsonMode) {
34
+ outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('agent staff', flags));
35
+ return;
36
+ }
37
+ this.log(colors.primary('Staff Agents'));
38
+ this.log(colors.textMuted('Persistent agents with dedicated worktrees.\n'));
39
+ const { action } = await this.prompt([{
40
+ type: 'list',
41
+ name: 'action',
42
+ message,
43
+ choices: [
44
+ { name: '📋 ' + menuChoices[0].name, value: menuChoices[0].value },
45
+ { name: '➕ ' + menuChoices[1].name, value: menuChoices[1].value },
46
+ { name: '🗑️ ' + menuChoices[2].name, value: menuChoices[2].value },
47
+ new inquirer.Separator(),
48
+ { name: '❌ ' + menuChoices[3].name, value: menuChoices[3].value },
49
+ ]
50
+ }], null);
51
+ if (action === 'cancel') {
52
+ this.log(colors.textMuted('Operation cancelled.'));
53
+ return;
54
+ }
55
+ try {
56
+ switch (action) {
57
+ case 'list': {
58
+ const { default: ListCommand } = await import('./list.js');
59
+ const cmd = new ListCommand([], this.config);
60
+ await cmd.run();
61
+ break;
62
+ }
63
+ case 'add': {
64
+ const { default: AddCommand } = await import('./add.js');
65
+ const cmd = new AddCommand([], this.config);
66
+ await cmd.run();
67
+ break;
68
+ }
69
+ case 'remove': {
70
+ const { default: RemoveCommand } = await import('./remove.js');
71
+ const cmd = new RemoveCommand([], this.config);
72
+ await cmd.run();
73
+ break;
74
+ }
75
+ default:
76
+ this.error(`Unknown action: ${action}`);
77
+ }
78
+ }
79
+ catch (error) {
80
+ this.error(`Failed to execute staff ${action}: ${error instanceof Error ? error.message : String(error)}`);
81
+ }
82
+ }
83
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/list.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/list.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/remove.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../staff/remove.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/add-names.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/add-names.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/create.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/create.js';
@@ -0,0 +1,10 @@
1
+ import { PromptCommand } from '../../../lib/prompt-command.js';
2
+ export default class AgentThemes extends PromptCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ }
@@ -0,0 +1,144 @@
1
+ import inquirer from 'inquirer';
2
+ import chalk from 'chalk';
3
+ import { PromptCommand } from '../../../lib/prompt-command.js';
4
+ import { machineOutputFlags } from '../../../lib/pmo/index.js';
5
+ import { getWorkspaceInfo } from '../../../lib/agents/commands.js';
6
+ import { ensureBuiltinThemes } from '../../../lib/themes.js';
7
+ import { getThemes, getAvailableThemeNames } from '../../../lib/database/index.js';
8
+ import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
9
+ export default class AgentThemes extends PromptCommand {
10
+ static description = 'Manage agent naming themes';
11
+ static examples = [
12
+ '<%= config.bin %> <%= command.id %> list',
13
+ '<%= config.bin %> <%= command.id %> create greek-gods',
14
+ '<%= config.bin %> <%= command.id %> add-names greek-gods zeus athena',
15
+ ];
16
+ static flags = {
17
+ ...machineOutputFlags,
18
+ };
19
+ async run() {
20
+ const { flags } = await this.parse(AgentThemes);
21
+ const jsonMode = shouldOutputJson(flags);
22
+ const menuChoices = [
23
+ { id: 'list', name: 'List themes', command: 'prlt agent themes list --format json' },
24
+ { id: 'create', name: 'Create a new theme', command: 'prlt agent themes create --machine' },
25
+ { id: 'add-names', name: 'Add names to a theme', command: 'prlt agent themes add-names --machine' },
26
+ { id: 'cancel', name: 'Cancel', command: '' },
27
+ ];
28
+ const message = 'What would you like to do?';
29
+ if (jsonMode) {
30
+ outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices.map(c => ({
31
+ name: c.name,
32
+ value: c.id,
33
+ command: c.command,
34
+ }))), createMetadata('agent themes', flags));
35
+ return;
36
+ }
37
+ this.log(chalk.bold('\nAgent Themes'));
38
+ this.log(chalk.dim('Optional themed name pools for your agents.\n'));
39
+ const { action } = await this.prompt([{
40
+ type: 'list',
41
+ name: 'action',
42
+ message,
43
+ choices: [
44
+ ...menuChoices.slice(0, 3).map(c => ({ name: c.name, value: c.id })),
45
+ new inquirer.Separator(),
46
+ { name: menuChoices[3].name, value: menuChoices[3].id }
47
+ ]
48
+ }], null);
49
+ if (action === 'cancel') {
50
+ this.log(chalk.dim('Cancelled.'));
51
+ return;
52
+ }
53
+ try {
54
+ switch (action) {
55
+ case 'list': {
56
+ const { default: ListCommand } = await import('./list.js');
57
+ const cmd = new ListCommand([], this.config);
58
+ await cmd.run();
59
+ break;
60
+ }
61
+ case 'create': {
62
+ const { themeName } = await this.prompt([{
63
+ type: 'input',
64
+ name: 'themeName',
65
+ message: 'Theme name:',
66
+ validate: (input) => {
67
+ if (!input.trim())
68
+ return 'Theme name is required';
69
+ return true;
70
+ }
71
+ }], null);
72
+ const normalized = themeName.trim().toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
73
+ if (themeName.trim() !== normalized) {
74
+ this.log(chalk.blue(`Normalized: ${themeName.trim()} → ${normalized}`));
75
+ }
76
+ const { default: CreateCommand } = await import('./create.js');
77
+ const cmd = new CreateCommand([normalized], this.config);
78
+ await cmd.run();
79
+ const { addNamesNow } = await this.prompt([{
80
+ type: 'list',
81
+ name: 'addNamesNow',
82
+ message: 'Add names to this theme now?',
83
+ choices: [
84
+ { name: 'Yes', value: true },
85
+ { name: 'No', value: false },
86
+ ],
87
+ }], null);
88
+ if (addNamesNow) {
89
+ const { names } = await this.prompt([{
90
+ type: 'input',
91
+ name: 'names',
92
+ message: 'Enter names (space-separated):',
93
+ validate: (input) => input.trim() ? true : 'At least one name is required'
94
+ }], null);
95
+ const addArgs = [normalized, ...names.trim().split(/\s+/)];
96
+ const { default: AddNamesCommand } = await import('./add-names.js');
97
+ const addCmd = new AddNamesCommand(addArgs, this.config);
98
+ await addCmd.run();
99
+ }
100
+ break;
101
+ }
102
+ case 'add-names': {
103
+ const workspaceInfo = getWorkspaceInfo();
104
+ ensureBuiltinThemes(workspaceInfo.path);
105
+ const themes = getThemes(workspaceInfo.path);
106
+ if (themes.length === 0) {
107
+ this.log(chalk.yellow('No themes found. Create one first.'));
108
+ return;
109
+ }
110
+ const themeChoices = themes.map(t => {
111
+ const availableNames = getAvailableThemeNames(workspaceInfo.path, t.id);
112
+ const builtinTag = t.builtin ? chalk.dim(' [built-in]') : '';
113
+ return {
114
+ name: `${t.display_name}${builtinTag} ${chalk.dim(`(${availableNames.length} names available)`)}`,
115
+ value: t.id
116
+ };
117
+ });
118
+ const { selectedTheme } = await this.prompt([{
119
+ type: 'list',
120
+ name: 'selectedTheme',
121
+ message: 'Select theme to add names to:',
122
+ choices: themeChoices
123
+ }], null);
124
+ const { names } = await this.prompt([{
125
+ type: 'input',
126
+ name: 'names',
127
+ message: 'Names to add (space-separated):',
128
+ validate: (input) => input.trim() ? true : 'At least one name is required'
129
+ }], null);
130
+ const addArgs = [selectedTheme, ...names.trim().split(/\s+/)];
131
+ const { default: AddNamesCommand } = await import('./add-names.js');
132
+ const cmd = new AddNamesCommand(addArgs, this.config);
133
+ await cmd.run();
134
+ break;
135
+ }
136
+ default:
137
+ this.error(`Unknown action: ${action}`);
138
+ }
139
+ }
140
+ catch (error) {
141
+ this.error(error instanceof Error ? error.message : String(error));
142
+ }
143
+ }
144
+ }
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/list.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/list.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/set.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/set.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/add-names.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/add-names.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/create.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/create.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/list.js';
@@ -0,0 +1 @@
1
+ export { default } from '../../theme/list.js';
@@ -36,7 +36,7 @@ export default class CategoryList extends PMOCommand {
36
36
  async execute() {
37
37
  const { flags } = await this.parse(CategoryList);
38
38
  const categoryType = flags.type;
39
- let filter = { type: categoryType };
39
+ const filter = { type: categoryType };
40
40
  if (flags.builtin)
41
41
  filter.isBuiltin = true;
42
42
  if (flags.custom)
@@ -0,0 +1,20 @@
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class LabelCreate extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ color: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ group: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ };
16
+ protected getPMOOptions(): {
17
+ promptIfMultiple: boolean;
18
+ };
19
+ execute(): Promise<void>;
20
+ }
@@ -0,0 +1,56 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
3
+ import { styles } from '../../lib/styles.js';
4
+ export default class LabelCreate extends PMOCommand {
5
+ static description = 'Create a new label';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> my-label',
8
+ '<%= config.bin %> <%= command.id %> urgent --color "#ff0000" --group type',
9
+ '<%= config.bin %> <%= command.id %> frontend --group area --description "Frontend work"',
10
+ ];
11
+ static args = {
12
+ name: Args.string({
13
+ description: 'Label name',
14
+ required: true,
15
+ }),
16
+ };
17
+ static flags = {
18
+ ...pmoBaseFlags,
19
+ color: Flags.string({
20
+ char: 'c',
21
+ description: 'Label color (hex, e.g. #ff0000)',
22
+ }),
23
+ description: Flags.string({
24
+ char: 'd',
25
+ description: 'Label description',
26
+ }),
27
+ group: Flags.string({
28
+ char: 'g',
29
+ description: 'Label group ID to add this label to',
30
+ }),
31
+ };
32
+ getPMOOptions() {
33
+ return { promptIfMultiple: false };
34
+ }
35
+ async execute() {
36
+ const { args, flags } = await this.parse(LabelCreate);
37
+ const label = await this.storage.createLabel({
38
+ name: args.name,
39
+ color: flags.color,
40
+ description: flags.description,
41
+ groupId: flags.group,
42
+ });
43
+ if (flags.machine || flags.json) {
44
+ this.log(JSON.stringify(label, null, 2));
45
+ return;
46
+ }
47
+ this.log(styles.success(`\nCreated label: ${label.name} (${label.id})`));
48
+ if (label.groupName) {
49
+ this.log(styles.muted(` Group: ${label.groupName}`));
50
+ }
51
+ if (label.color) {
52
+ this.log(styles.muted(` Color: ${label.color}`));
53
+ }
54
+ this.log('');
55
+ }
56
+ }
@@ -0,0 +1,17 @@
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class LabelDelete extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
+ };
13
+ protected getPMOOptions(): {
14
+ promptIfMultiple: boolean;
15
+ };
16
+ execute(): Promise<void>;
17
+ }
@@ -0,0 +1,31 @@
1
+ import { Args } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
3
+ import { styles } from '../../lib/styles.js';
4
+ export default class LabelDelete extends PMOCommand {
5
+ static description = 'Delete a label (removes from all tickets)';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> my-label',
8
+ ];
9
+ static args = {
10
+ id: Args.string({
11
+ description: 'Label ID to delete',
12
+ required: true,
13
+ }),
14
+ };
15
+ static flags = {
16
+ ...pmoBaseFlags,
17
+ };
18
+ getPMOOptions() {
19
+ return { promptIfMultiple: false };
20
+ }
21
+ async execute() {
22
+ const { args, flags } = await this.parse(LabelDelete);
23
+ await this.storage.deleteLabel(args.id);
24
+ if (flags.machine || flags.json) {
25
+ this.log(JSON.stringify({ success: true, deleted: args.id }));
26
+ return;
27
+ }
28
+ this.log(styles.success(`\nDeleted label: ${args.id}`));
29
+ this.log('');
30
+ }
31
+ }
@@ -0,0 +1,20 @@
1
+ import { PMOCommand } from '../../../lib/pmo/index.js';
2
+ export default class LabelGroupCreate extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ name: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ static flags: {
9
+ description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ exclusive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ required: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
+ machine: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ };
16
+ protected getPMOOptions(): {
17
+ promptIfMultiple: boolean;
18
+ };
19
+ execute(): Promise<void>;
20
+ }
@@ -0,0 +1,54 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
3
+ import { styles } from '../../../lib/styles.js';
4
+ export default class LabelGroupCreate extends PMOCommand {
5
+ static description = 'Create a new label group';
6
+ static examples = [
7
+ '<%= config.bin %> <%= command.id %> Priority',
8
+ '<%= config.bin %> <%= command.id %> Severity --exclusive --required',
9
+ '<%= config.bin %> <%= command.id %> Tags --no-exclusive --description "Free-form tags"',
10
+ ];
11
+ static args = {
12
+ name: Args.string({
13
+ description: 'Group name',
14
+ required: true,
15
+ }),
16
+ };
17
+ static flags = {
18
+ ...pmoBaseFlags,
19
+ description: Flags.string({
20
+ char: 'd',
21
+ description: 'Group description',
22
+ }),
23
+ exclusive: Flags.boolean({
24
+ description: 'Only one label from this group per ticket (default: true)',
25
+ default: true,
26
+ allowNo: true,
27
+ }),
28
+ required: Flags.boolean({
29
+ description: 'Must have one label from this group',
30
+ default: false,
31
+ }),
32
+ };
33
+ getPMOOptions() {
34
+ return { promptIfMultiple: false };
35
+ }
36
+ async execute() {
37
+ const { args, flags } = await this.parse(LabelGroupCreate);
38
+ const group = await this.storage.createLabelGroup({
39
+ name: args.name,
40
+ description: flags.description,
41
+ isExclusive: flags.exclusive,
42
+ isRequired: flags.required,
43
+ });
44
+ if (flags.machine || flags.json) {
45
+ this.log(JSON.stringify(group, null, 2));
46
+ return;
47
+ }
48
+ const exclusive = group.isExclusive ? 'exclusive' : 'non-exclusive';
49
+ const required = group.isRequired ? ', required' : '';
50
+ this.log(styles.success(`\nCreated label group: ${group.name} (${group.id})`));
51
+ this.log(styles.muted(` ${exclusive}${required}`));
52
+ this.log('');
53
+ }
54
+ }