@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.
- package/dist/commands/action/create.js +1 -1
- package/dist/commands/agent/{temp/cleanup.d.ts → cleanup.d.ts} +1 -1
- package/dist/commands/agent/{temp/cleanup.js → cleanup.js} +4 -4
- package/dist/commands/agent/index.js +8 -8
- package/dist/commands/branch/create.js +2 -2
- package/dist/commands/epic/create.d.ts +1 -0
- package/dist/commands/epic/create.js +39 -2
- package/dist/commands/epic/index.js +2 -2
- package/dist/commands/{epic/link/remove.d.ts → link/create.d.ts} +6 -7
- package/dist/commands/link/create.js +141 -0
- package/dist/commands/{epic/link/relates.d.ts → link/index.d.ts} +4 -5
- package/dist/commands/link/index.js +87 -0
- package/dist/commands/{epic/link/duplicates.d.ts → link/list.d.ts} +7 -4
- package/dist/commands/link/list.js +182 -0
- package/dist/commands/{spec/link → link}/remove.d.ts +4 -5
- package/dist/commands/link/remove.js +120 -0
- package/dist/commands/mcp-server.d.ts +22 -0
- package/dist/commands/mcp-server.js +98 -0
- package/dist/commands/phase/create.js +1 -1
- package/dist/commands/project/create.d.ts +1 -0
- package/dist/commands/project/create.js +38 -4
- package/dist/commands/spec/create.d.ts +1 -0
- package/dist/commands/spec/create.js +43 -2
- package/dist/commands/spec/index.js +2 -2
- package/dist/commands/{agent/staff → staff}/add.js +10 -10
- package/dist/commands/{agent/staff → staff}/index.d.ts +1 -1
- package/dist/commands/{agent/staff → staff}/index.js +7 -7
- package/dist/commands/{agent/staff → staff}/list.js +3 -3
- package/dist/commands/{agent/staff → staff}/remove.d.ts +1 -1
- package/dist/commands/{agent/staff → staff}/remove.js +8 -8
- package/dist/commands/{ticket/template → template}/apply.d.ts +8 -6
- package/dist/commands/template/apply.js +262 -0
- package/dist/commands/{ticket/template → template}/create.d.ts +5 -6
- package/dist/commands/template/create.js +238 -0
- package/dist/commands/template/index.js +48 -36
- package/dist/commands/{ticket/template → template}/save.d.ts +2 -2
- package/dist/commands/template/save.js +104 -0
- package/dist/commands/{phase/template → template}/update.d.ts +2 -2
- package/dist/commands/template/update.js +99 -0
- package/dist/commands/{agent/themes → theme}/add-names.d.ts +1 -1
- package/dist/commands/{agent/themes → theme}/add-names.js +6 -6
- package/dist/commands/{agent/themes → theme}/create.d.ts +1 -1
- package/dist/commands/{agent/themes → theme}/create.js +5 -5
- package/dist/commands/{agent/themes → theme}/index.d.ts +1 -1
- package/dist/commands/{agent/themes → theme}/index.js +10 -10
- package/dist/commands/{agent/themes → theme}/list.d.ts +1 -1
- package/dist/commands/{agent/themes → theme}/list.js +5 -5
- package/dist/commands/{agent/themes → theme}/set.d.ts +1 -1
- package/dist/commands/{agent/themes → theme}/set.js +7 -7
- package/dist/commands/ticket/create.d.ts +1 -0
- package/dist/commands/ticket/create.js +54 -2
- package/dist/commands/ticket/index.js +6 -6
- package/dist/commands/work/spawn.js +1 -1
- package/dist/lib/mcp/helpers.d.ts +43 -0
- package/dist/lib/mcp/helpers.js +57 -0
- package/dist/lib/mcp/index.d.ts +6 -0
- package/dist/lib/mcp/index.js +6 -0
- package/dist/lib/mcp/tools/action.d.ts +6 -0
- package/dist/lib/mcp/tools/action.js +88 -0
- package/dist/lib/mcp/tools/board.d.ts +6 -0
- package/dist/lib/mcp/tools/board.js +139 -0
- package/dist/lib/mcp/tools/category.d.ts +6 -0
- package/dist/lib/mcp/tools/category.js +84 -0
- package/dist/lib/mcp/tools/cli-passthrough.d.ts +15 -0
- package/dist/lib/mcp/tools/cli-passthrough.js +333 -0
- package/dist/lib/mcp/tools/epic.d.ts +6 -0
- package/dist/lib/mcp/tools/epic.js +178 -0
- package/dist/lib/mcp/tools/index.d.ts +18 -0
- package/dist/lib/mcp/tools/index.js +19 -0
- package/dist/lib/mcp/tools/phase.d.ts +6 -0
- package/dist/lib/mcp/tools/phase.js +131 -0
- package/dist/lib/mcp/tools/project.d.ts +6 -0
- package/dist/lib/mcp/tools/project.js +196 -0
- package/dist/lib/mcp/tools/roadmap.d.ts +6 -0
- package/dist/lib/mcp/tools/roadmap.js +123 -0
- package/dist/lib/mcp/tools/spec.d.ts +6 -0
- package/dist/lib/mcp/tools/spec.js +196 -0
- package/dist/lib/mcp/tools/status.d.ts +6 -0
- package/dist/lib/mcp/tools/status.js +109 -0
- package/dist/lib/mcp/tools/template.d.ts +6 -0
- package/dist/lib/mcp/tools/template.js +107 -0
- package/dist/lib/mcp/tools/ticket.d.ts +6 -0
- package/dist/lib/mcp/tools/ticket.js +393 -0
- package/dist/lib/mcp/tools/view.d.ts +6 -0
- package/dist/lib/mcp/tools/view.js +76 -0
- package/dist/lib/mcp/tools/work.d.ts +6 -0
- package/dist/lib/mcp/tools/work.js +132 -0
- package/dist/lib/mcp/tools/workflow.d.ts +6 -0
- package/dist/lib/mcp/tools/workflow.js +95 -0
- package/dist/lib/mcp/types.d.ts +17 -0
- package/dist/lib/mcp/types.js +4 -0
- package/dist/lib/prompt-json.d.ts +52 -1
- package/dist/lib/prompt-json.js +45 -0
- package/oclif.manifest.json +3660 -5564
- package/package.json +6 -4
- package/dist/commands/agent/temp/index.d.ts +0 -14
- package/dist/commands/agent/temp/index.js +0 -85
- package/dist/commands/agent/temp/list.d.ts +0 -7
- package/dist/commands/agent/temp/list.js +0 -108
- package/dist/commands/epic/link/block.d.ts +0 -14
- package/dist/commands/epic/link/block.js +0 -81
- package/dist/commands/epic/link/duplicates.js +0 -68
- package/dist/commands/epic/link/index.d.ts +0 -19
- package/dist/commands/epic/link/index.js +0 -272
- package/dist/commands/epic/link/relates.js +0 -68
- package/dist/commands/epic/link/remove.js +0 -93
- package/dist/commands/phase/template/apply.d.ts +0 -17
- package/dist/commands/phase/template/apply.js +0 -108
- package/dist/commands/phase/template/create.d.ts +0 -17
- package/dist/commands/phase/template/create.js +0 -104
- package/dist/commands/phase/template/delete.d.ts +0 -17
- package/dist/commands/phase/template/delete.js +0 -100
- package/dist/commands/phase/template/index.d.ts +0 -15
- package/dist/commands/phase/template/index.js +0 -130
- package/dist/commands/phase/template/list.d.ts +0 -16
- package/dist/commands/phase/template/list.js +0 -97
- package/dist/commands/phase/template/update.js +0 -89
- package/dist/commands/spec/link/depends.d.ts +0 -14
- package/dist/commands/spec/link/depends.js +0 -64
- package/dist/commands/spec/link/duplicates.d.ts +0 -14
- package/dist/commands/spec/link/duplicates.js +0 -63
- package/dist/commands/spec/link/index.d.ts +0 -19
- package/dist/commands/spec/link/index.js +0 -207
- package/dist/commands/spec/link/relates.d.ts +0 -14
- package/dist/commands/spec/link/relates.js +0 -63
- package/dist/commands/spec/link/remove.js +0 -96
- package/dist/commands/template/phase/apply.d.ts +0 -14
- package/dist/commands/template/phase/apply.js +0 -43
- package/dist/commands/template/phase/create.d.ts +0 -13
- package/dist/commands/template/phase/create.js +0 -38
- package/dist/commands/template/phase/delete.d.ts +0 -13
- package/dist/commands/template/phase/delete.js +0 -36
- package/dist/commands/template/phase/index.d.ts +0 -10
- package/dist/commands/template/phase/index.js +0 -63
- package/dist/commands/template/phase/list.d.ts +0 -11
- package/dist/commands/template/phase/list.js +0 -36
- package/dist/commands/template/phase/update.d.ts +0 -14
- package/dist/commands/template/phase/update.js +0 -43
- package/dist/commands/template/ticket/apply.d.ts +0 -17
- package/dist/commands/template/ticket/apply.js +0 -60
- package/dist/commands/template/ticket/create.d.ts +0 -20
- package/dist/commands/template/ticket/create.js +0 -89
- package/dist/commands/template/ticket/delete.d.ts +0 -13
- package/dist/commands/template/ticket/delete.js +0 -38
- package/dist/commands/template/ticket/index.d.ts +0 -10
- package/dist/commands/template/ticket/index.js +0 -63
- package/dist/commands/template/ticket/list.d.ts +0 -11
- package/dist/commands/template/ticket/list.js +0 -36
- package/dist/commands/template/ticket/save.d.ts +0 -15
- package/dist/commands/template/ticket/save.js +0 -46
- package/dist/commands/ticket/link/block.d.ts +0 -14
- package/dist/commands/ticket/link/block.js +0 -96
- package/dist/commands/ticket/link/duplicates.d.ts +0 -14
- package/dist/commands/ticket/link/duplicates.js +0 -95
- package/dist/commands/ticket/link/index.d.ts +0 -19
- package/dist/commands/ticket/link/index.js +0 -256
- package/dist/commands/ticket/link/relates.d.ts +0 -14
- package/dist/commands/ticket/link/relates.js +0 -95
- package/dist/commands/ticket/link/remove.d.ts +0 -16
- package/dist/commands/ticket/link/remove.js +0 -132
- package/dist/commands/ticket/template/apply.js +0 -252
- package/dist/commands/ticket/template/create.js +0 -386
- package/dist/commands/ticket/template/delete.d.ts +0 -17
- package/dist/commands/ticket/template/delete.js +0 -94
- package/dist/commands/ticket/template/index.d.ts +0 -15
- package/dist/commands/ticket/template/index.js +0 -120
- package/dist/commands/ticket/template/list.d.ts +0 -16
- package/dist/commands/ticket/template/list.js +0 -112
- package/dist/commands/ticket/template/save.js +0 -163
- /package/dist/commands/{agent/staff → staff}/add.d.ts +0 -0
- /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 '
|
|
5
|
-
import { ensureBuiltinThemes, BUILTIN_THEMES, isValidAgentName, normalizeAgentName } from '
|
|
6
|
-
import { getTheme, getThemes, getAvailableThemeNames, getActiveTheme } from '
|
|
7
|
-
import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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,8 +1,8 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import { colors } from '
|
|
4
|
-
import { PMOCommand, pmoBaseFlags } from '
|
|
5
|
-
import { shouldOutputJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '
|
|
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
|
|
37
|
-
{ name: 'Add staff agent', value: 'add', command: 'prlt
|
|
38
|
-
{ name: 'Remove staff agent', value: 'remove', command: 'prlt
|
|
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('
|
|
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 '
|
|
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
|
|
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
|
|
71
|
+
this.log(chalk.white(' Run "prlt staff add" to recreate'));
|
|
72
72
|
}
|
|
73
73
|
this.log(''); // Empty line between agents
|
|
74
74
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
-
import { colors, format } from '
|
|
4
|
-
import { getWorkspaceInfo, removeAgentsFromWorkspace, formatAgentList } from '
|
|
5
|
-
import { PMOCommand, pmoBaseFlags } from '
|
|
6
|
-
import { shouldOutputJson, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '
|
|
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('
|
|
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('
|
|
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('
|
|
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('
|
|
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 '
|
|
2
|
-
export default class
|
|
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 '
|
|
2
|
-
export default class
|
|
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
|
-
|
|
26
|
-
*/
|
|
27
|
-
private hasNonDefaultFlags;
|
|
25
|
+
private createTicketTemplate;
|
|
26
|
+
private createPhaseTemplate;
|
|
28
27
|
}
|