@proletariat/cli 0.3.23 → 0.3.24

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 (171) hide show
  1. package/dist/commands/action/create.js +1 -1
  2. package/dist/commands/agent/{temp/cleanup.d.ts → cleanup.d.ts} +1 -1
  3. package/dist/commands/agent/{temp/cleanup.js → cleanup.js} +4 -4
  4. package/dist/commands/agent/index.js +8 -8
  5. package/dist/commands/branch/create.js +2 -2
  6. package/dist/commands/epic/create.d.ts +1 -0
  7. package/dist/commands/epic/create.js +39 -2
  8. package/dist/commands/epic/index.js +2 -2
  9. package/dist/commands/{epic/link/remove.d.ts → link/create.d.ts} +6 -7
  10. package/dist/commands/link/create.js +141 -0
  11. package/dist/commands/{epic/link/relates.d.ts → link/index.d.ts} +4 -5
  12. package/dist/commands/link/index.js +87 -0
  13. package/dist/commands/{epic/link/duplicates.d.ts → link/list.d.ts} +7 -4
  14. package/dist/commands/link/list.js +182 -0
  15. package/dist/commands/{spec/link → link}/remove.d.ts +4 -5
  16. package/dist/commands/link/remove.js +120 -0
  17. package/dist/commands/mcp-server.d.ts +22 -0
  18. package/dist/commands/mcp-server.js +98 -0
  19. package/dist/commands/phase/create.js +1 -1
  20. package/dist/commands/project/create.d.ts +1 -0
  21. package/dist/commands/project/create.js +38 -4
  22. package/dist/commands/spec/create.d.ts +1 -0
  23. package/dist/commands/spec/create.js +43 -2
  24. package/dist/commands/spec/index.js +2 -2
  25. package/dist/commands/{agent/staff → staff}/add.js +10 -10
  26. package/dist/commands/{agent/staff → staff}/index.d.ts +1 -1
  27. package/dist/commands/{agent/staff → staff}/index.js +7 -7
  28. package/dist/commands/{agent/staff → staff}/list.js +3 -3
  29. package/dist/commands/{agent/staff → staff}/remove.d.ts +1 -1
  30. package/dist/commands/{agent/staff → staff}/remove.js +8 -8
  31. package/dist/commands/{ticket/template → template}/apply.d.ts +8 -6
  32. package/dist/commands/template/apply.js +262 -0
  33. package/dist/commands/{ticket/template → template}/create.d.ts +5 -6
  34. package/dist/commands/template/create.js +238 -0
  35. package/dist/commands/template/index.js +48 -36
  36. package/dist/commands/{ticket/template → template}/save.d.ts +2 -2
  37. package/dist/commands/template/save.js +104 -0
  38. package/dist/commands/{phase/template → template}/update.d.ts +2 -2
  39. package/dist/commands/template/update.js +99 -0
  40. package/dist/commands/{agent/themes → theme}/add-names.d.ts +1 -1
  41. package/dist/commands/{agent/themes → theme}/add-names.js +6 -6
  42. package/dist/commands/{agent/themes → theme}/create.d.ts +1 -1
  43. package/dist/commands/{agent/themes → theme}/create.js +5 -5
  44. package/dist/commands/{agent/themes → theme}/index.d.ts +1 -1
  45. package/dist/commands/{agent/themes → theme}/index.js +10 -10
  46. package/dist/commands/{agent/themes → theme}/list.d.ts +1 -1
  47. package/dist/commands/{agent/themes → theme}/list.js +5 -5
  48. package/dist/commands/{agent/themes → theme}/set.d.ts +1 -1
  49. package/dist/commands/{agent/themes → theme}/set.js +7 -7
  50. package/dist/commands/ticket/create.d.ts +1 -0
  51. package/dist/commands/ticket/create.js +54 -2
  52. package/dist/commands/ticket/index.js +6 -6
  53. package/dist/commands/work/spawn.js +1 -1
  54. package/dist/lib/mcp/helpers.d.ts +43 -0
  55. package/dist/lib/mcp/helpers.js +57 -0
  56. package/dist/lib/mcp/index.d.ts +6 -0
  57. package/dist/lib/mcp/index.js +6 -0
  58. package/dist/lib/mcp/tools/action.d.ts +6 -0
  59. package/dist/lib/mcp/tools/action.js +88 -0
  60. package/dist/lib/mcp/tools/board.d.ts +6 -0
  61. package/dist/lib/mcp/tools/board.js +139 -0
  62. package/dist/lib/mcp/tools/category.d.ts +6 -0
  63. package/dist/lib/mcp/tools/category.js +84 -0
  64. package/dist/lib/mcp/tools/cli-passthrough.d.ts +15 -0
  65. package/dist/lib/mcp/tools/cli-passthrough.js +333 -0
  66. package/dist/lib/mcp/tools/epic.d.ts +6 -0
  67. package/dist/lib/mcp/tools/epic.js +178 -0
  68. package/dist/lib/mcp/tools/index.d.ts +18 -0
  69. package/dist/lib/mcp/tools/index.js +19 -0
  70. package/dist/lib/mcp/tools/phase.d.ts +6 -0
  71. package/dist/lib/mcp/tools/phase.js +131 -0
  72. package/dist/lib/mcp/tools/project.d.ts +6 -0
  73. package/dist/lib/mcp/tools/project.js +196 -0
  74. package/dist/lib/mcp/tools/roadmap.d.ts +6 -0
  75. package/dist/lib/mcp/tools/roadmap.js +123 -0
  76. package/dist/lib/mcp/tools/spec.d.ts +6 -0
  77. package/dist/lib/mcp/tools/spec.js +196 -0
  78. package/dist/lib/mcp/tools/status.d.ts +6 -0
  79. package/dist/lib/mcp/tools/status.js +109 -0
  80. package/dist/lib/mcp/tools/template.d.ts +6 -0
  81. package/dist/lib/mcp/tools/template.js +107 -0
  82. package/dist/lib/mcp/tools/ticket.d.ts +6 -0
  83. package/dist/lib/mcp/tools/ticket.js +393 -0
  84. package/dist/lib/mcp/tools/view.d.ts +6 -0
  85. package/dist/lib/mcp/tools/view.js +76 -0
  86. package/dist/lib/mcp/tools/work.d.ts +6 -0
  87. package/dist/lib/mcp/tools/work.js +132 -0
  88. package/dist/lib/mcp/tools/workflow.d.ts +6 -0
  89. package/dist/lib/mcp/tools/workflow.js +95 -0
  90. package/dist/lib/mcp/types.d.ts +17 -0
  91. package/dist/lib/mcp/types.js +4 -0
  92. package/dist/lib/prompt-json.d.ts +52 -1
  93. package/dist/lib/prompt-json.js +45 -0
  94. package/oclif.manifest.json +3660 -5564
  95. package/package.json +6 -4
  96. package/dist/commands/agent/temp/index.d.ts +0 -14
  97. package/dist/commands/agent/temp/index.js +0 -85
  98. package/dist/commands/agent/temp/list.d.ts +0 -7
  99. package/dist/commands/agent/temp/list.js +0 -108
  100. package/dist/commands/epic/link/block.d.ts +0 -14
  101. package/dist/commands/epic/link/block.js +0 -81
  102. package/dist/commands/epic/link/duplicates.js +0 -68
  103. package/dist/commands/epic/link/index.d.ts +0 -19
  104. package/dist/commands/epic/link/index.js +0 -272
  105. package/dist/commands/epic/link/relates.js +0 -68
  106. package/dist/commands/epic/link/remove.js +0 -93
  107. package/dist/commands/phase/template/apply.d.ts +0 -17
  108. package/dist/commands/phase/template/apply.js +0 -108
  109. package/dist/commands/phase/template/create.d.ts +0 -17
  110. package/dist/commands/phase/template/create.js +0 -104
  111. package/dist/commands/phase/template/delete.d.ts +0 -17
  112. package/dist/commands/phase/template/delete.js +0 -100
  113. package/dist/commands/phase/template/index.d.ts +0 -15
  114. package/dist/commands/phase/template/index.js +0 -130
  115. package/dist/commands/phase/template/list.d.ts +0 -16
  116. package/dist/commands/phase/template/list.js +0 -97
  117. package/dist/commands/phase/template/update.js +0 -89
  118. package/dist/commands/spec/link/depends.d.ts +0 -14
  119. package/dist/commands/spec/link/depends.js +0 -64
  120. package/dist/commands/spec/link/duplicates.d.ts +0 -14
  121. package/dist/commands/spec/link/duplicates.js +0 -63
  122. package/dist/commands/spec/link/index.d.ts +0 -19
  123. package/dist/commands/spec/link/index.js +0 -207
  124. package/dist/commands/spec/link/relates.d.ts +0 -14
  125. package/dist/commands/spec/link/relates.js +0 -63
  126. package/dist/commands/spec/link/remove.js +0 -96
  127. package/dist/commands/template/phase/apply.d.ts +0 -14
  128. package/dist/commands/template/phase/apply.js +0 -43
  129. package/dist/commands/template/phase/create.d.ts +0 -13
  130. package/dist/commands/template/phase/create.js +0 -38
  131. package/dist/commands/template/phase/delete.d.ts +0 -13
  132. package/dist/commands/template/phase/delete.js +0 -36
  133. package/dist/commands/template/phase/index.d.ts +0 -10
  134. package/dist/commands/template/phase/index.js +0 -63
  135. package/dist/commands/template/phase/list.d.ts +0 -11
  136. package/dist/commands/template/phase/list.js +0 -36
  137. package/dist/commands/template/phase/update.d.ts +0 -14
  138. package/dist/commands/template/phase/update.js +0 -43
  139. package/dist/commands/template/ticket/apply.d.ts +0 -17
  140. package/dist/commands/template/ticket/apply.js +0 -60
  141. package/dist/commands/template/ticket/create.d.ts +0 -20
  142. package/dist/commands/template/ticket/create.js +0 -89
  143. package/dist/commands/template/ticket/delete.d.ts +0 -13
  144. package/dist/commands/template/ticket/delete.js +0 -38
  145. package/dist/commands/template/ticket/index.d.ts +0 -10
  146. package/dist/commands/template/ticket/index.js +0 -63
  147. package/dist/commands/template/ticket/list.d.ts +0 -11
  148. package/dist/commands/template/ticket/list.js +0 -36
  149. package/dist/commands/template/ticket/save.d.ts +0 -15
  150. package/dist/commands/template/ticket/save.js +0 -46
  151. package/dist/commands/ticket/link/block.d.ts +0 -14
  152. package/dist/commands/ticket/link/block.js +0 -96
  153. package/dist/commands/ticket/link/duplicates.d.ts +0 -14
  154. package/dist/commands/ticket/link/duplicates.js +0 -95
  155. package/dist/commands/ticket/link/index.d.ts +0 -19
  156. package/dist/commands/ticket/link/index.js +0 -256
  157. package/dist/commands/ticket/link/relates.d.ts +0 -14
  158. package/dist/commands/ticket/link/relates.js +0 -95
  159. package/dist/commands/ticket/link/remove.d.ts +0 -16
  160. package/dist/commands/ticket/link/remove.js +0 -132
  161. package/dist/commands/ticket/template/apply.js +0 -252
  162. package/dist/commands/ticket/template/create.js +0 -386
  163. package/dist/commands/ticket/template/delete.d.ts +0 -17
  164. package/dist/commands/ticket/template/delete.js +0 -94
  165. package/dist/commands/ticket/template/index.d.ts +0 -15
  166. package/dist/commands/ticket/template/index.js +0 -120
  167. package/dist/commands/ticket/template/list.d.ts +0 -16
  168. package/dist/commands/ticket/template/list.js +0 -112
  169. package/dist/commands/ticket/template/save.js +0 -163
  170. /package/dist/commands/{agent/staff → staff}/add.d.ts +0 -0
  171. /package/dist/commands/{agent/staff → staff}/list.d.ts +0 -0
@@ -1,10 +1,10 @@
1
1
  import { Command, Args, Flags } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
3
  import inquirer from 'inquirer';
4
- import { getWorkspaceInfo, validateAgentNames, addAgentsToWorkspace } from '../../../lib/agents/commands.js';
5
- import { ensureBuiltinThemes, BUILTIN_THEMES, isValidAgentName, normalizeAgentName } from '../../../lib/themes.js';
6
- import { getTheme, getThemes, getAvailableThemeNames, getActiveTheme } from '../../../lib/database/index.js';
7
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
4
+ import { getWorkspaceInfo, validateAgentNames, addAgentsToWorkspace } from '../../lib/agents/commands.js';
5
+ import { ensureBuiltinThemes, BUILTIN_THEMES, isValidAgentName, normalizeAgentName } from '../../lib/themes.js';
6
+ import { getTheme, getThemes, getAvailableThemeNames, getActiveTheme } from '../../lib/database/index.js';
7
+ import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
8
8
  export default class Add extends Command {
9
9
  static description = 'Add new agents to the workspace';
10
10
  static examples = [
@@ -58,7 +58,7 @@ export default class Add extends Command {
58
58
  if (!theme) {
59
59
  const available = BUILTIN_THEMES.map(t => t.name).join(', ');
60
60
  if (jsonMode) {
61
- outputErrorAsJson('THEME_NOT_FOUND', `Theme "${flags.theme}" not found. Available: ${available}`, createMetadata('agent add', flags));
61
+ outputErrorAsJson('THEME_NOT_FOUND', `Theme "${flags.theme}" not found. Available: ${available}`, createMetadata('staff add', flags));
62
62
  return;
63
63
  }
64
64
  this.error(`Theme "${flags.theme}" not found. Available: ${available}`);
@@ -68,7 +68,7 @@ export default class Add extends Command {
68
68
  const availableNames = getAvailableThemeNames(workspaceInfo.path, themeId);
69
69
  if (availableNames.length === 0) {
70
70
  if (jsonMode) {
71
- outputErrorAsJson('NO_AVAILABLE_NAMES', `No available names in theme "${theme.display_name}". All names are in use.`, createMetadata('agent add', flags));
71
+ outputErrorAsJson('NO_AVAILABLE_NAMES', `No available names in theme "${theme.display_name}". All names are in use.`, createMetadata('staff add', flags));
72
72
  return;
73
73
  }
74
74
  this.error(`No available names in theme "${theme.display_name}". All names are in use.`);
@@ -78,7 +78,7 @@ export default class Add extends Command {
78
78
  const selectMessage = `Select agent names from ${theme.display_name}:`;
79
79
  // In JSON mode, output theme names selection prompt
80
80
  if (jsonMode) {
81
- outputPromptAsJson(buildPromptConfig('checkbox', 'names', selectMessage, nameChoices), createMetadata('agent add', flags));
81
+ outputPromptAsJson(buildPromptConfig('checkbox', 'names', selectMessage, nameChoices), createMetadata('staff add', flags));
82
82
  return;
83
83
  }
84
84
  // Interactive selection from theme
@@ -103,7 +103,7 @@ export default class Add extends Command {
103
103
  const availableNames = getAvailableThemeNames(workspaceInfo.path, activeTheme.id);
104
104
  if (availableNames.length === 0) {
105
105
  if (jsonMode) {
106
- outputErrorAsJson('NO_AVAILABLE_NAMES', `No available names in ${activeTheme.display_name}. All names are in use.`, createMetadata('agent add', flags));
106
+ outputErrorAsJson('NO_AVAILABLE_NAMES', `No available names in ${activeTheme.display_name}. All names are in use.`, createMetadata('staff add', flags));
107
107
  return;
108
108
  }
109
109
  this.log(chalk.yellow(`No available names in ${activeTheme.display_name}. All names are in use.`));
@@ -118,7 +118,7 @@ export default class Add extends Command {
118
118
  const selectMessage = `Select agents from ${activeTheme.display_name}:`;
119
119
  // In JSON mode, output agent names selection prompt
120
120
  if (jsonMode) {
121
- outputPromptAsJson(buildPromptConfig('checkbox', 'names', selectMessage, nameChoices), createMetadata('agent add', flags));
121
+ outputPromptAsJson(buildPromptConfig('checkbox', 'names', selectMessage, nameChoices), createMetadata('staff add', flags));
122
122
  return;
123
123
  }
124
124
  // Add separator before custom option for interactive mode
@@ -175,7 +175,7 @@ export default class Add extends Command {
175
175
  const selectMessage = 'No theme set. Select a theme or enter custom names:';
176
176
  // In JSON mode, output theme selection prompt
177
177
  if (jsonMode) {
178
- outputPromptAsJson(buildPromptConfig('list', 'theme', selectMessage, themeChoices), createMetadata('agent add', flags));
178
+ outputPromptAsJson(buildPromptConfig('list', 'theme', selectMessage, themeChoices), createMetadata('staff add', flags));
179
179
  return;
180
180
  }
181
181
  // Add separator and styling for interactive mode
@@ -1,4 +1,4 @@
1
- import { PMOCommand } from '../../../lib/pmo/index.js';
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
2
  export default class Staff extends PMOCommand {
3
3
  static description: string;
4
4
  static examples: string[];
@@ -1,8 +1,8 @@
1
1
  import { Flags } from '@oclif/core';
2
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';
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
6
  export default class Staff extends PMOCommand {
7
7
  static description = 'Manage staff (persistent) agents';
8
8
  static examples = [
@@ -33,15 +33,15 @@ export default class Staff extends PMOCommand {
33
33
  // Define choices once, use for both JSON and interactive modes
34
34
  // Include command field for AI agent navigation
35
35
  const menuChoices = [
36
- { name: 'List staff agents', value: 'list', command: 'prlt agent staff list --machine' },
37
- { name: 'Add staff agent', value: 'add', command: 'prlt agent staff add --machine' },
38
- { name: 'Remove staff agent', value: 'remove', command: 'prlt agent staff remove --machine' },
36
+ { name: 'List staff agents', value: 'list', command: 'prlt staff list --machine' },
37
+ { name: 'Add staff agent', value: 'add', command: 'prlt staff add --machine' },
38
+ { name: 'Remove staff agent', value: 'remove', command: 'prlt staff remove --machine' },
39
39
  { name: 'Cancel', value: 'cancel', command: '' },
40
40
  ];
41
41
  const message = 'What would you like to do?';
42
42
  // In JSON mode, output menu prompt
43
43
  if (jsonMode) {
44
- outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('agent staff', flags));
44
+ outputPromptAsJson(buildPromptConfig('list', 'action', message, menuChoices), createMetadata('staff', flags));
45
45
  return;
46
46
  }
47
47
  this.log(colors.primary('Staff Agents'));
@@ -2,7 +2,7 @@ import { Command } from '@oclif/core';
2
2
  import chalk from 'chalk';
3
3
  import * as path from 'node:path';
4
4
  import * as fs from 'node:fs';
5
- import { getWorkspaceInfo, getAllAgentsStatus } from '../../../lib/agents/commands.js';
5
+ import { getWorkspaceInfo, getAllAgentsStatus } from '../../lib/agents/commands.js';
6
6
  export default class List extends Command {
7
7
  static description = 'List all staff (persistent) agents and their status';
8
8
  static examples = [
@@ -16,7 +16,7 @@ export default class List extends Command {
16
16
  // Filter to staff agents only
17
17
  const staffAgents = workspaceInfo.agents.filter(a => a.type === 'persistent');
18
18
  if (staffAgents.length === 0) {
19
- this.log(chalk.yellow('No staff agents found. Add staff agents with "prlt agent staff add"'));
19
+ this.log(chalk.yellow('No staff agents found. Add staff agents with "prlt staff add"'));
20
20
  return;
21
21
  }
22
22
  // Get status for all agents and filter to staff
@@ -68,7 +68,7 @@ export default class List extends Command {
68
68
  else {
69
69
  this.log(chalk.red(` Agent directory not found`));
70
70
  }
71
- this.log(chalk.white(' Run "prlt agent staff add" to recreate'));
71
+ this.log(chalk.white(' Run "prlt staff add" to recreate'));
72
72
  }
73
73
  this.log(''); // Empty line between agents
74
74
  }
@@ -1,4 +1,4 @@
1
- import { PMOCommand } from '../../../lib/pmo/index.js';
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
2
  export default class Remove extends PMOCommand {
3
3
  static description: string;
4
4
  static examples: string[];
@@ -1,9 +1,9 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import inquirer from 'inquirer';
3
- import { colors, format } from '../../../lib/colors.js';
4
- import { getWorkspaceInfo, removeAgentsFromWorkspace, formatAgentList } from '../../../lib/agents/commands.js';
5
- import { PMOCommand, pmoBaseFlags } from '../../../lib/pmo/index.js';
6
- import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../../lib/prompt-json.js';
3
+ import { colors, format } from '../../lib/colors.js';
4
+ import { getWorkspaceInfo, removeAgentsFromWorkspace, formatAgentList } from '../../lib/agents/commands.js';
5
+ import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
6
+ import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
7
7
  export default class Remove extends PMOCommand {
8
8
  static description = 'Remove a specific agent from the workspace';
9
9
  static examples = [
@@ -40,7 +40,7 @@ export default class Remove extends PMOCommand {
40
40
  // Helper to handle errors in JSON mode
41
41
  const handleError = (code, message) => {
42
42
  if (jsonMode) {
43
- outputErrorAsJson(code, message, createMetadata('agent remove', flags));
43
+ outputErrorAsJson(code, message, createMetadata('staff remove', flags));
44
44
  this.exit(1);
45
45
  }
46
46
  this.error(message);
@@ -51,7 +51,7 @@ export default class Remove extends PMOCommand {
51
51
  const staffAgents = workspaceInfo.agents.filter(a => a.type === 'persistent');
52
52
  if (staffAgents.length === 0) {
53
53
  if (jsonMode) {
54
- outputErrorAsJson('NO_AGENTS', 'No staff agents to remove.', createMetadata('agent staff remove', flags));
54
+ outputErrorAsJson('NO_AGENTS', 'No staff agents to remove.', createMetadata('staff remove', flags));
55
55
  return;
56
56
  }
57
57
  this.log(colors.warning('No staff agents to remove.'));
@@ -68,7 +68,7 @@ export default class Remove extends PMOCommand {
68
68
  const selectMessage = 'Select agent to remove:';
69
69
  // In JSON mode, output agent selection prompt
70
70
  if (jsonMode) {
71
- outputPromptAsJson(buildPromptConfig('list', 'name', selectMessage, agentChoices), createMetadata('agent remove', flags));
71
+ outputPromptAsJson(buildPromptConfig('list', 'name', selectMessage, agentChoices), createMetadata('staff remove', flags));
72
72
  return;
73
73
  }
74
74
  const { selected } = await inquirer.prompt([
@@ -106,7 +106,7 @@ export default class Remove extends PMOCommand {
106
106
  // Confirm removal
107
107
  // In JSON mode, output confirmation prompt
108
108
  if (jsonMode) {
109
- outputPromptAsJson(buildPromptConfig('list', 'confirmed', confirmMessage, confirmChoices), createMetadata('agent remove', flags));
109
+ outputPromptAsJson(buildPromptConfig('list', 'confirmed', confirmMessage, confirmChoices), createMetadata('staff remove', flags));
110
110
  return;
111
111
  }
112
112
  const { confirm } = await inquirer.prompt([
@@ -1,25 +1,27 @@
1
- import { PMOCommand } from '../../../lib/pmo/index.js';
2
- export default class TicketTemplateApply extends PMOCommand {
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class TemplateApply extends PMOCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {
6
6
  template: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
7
  };
8
8
  static flags: {
9
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
10
  title: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  column: 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
  assignee: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
15
  owner: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
- status: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
- labels: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
16
  description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ epic: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
18
+ 'no-subtasks': import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
19
  interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
19
21
  json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
20
- 'no-subtasks': import("@oclif/core/interfaces").BooleanFlag<boolean>;
21
- epic: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
22
  project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
23
23
  };
24
24
  execute(): Promise<void>;
25
+ private applyTicketTemplate;
26
+ private applyPhaseTemplate;
25
27
  }
@@ -0,0 +1,262 @@
1
+ import { Flags, Args } from '@oclif/core';
2
+ import inquirer from 'inquirer';
3
+ import { PMOCommand, pmoBaseFlags, autoExportToBoard } from '../../lib/pmo/index.js';
4
+ import { PRIORITIES, PRIORITY_LABELS } from '../../lib/pmo/types.js';
5
+ import { styles } from '../../lib/styles.js';
6
+ import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildFormPromptConfig, buildPromptConfig, } from '../../lib/prompt-json.js';
7
+ export default class TemplateApply extends PMOCommand {
8
+ static description = 'Apply a template';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %> --type ticket bug-report',
11
+ '<%= config.bin %> <%= command.id %> --type ticket bug-report --title "Login fails"',
12
+ '<%= config.bin %> <%= command.id %> --type phase agile',
13
+ '<%= config.bin %> <%= command.id %> --type phase default --force',
14
+ ];
15
+ static args = {
16
+ template: Args.string({
17
+ description: 'Template ID to apply',
18
+ required: false,
19
+ }),
20
+ };
21
+ static flags = {
22
+ ...pmoBaseFlags,
23
+ type: Flags.string({
24
+ char: 't',
25
+ description: 'Template type',
26
+ options: ['ticket', 'phase'],
27
+ }),
28
+ // Ticket-specific flags
29
+ title: Flags.string({
30
+ description: 'Ticket title (ticket only)',
31
+ }),
32
+ column: Flags.string({
33
+ char: 'c',
34
+ description: 'Column to place ticket (ticket only)',
35
+ }),
36
+ priority: Flags.string({
37
+ char: 'p',
38
+ description: 'Priority override (ticket only)',
39
+ options: [...PRIORITIES],
40
+ }),
41
+ category: Flags.string({
42
+ description: 'Category override (ticket only)',
43
+ }),
44
+ assignee: Flags.string({
45
+ char: 'a',
46
+ description: 'Assignee (ticket only)',
47
+ }),
48
+ owner: Flags.string({
49
+ char: 'o',
50
+ description: 'Owner (ticket only)',
51
+ }),
52
+ description: Flags.string({
53
+ char: 'd',
54
+ description: 'Description override (ticket only)',
55
+ }),
56
+ epic: Flags.string({
57
+ char: 'e',
58
+ description: 'Link to epic (ticket only)',
59
+ }),
60
+ 'no-subtasks': Flags.boolean({
61
+ description: 'Skip creating subtasks (ticket only)',
62
+ default: false,
63
+ }),
64
+ interactive: Flags.boolean({
65
+ char: 'i',
66
+ description: 'Interactive mode (ticket only)',
67
+ default: false,
68
+ }),
69
+ // Phase-specific flags
70
+ force: Flags.boolean({
71
+ char: 'f',
72
+ description: 'Skip confirmation (phase only)',
73
+ default: false,
74
+ }),
75
+ json: Flags.boolean({
76
+ char: 'm',
77
+ aliases: ['machine'],
78
+ description: 'Output as JSON for AI agents/scripts',
79
+ default: false,
80
+ }),
81
+ };
82
+ async execute() {
83
+ const { args, flags } = await this.parse(TemplateApply);
84
+ const jsonMode = shouldOutputJson(flags);
85
+ // Determine template type
86
+ let templateType = flags.type;
87
+ if (!templateType) {
88
+ if (jsonMode) {
89
+ outputPromptAsJson(buildPromptConfig('list', 'type', 'What type of template?', [
90
+ { name: 'Ticket template', value: 'ticket' },
91
+ { name: 'Phase template', value: 'phase' },
92
+ ]), createMetadata('template apply', flags));
93
+ return;
94
+ }
95
+ const { selectedType } = await inquirer.prompt([{
96
+ type: 'list',
97
+ name: 'selectedType',
98
+ message: 'What type of template?',
99
+ choices: [
100
+ { name: 'Ticket template', value: 'ticket' },
101
+ { name: 'Phase template', value: 'phase' },
102
+ ],
103
+ }]);
104
+ templateType = selectedType;
105
+ }
106
+ if (templateType === 'ticket') {
107
+ await this.applyTicketTemplate(args.template, flags, jsonMode);
108
+ }
109
+ else {
110
+ await this.applyPhaseTemplate(args.template, flags, jsonMode);
111
+ }
112
+ }
113
+ async applyTicketTemplate(templateId, flags, jsonMode) {
114
+ const projectId = await this.requireProject();
115
+ const board = await this.storage.getBoard(projectId);
116
+ const columns = board.columns.map(col => col.name);
117
+ const handleError = (code, message) => {
118
+ if (jsonMode) {
119
+ outputErrorAsJson(code, message, createMetadata('template apply', flags));
120
+ this.exit(1);
121
+ }
122
+ this.error(message);
123
+ };
124
+ // Get template
125
+ if (!templateId) {
126
+ const templates = await this.storage.listTicketTemplates();
127
+ if (templates.length === 0) {
128
+ return handleError('NO_TEMPLATES', 'No ticket templates. Create with: prlt template create --type ticket');
129
+ }
130
+ const { selected } = await inquirer.prompt([{
131
+ type: 'list',
132
+ name: 'selected',
133
+ message: 'Select template:',
134
+ choices: templates.map(t => ({ name: `${t.name}${t.description ? ` - ${t.description}` : ''}`, value: t.id })),
135
+ }]);
136
+ templateId = selected;
137
+ }
138
+ const template = await this.storage.getTicketTemplate(templateId);
139
+ if (!template) {
140
+ return handleError('TEMPLATE_NOT_FOUND', `Template not found: ${templateId}`);
141
+ }
142
+ // Determine ticket data
143
+ let title = flags.title || template.titlePattern || '';
144
+ let column = flags.column || columns[0];
145
+ let priority = flags.priority || template.defaultPriority;
146
+ let category = flags.category || template.defaultCategory;
147
+ let assignee = flags.assignee || template.defaultAssignee;
148
+ let owner = flags.owner || template.defaultOwner;
149
+ let description = flags.description || template.descriptionTemplate;
150
+ const labels = template.defaultLabels;
151
+ // Interactive mode
152
+ if (flags.interactive || !title) {
153
+ const fields = [
154
+ { type: 'input', name: 'title', message: 'Title:', default: title || undefined },
155
+ { type: 'list', name: 'column', message: 'Column:', choices: columns.map(c => ({ name: c, value: c })), default: column },
156
+ { type: 'list', name: 'priority', message: 'Priority:', choices: [{ name: 'None', value: '' }, ...PRIORITIES.map(p => ({ name: PRIORITY_LABELS[p], value: p }))], default: priority },
157
+ ];
158
+ if (jsonMode) {
159
+ outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('template apply', flags));
160
+ return;
161
+ }
162
+ const answers = await inquirer.prompt(fields.map(f => ({
163
+ ...f,
164
+ validate: f.name === 'title' ? ((i) => i.length > 0 || 'Required') : undefined,
165
+ })));
166
+ title = answers.title;
167
+ column = answers.column;
168
+ priority = answers.priority || undefined;
169
+ }
170
+ // Validate epic if provided
171
+ if (flags.epic) {
172
+ const epic = await this.storage.getEpic(flags.epic);
173
+ if (!epic)
174
+ this.error(`Epic not found: ${flags.epic}`);
175
+ }
176
+ // Create ticket
177
+ const ticket = await this.storage.createTicket(projectId, {
178
+ title,
179
+ statusName: column,
180
+ priority,
181
+ category,
182
+ assignee,
183
+ owner,
184
+ labels,
185
+ description,
186
+ epicId: flags.epic,
187
+ });
188
+ // Add subtasks
189
+ if (!flags['no-subtasks'] && template.suggestedSubtasks.length > 0) {
190
+ for (const subtask of template.suggestedSubtasks) {
191
+ await this.storage.addSubtask(ticket.id, subtask.title);
192
+ }
193
+ }
194
+ await autoExportToBoard(this.pmoPath, this.storage, (msg) => this.log(styles.muted(msg)));
195
+ this.log(styles.success(`\nCreated ticket ${styles.emphasis(ticket.id)} from template "${template.name}"`));
196
+ this.log(styles.muted(` Title: ${ticket.title}`));
197
+ this.log(styles.muted(` Status: ${ticket.statusName}`));
198
+ if (priority)
199
+ this.log(styles.muted(` Priority: ${priority}`));
200
+ if (template.suggestedSubtasks.length > 0 && !flags['no-subtasks']) {
201
+ this.log(styles.muted(` Subtasks: ${template.suggestedSubtasks.length} created`));
202
+ }
203
+ }
204
+ async applyPhaseTemplate(templateId, flags, jsonMode) {
205
+ const handleError = (code, message) => {
206
+ if (jsonMode) {
207
+ outputErrorAsJson(code, message, createMetadata('template apply', flags));
208
+ this.exit(1);
209
+ }
210
+ this.error(message);
211
+ };
212
+ // Get template
213
+ if (!templateId) {
214
+ const templates = await this.storage.listPhaseTemplates();
215
+ if (templates.length === 0) {
216
+ return handleError('NO_TEMPLATES', 'No phase templates. Create with: prlt template create --type phase');
217
+ }
218
+ const { selected } = await inquirer.prompt([{
219
+ type: 'list',
220
+ name: 'selected',
221
+ message: 'Select phase template:',
222
+ choices: templates.map(t => ({ name: `${t.name}${t.description ? ` - ${t.description}` : ''}`, value: t.id })),
223
+ }]);
224
+ templateId = selected;
225
+ }
226
+ const template = await this.storage.getPhaseTemplate(templateId);
227
+ if (!template) {
228
+ return handleError('TEMPLATE_NOT_FOUND', `Template not found: ${templateId}`);
229
+ }
230
+ // Check existing phases
231
+ const existingPhases = await this.storage.listPhases();
232
+ if (existingPhases.length > 0 && !flags.force) {
233
+ if (jsonMode) {
234
+ outputPromptAsJson(buildPromptConfig('list', 'confirmed', `Replace ${existingPhases.length} existing phase(s)?`, [
235
+ { name: 'No', value: 'false' },
236
+ { name: 'Yes', value: 'true' },
237
+ ]), createMetadata('template apply', flags));
238
+ return;
239
+ }
240
+ this.log(styles.warning(`\nThis will REPLACE ${existingPhases.length} existing phase(s).`));
241
+ const { confirm } = await inquirer.prompt([{
242
+ type: 'list',
243
+ name: 'confirm',
244
+ message: `Apply template "${template.name}"?`,
245
+ choices: [
246
+ { name: 'No', value: false },
247
+ { name: 'Yes', value: true },
248
+ ],
249
+ }]);
250
+ if (!confirm) {
251
+ this.log(styles.muted('Cancelled'));
252
+ return;
253
+ }
254
+ }
255
+ const phases = await this.storage.applyPhaseTemplate(templateId);
256
+ this.log(styles.success(`\nApplied phase template "${styles.emphasis(template.name)}"`));
257
+ this.log(styles.muted(`Created ${phases.length} phases:`));
258
+ for (const phase of phases) {
259
+ this.log(styles.muted(` • ${phase.name} [${phase.category}]`));
260
+ }
261
+ }
262
+ }
@@ -1,11 +1,12 @@
1
- import { PMOCommand } from '../../../lib/pmo/index.js';
2
- export default class TicketTemplateCreate extends PMOCommand {
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class TemplateCreate extends PMOCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static args: {
6
6
  name: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
7
7
  };
8
8
  static flags: {
9
+ type: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
10
  description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
11
  'title-pattern': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
12
  'description-template': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -21,8 +22,6 @@ export default class TicketTemplateCreate extends PMOCommand {
21
22
  promptIfMultiple: boolean;
22
23
  };
23
24
  execute(): Promise<void>;
24
- /**
25
- * Check if any non-default flags were provided (indicating non-interactive intent)
26
- */
27
- private hasNonDefaultFlags;
25
+ private createTicketTemplate;
26
+ private createPhaseTemplate;
28
27
  }