@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.
- package/dist/commands/agent/auth.d.ts +3 -1
- package/dist/commands/agent/auth.js +8 -11
- package/dist/commands/agent/index.js +11 -2
- package/dist/commands/agent/staff/add.d.ts +1 -0
- package/dist/commands/agent/staff/add.js +1 -0
- package/dist/commands/agent/staff/index.d.ts +15 -0
- package/dist/commands/agent/staff/index.js +83 -0
- package/dist/commands/agent/staff/list.d.ts +1 -0
- package/dist/commands/agent/staff/list.js +1 -0
- package/dist/commands/agent/staff/remove.d.ts +1 -0
- package/dist/commands/agent/staff/remove.js +1 -0
- package/dist/commands/agent/themes/add-names.d.ts +1 -0
- package/dist/commands/agent/themes/add-names.js +1 -0
- package/dist/commands/agent/themes/create.d.ts +1 -0
- package/dist/commands/agent/themes/create.js +1 -0
- package/dist/commands/agent/themes/index.d.ts +10 -0
- package/dist/commands/agent/themes/index.js +144 -0
- package/dist/commands/agent/themes/list.d.ts +1 -0
- package/dist/commands/agent/themes/list.js +1 -0
- package/dist/commands/agent/themes/set.d.ts +1 -0
- package/dist/commands/agent/themes/set.js +1 -0
- package/dist/commands/agents/themes/add-names.d.ts +1 -0
- package/dist/commands/agents/themes/add-names.js +1 -0
- package/dist/commands/agents/themes/create.d.ts +1 -0
- package/dist/commands/agents/themes/create.js +1 -0
- package/dist/commands/agents/themes/list.d.ts +1 -0
- package/dist/commands/agents/themes/list.js +1 -0
- package/dist/commands/category/list.js +1 -1
- package/dist/commands/label/create.d.ts +20 -0
- package/dist/commands/label/create.js +56 -0
- package/dist/commands/label/delete.d.ts +17 -0
- package/dist/commands/label/delete.js +31 -0
- package/dist/commands/label/group/create.d.ts +20 -0
- package/dist/commands/label/group/create.js +54 -0
- package/dist/commands/label/group/list.d.ts +14 -0
- package/dist/commands/label/group/list.js +51 -0
- package/dist/commands/label/index.d.ts +15 -0
- package/dist/commands/label/index.js +58 -0
- package/dist/commands/label/list.d.ts +16 -0
- package/dist/commands/label/list.js +82 -0
- package/dist/commands/link/list.js +3 -2
- package/dist/commands/mcp-server.js +2 -1
- package/dist/commands/phase/template/apply.d.ts +26 -0
- package/dist/commands/phase/template/apply.js +14 -0
- package/dist/commands/phase/template/create.d.ts +23 -0
- package/dist/commands/phase/template/create.js +14 -0
- package/dist/commands/phase/template/delete.d.ts +18 -0
- package/dist/commands/phase/template/delete.js +61 -0
- package/dist/commands/phase/template/list.d.ts +17 -0
- package/dist/commands/phase/template/list.js +88 -0
- package/dist/commands/phase/template/update.d.ts +1 -0
- package/dist/commands/phase/template/update.js +1 -0
- package/dist/commands/priority/add.js +1 -1
- package/dist/commands/project/update.js +0 -2
- package/dist/commands/roadmap/generate.js +1 -2
- package/dist/commands/session/health.js +1 -1
- package/dist/commands/spec/link/depends.d.ts +18 -0
- package/dist/commands/spec/link/depends.js +86 -0
- package/dist/commands/spec/link/index.d.ts +17 -0
- package/dist/commands/spec/link/index.js +92 -0
- package/dist/commands/spec/link/remove.d.ts +18 -0
- package/dist/commands/spec/link/remove.js +90 -0
- package/dist/commands/support/logs.js +2 -2
- package/dist/commands/template/apply.js +5 -4
- package/dist/commands/template/create.js +1 -1
- package/dist/commands/ticket/link/block.d.ts +15 -0
- package/dist/commands/ticket/link/block.js +95 -0
- package/dist/commands/ticket/link/index.d.ts +14 -0
- package/dist/commands/ticket/link/index.js +96 -0
- package/dist/commands/ticket/list.d.ts +1 -0
- package/dist/commands/ticket/list.js +6 -0
- package/dist/commands/ticket/resolve.js +1 -1
- package/dist/commands/ticket/template/apply.d.ts +26 -0
- package/dist/commands/ticket/template/apply.js +14 -0
- package/dist/commands/ticket/template/delete.d.ts +18 -0
- package/dist/commands/ticket/template/delete.js +61 -0
- package/dist/commands/ticket/template/list.d.ts +17 -0
- package/dist/commands/ticket/template/list.js +77 -0
- package/dist/commands/ticket/template/save.d.ts +17 -0
- package/dist/commands/ticket/template/save.js +97 -0
- package/dist/commands/ticket/view.d.ts +1 -0
- package/dist/commands/ticket/view.js +1 -0
- package/dist/commands/work/ready.js +17 -0
- package/dist/commands/work/resolve.js +1 -1
- package/dist/commands/work/spawn.js +4 -4
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +52 -17
- package/dist/lib/database/index.d.ts +1 -1
- package/dist/lib/database/index.js +20 -0
- package/dist/lib/execution/devcontainer.js +3 -1
- package/dist/lib/execution/runners.d.ts +7 -2
- package/dist/lib/execution/runners.js +18 -10
- package/dist/lib/execution/types.d.ts +1 -0
- package/dist/lib/flags/resolver.js +1 -0
- package/dist/lib/mcp/helpers.d.ts +1 -2
- package/dist/lib/mcp/tools/diet.js +1 -0
- package/dist/lib/mcp/tools/index.d.ts +1 -0
- package/dist/lib/mcp/tools/index.js +1 -0
- package/dist/lib/mcp/tools/label.d.ts +6 -0
- package/dist/lib/mcp/tools/label.js +338 -0
- package/dist/lib/mcp/tools/ticket.js +53 -17
- package/dist/lib/multiline-input.js +6 -18
- package/dist/lib/pmo/base-command.d.ts +0 -1
- package/dist/lib/pmo/base-command.js +0 -1
- package/dist/lib/pmo/schema.d.ts +6 -0
- package/dist/lib/pmo/schema.js +44 -0
- package/dist/lib/pmo/storage/base.d.ts +6 -0
- package/dist/lib/pmo/storage/base.js +116 -2
- package/dist/lib/pmo/storage/index.d.ts +23 -1
- package/dist/lib/pmo/storage/index.js +59 -1
- package/dist/lib/pmo/storage/labels.d.ts +55 -0
- package/dist/lib/pmo/storage/labels.js +346 -0
- package/dist/lib/pmo/storage/tickets.js +17 -0
- package/dist/lib/pmo/storage/types.d.ts +24 -0
- package/dist/lib/pmo/types.d.ts +44 -0
- package/dist/lib/pmo/utils.js +1 -1
- package/oclif.manifest.json +5702 -3660
- 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
|
|
58
|
-
|
|
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('
|
|
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
|
-
|
|
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('
|
|
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('
|
|
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
|
-
|
|
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
|
+
}
|