@proletariat/cli 0.3.24 → 0.3.26
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 +3 -3
- package/dist/commands/action/index.js +2 -2
- package/dist/commands/action/update.js +3 -3
- package/dist/commands/agent/auth.js +1 -1
- package/dist/commands/agent/cleanup.js +6 -6
- package/dist/commands/agent/discover.js +1 -1
- package/dist/commands/agent/remove.js +4 -4
- package/dist/commands/autocomplete/setup.d.ts +2 -2
- package/dist/commands/autocomplete/setup.js +5 -5
- package/dist/commands/branch/create.js +31 -30
- package/dist/commands/category/create.js +4 -5
- package/dist/commands/category/delete.js +2 -3
- package/dist/commands/category/rename.js +2 -3
- package/dist/commands/claude.d.ts +2 -8
- package/dist/commands/claude.js +26 -26
- package/dist/commands/commit.d.ts +2 -8
- package/dist/commands/commit.js +4 -26
- package/dist/commands/config/index.d.ts +2 -10
- package/dist/commands/config/index.js +8 -34
- package/dist/commands/docker/index.d.ts +2 -2
- package/dist/commands/docker/index.js +8 -8
- package/dist/commands/epic/activate.js +9 -17
- package/dist/commands/epic/archive.js +13 -24
- package/dist/commands/epic/create.js +7 -6
- package/dist/commands/epic/delete.js +4 -5
- package/dist/commands/epic/move.js +28 -47
- package/dist/commands/epic/progress.js +10 -14
- package/dist/commands/epic/project.js +42 -59
- package/dist/commands/epic/reorder.js +25 -30
- package/dist/commands/epic/spec.d.ts +1 -0
- package/dist/commands/epic/spec.js +39 -40
- package/dist/commands/epic/ticket.d.ts +2 -0
- package/dist/commands/epic/ticket.js +63 -37
- package/dist/commands/feedback/index.d.ts +10 -0
- package/dist/commands/feedback/index.js +60 -0
- package/dist/commands/feedback/list.d.ts +12 -0
- package/dist/commands/feedback/list.js +126 -0
- package/dist/commands/feedback/submit.d.ts +16 -0
- package/dist/commands/feedback/submit.js +220 -0
- package/dist/commands/feedback/view.d.ts +15 -0
- package/dist/commands/feedback/view.js +109 -0
- package/dist/commands/gh/index.js +4 -0
- package/dist/commands/link/index.js +2 -2
- package/dist/commands/pmo/init.d.ts +2 -2
- package/dist/commands/pmo/init.js +7 -7
- package/dist/commands/project/spec.js +6 -6
- package/dist/commands/repo/create.d.ts +38 -0
- package/dist/commands/repo/create.js +283 -0
- package/dist/commands/repo/index.js +7 -0
- package/dist/commands/roadmap/add-project.js +9 -22
- package/dist/commands/roadmap/create.d.ts +0 -1
- package/dist/commands/roadmap/create.js +46 -40
- package/dist/commands/roadmap/delete.js +10 -24
- package/dist/commands/roadmap/generate.d.ts +1 -0
- package/dist/commands/roadmap/generate.js +21 -22
- package/dist/commands/roadmap/remove-project.js +14 -34
- package/dist/commands/roadmap/reorder.js +19 -26
- package/dist/commands/roadmap/update.js +27 -26
- package/dist/commands/roadmap/view.js +5 -12
- package/dist/commands/session/attach.d.ts +1 -8
- package/dist/commands/session/attach.js +93 -59
- package/dist/commands/session/health.d.ts +29 -0
- package/dist/commands/session/health.js +495 -0
- package/dist/commands/session/index.js +4 -0
- package/dist/commands/session/list.d.ts +0 -8
- package/dist/commands/session/list.js +130 -81
- package/dist/commands/spec/create.js +1 -1
- package/dist/commands/spec/edit.js +64 -35
- package/dist/commands/staff/add.d.ts +2 -2
- package/dist/commands/staff/add.js +15 -14
- package/dist/commands/staff/index.js +2 -2
- package/dist/commands/staff/remove.js +4 -4
- package/dist/commands/status/index.js +6 -7
- package/dist/commands/support/book.d.ts +10 -0
- package/dist/commands/support/book.js +54 -0
- package/dist/commands/support/discord.d.ts +10 -0
- package/dist/commands/support/discord.js +54 -0
- package/dist/commands/support/docs.d.ts +10 -0
- package/dist/commands/support/docs.js +54 -0
- package/dist/commands/support/index.d.ts +19 -0
- package/dist/commands/support/index.js +81 -0
- package/dist/commands/support/issues.d.ts +11 -0
- package/dist/commands/support/issues.js +77 -0
- package/dist/commands/support/logs.d.ts +18 -0
- package/dist/commands/support/logs.js +247 -0
- package/dist/commands/template/apply.js +10 -11
- package/dist/commands/template/create.js +18 -17
- package/dist/commands/template/index.d.ts +2 -2
- package/dist/commands/template/index.js +6 -6
- package/dist/commands/template/save.js +8 -7
- package/dist/commands/template/update.js +6 -7
- package/dist/commands/terminal/title.d.ts +2 -26
- package/dist/commands/terminal/title.js +4 -33
- package/dist/commands/theme/index.d.ts +2 -2
- package/dist/commands/theme/index.js +19 -18
- package/dist/commands/theme/set.d.ts +2 -2
- package/dist/commands/theme/set.js +5 -5
- package/dist/commands/ticket/create.js +52 -26
- package/dist/commands/ticket/delete.js +15 -13
- package/dist/commands/ticket/edit.js +59 -20
- package/dist/commands/ticket/epic.js +12 -10
- package/dist/commands/ticket/move.d.ts +7 -0
- package/dist/commands/ticket/move.js +132 -0
- package/dist/commands/ticket/project.js +11 -9
- package/dist/commands/ticket/reassign.js +23 -19
- package/dist/commands/ticket/spec.js +7 -5
- package/dist/commands/ticket/update.js +55 -53
- package/dist/commands/whoami.js +1 -0
- package/dist/commands/work/ready.js +7 -7
- package/dist/commands/work/revise.js +13 -11
- package/dist/commands/work/spawn.d.ts +1 -0
- package/dist/commands/work/spawn.js +225 -64
- package/dist/commands/work/start.d.ts +1 -0
- package/dist/commands/work/start.js +301 -173
- package/dist/hooks/init.js +4 -0
- package/dist/lib/execution/runners.js +21 -17
- package/dist/lib/execution/session-utils.d.ts +60 -0
- package/dist/lib/execution/session-utils.js +162 -0
- package/dist/lib/execution/spawner.d.ts +2 -0
- package/dist/lib/execution/spawner.js +42 -0
- package/dist/lib/flags/resolver.d.ts +2 -2
- package/dist/lib/flags/resolver.js +15 -0
- package/dist/lib/init/index.js +18 -0
- package/dist/lib/multiline-input.d.ts +63 -0
- package/dist/lib/multiline-input.js +360 -0
- package/dist/lib/pr/index.d.ts +4 -0
- package/dist/lib/pr/index.js +32 -14
- package/dist/lib/prompt-command.d.ts +3 -0
- package/dist/lib/prompt-json.d.ts +77 -6
- package/dist/lib/prompt-json.js +46 -0
- package/dist/lib/repos/git.d.ts +7 -0
- package/dist/lib/repos/git.js +20 -0
- package/oclif.manifest.json +2913 -2246
- package/package.json +1 -1
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { PMOCommand } from '../../lib/pmo/index.js';
|
|
2
|
+
interface CreateRepoResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
url?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Get the user's GitHub organizations.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getGHOrganizations(): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Create a GitHub repository using `gh` CLI.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createGHRepo(options: {
|
|
16
|
+
name: string;
|
|
17
|
+
visibility: 'public' | 'private';
|
|
18
|
+
org?: string;
|
|
19
|
+
cwd?: string;
|
|
20
|
+
push?: boolean;
|
|
21
|
+
}): CreateRepoResult;
|
|
22
|
+
export default class Create extends PMOCommand {
|
|
23
|
+
static description: string;
|
|
24
|
+
static examples: string[];
|
|
25
|
+
static flags: {
|
|
26
|
+
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
27
|
+
visibility: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
|
+
org: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
29
|
+
push: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
30
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
31
|
+
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
32
|
+
};
|
|
33
|
+
protected getPMOOptions(): {
|
|
34
|
+
promptIfMultiple: boolean;
|
|
35
|
+
};
|
|
36
|
+
execute(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { execSync, spawnSync } from 'node:child_process';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
5
|
+
import { colors, format } from '../../lib/colors.js';
|
|
6
|
+
import { findHQRoot, isInGitRepo } from '../../lib/repos/index.js';
|
|
7
|
+
import { hasGitHubRemote } from '../../lib/repos/git.js';
|
|
8
|
+
import { isGHInstalled, isGHAuthenticated, getGHUsername, } from '../../lib/pr/index.js';
|
|
9
|
+
import { shouldOutputJson, outputSuccessAsJson, outputErrorAsJson, outputPromptAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
|
|
10
|
+
import { addRepositoriesToDatabase } from '../../lib/database/index.js';
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// GitHub Helpers
|
|
13
|
+
// =============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Get the user's GitHub organizations.
|
|
16
|
+
*/
|
|
17
|
+
export function getGHOrganizations() {
|
|
18
|
+
try {
|
|
19
|
+
const result = execSync('gh api user/orgs --jq ".[].login"', {
|
|
20
|
+
encoding: 'utf-8',
|
|
21
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
22
|
+
}).trim();
|
|
23
|
+
return result ? result.split('\n').filter(Boolean) : [];
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create a GitHub repository using `gh` CLI.
|
|
31
|
+
*/
|
|
32
|
+
export function createGHRepo(options) {
|
|
33
|
+
const { name, visibility, org, cwd, push = true } = options;
|
|
34
|
+
const repoName = org ? `${org}/${name}` : name;
|
|
35
|
+
const args = [
|
|
36
|
+
'repo', 'create', repoName,
|
|
37
|
+
`--${visibility}`,
|
|
38
|
+
'--source=.',
|
|
39
|
+
'--remote=origin',
|
|
40
|
+
];
|
|
41
|
+
if (push) {
|
|
42
|
+
args.push('--push');
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const result = spawnSync('gh', args, {
|
|
46
|
+
cwd,
|
|
47
|
+
encoding: 'utf-8',
|
|
48
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
49
|
+
});
|
|
50
|
+
if (result.status !== 0) {
|
|
51
|
+
return {
|
|
52
|
+
success: false,
|
|
53
|
+
error: result.stderr || 'Failed to create repository',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Parse the repo URL from stdout
|
|
57
|
+
const url = result.stdout.trim();
|
|
58
|
+
return {
|
|
59
|
+
success: true,
|
|
60
|
+
url,
|
|
61
|
+
name: repoName,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
success: false,
|
|
67
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// Command
|
|
73
|
+
// =============================================================================
|
|
74
|
+
export default class Create extends PMOCommand {
|
|
75
|
+
static description = 'Create a GitHub repository and set up remote';
|
|
76
|
+
static examples = [
|
|
77
|
+
'<%= config.bin %> <%= command.id %>',
|
|
78
|
+
'<%= config.bin %> <%= command.id %> --name my-repo --visibility private',
|
|
79
|
+
'<%= config.bin %> <%= command.id %> --name my-repo --org my-company',
|
|
80
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
81
|
+
];
|
|
82
|
+
static flags = {
|
|
83
|
+
...pmoBaseFlags,
|
|
84
|
+
name: Flags.string({
|
|
85
|
+
char: 'n',
|
|
86
|
+
description: 'Repository name (defaults to current directory name)',
|
|
87
|
+
}),
|
|
88
|
+
visibility: Flags.string({
|
|
89
|
+
char: 'v',
|
|
90
|
+
description: 'Repository visibility',
|
|
91
|
+
options: ['public', 'private'],
|
|
92
|
+
default: 'private',
|
|
93
|
+
}),
|
|
94
|
+
org: Flags.string({
|
|
95
|
+
char: 'o',
|
|
96
|
+
description: 'GitHub organization (creates personal repo if not specified)',
|
|
97
|
+
}),
|
|
98
|
+
push: Flags.boolean({
|
|
99
|
+
description: 'Push initial commit after creating repo',
|
|
100
|
+
default: true,
|
|
101
|
+
allowNo: true,
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
getPMOOptions() {
|
|
105
|
+
return { promptIfMultiple: false };
|
|
106
|
+
}
|
|
107
|
+
async execute() {
|
|
108
|
+
const { flags } = await this.parse(Create);
|
|
109
|
+
const jsonMode = shouldOutputJson(flags);
|
|
110
|
+
const metadata = createMetadata('repo create', flags);
|
|
111
|
+
const handleError = (code, message) => {
|
|
112
|
+
if (jsonMode) {
|
|
113
|
+
outputErrorAsJson(code, message, metadata);
|
|
114
|
+
this.exit(1);
|
|
115
|
+
}
|
|
116
|
+
this.error(message);
|
|
117
|
+
};
|
|
118
|
+
// Check prerequisites
|
|
119
|
+
if (!isGHInstalled()) {
|
|
120
|
+
return handleError('GH_NOT_INSTALLED', 'GitHub CLI (gh) is not installed. Install with: brew install gh');
|
|
121
|
+
}
|
|
122
|
+
if (!isGHAuthenticated()) {
|
|
123
|
+
return handleError('GH_NOT_AUTHENTICATED', 'Not authenticated with GitHub. Run: gh auth login');
|
|
124
|
+
}
|
|
125
|
+
// Must be in a git repo
|
|
126
|
+
if (!isInGitRepo()) {
|
|
127
|
+
return handleError('NOT_GIT_REPO', 'Not in a git repository. Initialize one with: git init');
|
|
128
|
+
}
|
|
129
|
+
// Check if remote already exists
|
|
130
|
+
if (hasGitHubRemote()) {
|
|
131
|
+
return handleError('REMOTE_EXISTS', 'This repository already has a GitHub remote configured.');
|
|
132
|
+
}
|
|
133
|
+
// Gather parameters
|
|
134
|
+
let repoName = flags.name;
|
|
135
|
+
let visibility = flags.visibility;
|
|
136
|
+
let org = flags.org;
|
|
137
|
+
// Get default repo name from directory
|
|
138
|
+
if (!repoName) {
|
|
139
|
+
repoName = path.basename(process.cwd());
|
|
140
|
+
}
|
|
141
|
+
// Prompt for repo name
|
|
142
|
+
const nameMessage = 'Repository name:';
|
|
143
|
+
if (jsonMode) {
|
|
144
|
+
if (!flags.name) {
|
|
145
|
+
outputPromptAsJson(buildPromptConfig('input', 'repoName', nameMessage, undefined, repoName), metadata);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
const nameResult = await this.prompt([{
|
|
151
|
+
type: 'input',
|
|
152
|
+
name: 'repoName',
|
|
153
|
+
message: nameMessage,
|
|
154
|
+
default: repoName,
|
|
155
|
+
validate: (input) => {
|
|
156
|
+
const value = String(input || '');
|
|
157
|
+
if (!value.trim())
|
|
158
|
+
return 'Repository name is required';
|
|
159
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(value)) {
|
|
160
|
+
return 'Repository name can only contain letters, numbers, dots, hyphens, and underscores';
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
},
|
|
164
|
+
}], null);
|
|
165
|
+
repoName = nameResult.repoName;
|
|
166
|
+
}
|
|
167
|
+
// Prompt for visibility
|
|
168
|
+
const visibilityChoices = [
|
|
169
|
+
{ name: 'Private', value: 'private' },
|
|
170
|
+
{ name: 'Public', value: 'public' },
|
|
171
|
+
];
|
|
172
|
+
const visibilityMessage = 'Repository visibility:';
|
|
173
|
+
if (jsonMode) {
|
|
174
|
+
if (!flags.visibility) {
|
|
175
|
+
outputPromptAsJson(buildPromptConfig('list', 'visibility', visibilityMessage, visibilityChoices, visibility), metadata);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const visibilityResult = await this.prompt([{
|
|
181
|
+
type: 'list',
|
|
182
|
+
name: 'visibility',
|
|
183
|
+
message: visibilityMessage,
|
|
184
|
+
choices: visibilityChoices,
|
|
185
|
+
default: visibility,
|
|
186
|
+
}], null);
|
|
187
|
+
visibility = visibilityResult.visibility;
|
|
188
|
+
}
|
|
189
|
+
// Prompt for org if orgs are available
|
|
190
|
+
const orgs = getGHOrganizations();
|
|
191
|
+
const username = getGHUsername();
|
|
192
|
+
if (orgs.length > 0 && !flags.org) {
|
|
193
|
+
const ownerChoices = [
|
|
194
|
+
{ name: `${username || 'Personal'} (personal account)`, value: '' },
|
|
195
|
+
...orgs.map(o => ({ name: o, value: o })),
|
|
196
|
+
];
|
|
197
|
+
const orgMessage = 'Create repository under:';
|
|
198
|
+
if (jsonMode) {
|
|
199
|
+
outputPromptAsJson(buildPromptConfig('list', 'org', orgMessage, ownerChoices), metadata);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const orgResult = await this.prompt([{
|
|
203
|
+
type: 'list',
|
|
204
|
+
name: 'org',
|
|
205
|
+
message: orgMessage,
|
|
206
|
+
choices: ownerChoices,
|
|
207
|
+
}], null);
|
|
208
|
+
org = orgResult.org || undefined;
|
|
209
|
+
}
|
|
210
|
+
// Confirm creation (interactive only)
|
|
211
|
+
if (!jsonMode) {
|
|
212
|
+
this.log('');
|
|
213
|
+
this.log(colors.primary('Creating GitHub repository:'));
|
|
214
|
+
this.log(` Name: ${org ? `${org}/${repoName}` : repoName}`);
|
|
215
|
+
this.log(` Visibility: ${visibility}`);
|
|
216
|
+
this.log(` Push initial commit: ${flags.push ? 'Yes' : 'No'}`);
|
|
217
|
+
this.log('');
|
|
218
|
+
const confirmChoices = [
|
|
219
|
+
{ name: 'Yes', value: true },
|
|
220
|
+
{ name: 'No', value: false },
|
|
221
|
+
];
|
|
222
|
+
const confirmResult = await this.prompt([{
|
|
223
|
+
type: 'list',
|
|
224
|
+
name: 'confirm',
|
|
225
|
+
message: 'Proceed with creation?',
|
|
226
|
+
choices: confirmChoices,
|
|
227
|
+
}], null);
|
|
228
|
+
if (!confirmResult.confirm) {
|
|
229
|
+
this.log(colors.textMuted('Operation cancelled.'));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Create the repository
|
|
234
|
+
if (!jsonMode) {
|
|
235
|
+
this.log(colors.primary('Creating GitHub repository...'));
|
|
236
|
+
}
|
|
237
|
+
const result = createGHRepo({
|
|
238
|
+
name: repoName,
|
|
239
|
+
visibility,
|
|
240
|
+
org,
|
|
241
|
+
push: flags.push,
|
|
242
|
+
});
|
|
243
|
+
if (!result.success) {
|
|
244
|
+
return handleError('CREATE_FAILED', `Failed to create repository: ${result.error}`);
|
|
245
|
+
}
|
|
246
|
+
// Update prlt database if in HQ
|
|
247
|
+
const hqPath = findHQRoot();
|
|
248
|
+
if (hqPath) {
|
|
249
|
+
try {
|
|
250
|
+
// Use the actual local folder name for the DB path, not repoName
|
|
251
|
+
// (repoName may differ if user overrides it via --name)
|
|
252
|
+
const localFolderName = path.basename(process.cwd());
|
|
253
|
+
addRepositoriesToDatabase(hqPath, [{
|
|
254
|
+
name: repoName,
|
|
255
|
+
path: `repos/${localFolderName}`,
|
|
256
|
+
source_url: result.url,
|
|
257
|
+
}]);
|
|
258
|
+
if (!jsonMode) {
|
|
259
|
+
this.log(colors.textMuted('Updated prlt workspace database.'));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// Ignore database update errors - repo was still created
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Success output
|
|
267
|
+
if (jsonMode) {
|
|
268
|
+
outputSuccessAsJson({
|
|
269
|
+
created: true,
|
|
270
|
+
name: result.name,
|
|
271
|
+
url: result.url,
|
|
272
|
+
visibility,
|
|
273
|
+
org: org || null,
|
|
274
|
+
}, metadata);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
this.log('');
|
|
278
|
+
this.log(format.success(`Repository created: ${result.url}`));
|
|
279
|
+
this.log('');
|
|
280
|
+
this.log(colors.textMuted('Your local repository is now connected to GitHub.'));
|
|
281
|
+
this.log(colors.textMuted('You can push changes with: git push'));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
@@ -23,6 +23,7 @@ export default class Repo extends PMOCommand {
|
|
|
23
23
|
const menuChoices = [
|
|
24
24
|
{ name: 'List all repositories', value: 'list', command: 'prlt repo list --json' },
|
|
25
25
|
{ name: 'Add repository', value: 'add', command: 'prlt repo add --json' },
|
|
26
|
+
{ name: 'Create GitHub repository', value: 'create', command: 'prlt repo create --json' },
|
|
26
27
|
{ name: 'Remove repository', value: 'remove', command: 'prlt repo remove --json' },
|
|
27
28
|
{ name: 'View repository details', value: 'view', command: 'prlt repo view --json' },
|
|
28
29
|
{ name: 'Add multiple repositories', value: 'add-bulk', command: 'prlt repo add --bulk --json' },
|
|
@@ -55,6 +56,12 @@ export default class Repo extends PMOCommand {
|
|
|
55
56
|
await cmd.run();
|
|
56
57
|
break;
|
|
57
58
|
}
|
|
59
|
+
case 'create': {
|
|
60
|
+
const { default: CreateCommand } = await import('./create.js');
|
|
61
|
+
const cmd = new CreateCommand([], this.config);
|
|
62
|
+
await cmd.run();
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
58
65
|
case 'add': {
|
|
59
66
|
const { default: AddCommand } = await import('./add.js');
|
|
60
67
|
const cmd = new AddCommand([], this.config);
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
2
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
4
3
|
import { styles } from '../../lib/styles.js';
|
|
5
|
-
import { shouldOutputJson,
|
|
4
|
+
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
6
5
|
export default class RoadmapAddProject extends PMOCommand {
|
|
7
6
|
static description = 'Add a project to a roadmap';
|
|
8
7
|
static examples = [
|
|
@@ -50,23 +49,17 @@ export default class RoadmapAddProject extends PMOCommand {
|
|
|
50
49
|
}
|
|
51
50
|
this.error('No roadmaps found. Create one with: prlt roadmap create');
|
|
52
51
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
name: `${r.name}${r.isDefault ? ' (default)' : ''}`,
|
|
56
|
-
value: r.id,
|
|
57
|
-
}));
|
|
58
|
-
outputPromptAsJson(buildPromptConfig('list', 'roadmap', 'Select roadmap:', choices), createMetadata('roadmap add-project', flags));
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
const { selected } = await inquirer.prompt([{
|
|
52
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'roadmap add-project' } : null;
|
|
53
|
+
const { selected } = await this.prompt([{
|
|
62
54
|
type: 'list',
|
|
63
55
|
name: 'selected',
|
|
64
56
|
message: 'Select roadmap:',
|
|
65
57
|
choices: roadmaps.map(r => ({
|
|
66
58
|
name: `${r.name}${r.isDefault ? ' (default)' : ''}`,
|
|
67
59
|
value: r.id,
|
|
60
|
+
command: `prlt roadmap add-project "${r.id}" --json`,
|
|
68
61
|
})),
|
|
69
|
-
}]);
|
|
62
|
+
}], jsonModeConfig);
|
|
70
63
|
roadmapId = selected;
|
|
71
64
|
}
|
|
72
65
|
const roadmap = await this.storage.getRoadmap(roadmapId);
|
|
@@ -93,23 +86,17 @@ export default class RoadmapAddProject extends PMOCommand {
|
|
|
93
86
|
// Select project
|
|
94
87
|
let projectId = args.project;
|
|
95
88
|
if (!projectId) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
name: p.name,
|
|
99
|
-
value: p.id,
|
|
100
|
-
}));
|
|
101
|
-
outputPromptAsJson(buildPromptConfig('list', 'project', 'Select project to add:', choices), createMetadata('roadmap add-project', flags));
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const { selected } = await inquirer.prompt([{
|
|
89
|
+
const projectJsonModeConfig = jsonMode ? { flags, commandName: 'roadmap add-project' } : null;
|
|
90
|
+
const { selected } = await this.prompt([{
|
|
105
91
|
type: 'list',
|
|
106
92
|
name: 'selected',
|
|
107
93
|
message: 'Select project to add:',
|
|
108
94
|
choices: availableProjects.map(p => ({
|
|
109
95
|
name: p.name,
|
|
110
96
|
value: p.id,
|
|
97
|
+
command: `prlt roadmap add-project "${roadmapId}" "${p.id}" --json`,
|
|
111
98
|
})),
|
|
112
|
-
}]);
|
|
99
|
+
}], projectJsonModeConfig);
|
|
113
100
|
projectId = selected;
|
|
114
101
|
}
|
|
115
102
|
// Verify project exists and isn't already in roadmap
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { Flags, Args } from '@oclif/core';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
2
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
4
3
|
import { styles } from '../../lib/styles.js';
|
|
5
4
|
import { slugify } from '../../lib/pmo/utils.js';
|
|
6
|
-
import { shouldOutputJson
|
|
5
|
+
import { shouldOutputJson } from '../../lib/prompt-json.js';
|
|
7
6
|
export default class RoadmapCreate extends PMOCommand {
|
|
8
7
|
static description = 'Create a new roadmap';
|
|
9
8
|
static examples = [
|
|
@@ -54,26 +53,46 @@ export default class RoadmapCreate extends PMOCommand {
|
|
|
54
53
|
const jsonMode = shouldOutputJson(flags);
|
|
55
54
|
let roadmapData;
|
|
56
55
|
if (flags.interactive || (!args.name && !flags.name)) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'roadmap create' } : null;
|
|
57
|
+
// Prompt for name - in JSON mode, outputs prompt and exits; agent re-runs with --name flag
|
|
58
|
+
const { name } = await this.prompt([{
|
|
59
|
+
type: 'input',
|
|
60
|
+
name: 'name',
|
|
61
|
+
message: 'Roadmap name:',
|
|
62
|
+
default: flags.name,
|
|
63
|
+
validate: (input) => (typeof input === 'string' && input.length > 0) || 'Name is required',
|
|
64
|
+
}], jsonModeConfig);
|
|
65
|
+
// Prompt for id
|
|
66
|
+
const { id } = await this.prompt([{
|
|
67
|
+
type: 'input',
|
|
68
|
+
name: 'id',
|
|
69
|
+
message: 'Roadmap ID (leave blank to auto-generate):',
|
|
70
|
+
default: `roadmap-${slugify(name)}`,
|
|
71
|
+
}], jsonModeConfig);
|
|
72
|
+
// Prompt for description
|
|
73
|
+
const { description } = await this.prompt([{
|
|
74
|
+
type: 'input',
|
|
75
|
+
name: 'description',
|
|
76
|
+
message: 'Description (optional):',
|
|
77
|
+
default: flags.description,
|
|
78
|
+
}], jsonModeConfig);
|
|
79
|
+
// Prompt for isDefault
|
|
80
|
+
const { isDefault } = await this.prompt([{
|
|
62
81
|
type: 'list',
|
|
63
82
|
name: 'isDefault',
|
|
64
83
|
message: 'Set as default roadmap?',
|
|
65
84
|
choices: [
|
|
66
|
-
{ name: 'No', value: 'false' },
|
|
67
|
-
{ name: 'Yes', value: 'true' },
|
|
85
|
+
{ name: 'No', value: 'false', command: `prlt roadmap create --name "${name}" --json` },
|
|
86
|
+
{ name: 'Yes', value: 'true', command: `prlt roadmap create --name "${name}" --default --json` },
|
|
68
87
|
],
|
|
69
88
|
default: flags.default ? 'true' : 'false',
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
}], jsonModeConfig);
|
|
90
|
+
roadmapData = {
|
|
91
|
+
name,
|
|
92
|
+
id: id || undefined,
|
|
93
|
+
description: description || undefined,
|
|
94
|
+
isDefault: isDefault === 'true',
|
|
95
|
+
};
|
|
77
96
|
}
|
|
78
97
|
else {
|
|
79
98
|
roadmapData = {
|
|
@@ -113,22 +132,26 @@ export default class RoadmapCreate extends PMOCommand {
|
|
|
113
132
|
const projects = await this.storage.listProjects({ isArchived: false });
|
|
114
133
|
if (projects.length > 0) {
|
|
115
134
|
this.log('');
|
|
116
|
-
const { addProjects } = await
|
|
135
|
+
const { addProjects } = await this.prompt([{
|
|
117
136
|
type: 'list',
|
|
118
137
|
name: 'addProjects',
|
|
119
138
|
message: 'Add projects to this roadmap now?',
|
|
120
139
|
choices: [
|
|
121
|
-
{ name: 'Yes', value: true },
|
|
122
|
-
{ name: 'No, I\'ll add them later', value: false },
|
|
140
|
+
{ name: 'Yes', value: true, command: `prlt roadmap add-project "${roadmap.id}" --json` },
|
|
141
|
+
{ name: 'No, I\'ll add them later', value: false, command: '' },
|
|
123
142
|
],
|
|
124
|
-
}]);
|
|
143
|
+
}], null);
|
|
125
144
|
if (addProjects) {
|
|
126
|
-
const { selectedProjects } = await
|
|
145
|
+
const { selectedProjects } = await this.prompt([{
|
|
127
146
|
type: 'checkbox',
|
|
128
147
|
name: 'selectedProjects',
|
|
129
148
|
message: 'Select projects to include:',
|
|
130
|
-
choices: projects.map(p => ({
|
|
131
|
-
|
|
149
|
+
choices: projects.map(p => ({
|
|
150
|
+
name: p.name,
|
|
151
|
+
value: p.id,
|
|
152
|
+
command: `prlt roadmap add-project "${roadmap.id}" "${p.id}" --json`,
|
|
153
|
+
})),
|
|
154
|
+
}], null);
|
|
132
155
|
for (const projectId of selectedProjects) {
|
|
133
156
|
// eslint-disable-next-line no-await-in-loop -- Sequential updates
|
|
134
157
|
await this.storage.addProjectToRoadmap(roadmap.id, projectId);
|
|
@@ -143,21 +166,4 @@ export default class RoadmapCreate extends PMOCommand {
|
|
|
143
166
|
this.log(styles.muted(` prlt roadmap add-project ${roadmap.id}`));
|
|
144
167
|
this.log(styles.muted(` prlt roadmap generate ${roadmap.id}`));
|
|
145
168
|
}
|
|
146
|
-
async promptRoadmapData(fields) {
|
|
147
|
-
const answers = await inquirer.prompt(fields.map(field => ({
|
|
148
|
-
...field,
|
|
149
|
-
validate: field.name === 'name'
|
|
150
|
-
? ((input) => input.length > 0 || 'Name is required')
|
|
151
|
-
: undefined,
|
|
152
|
-
default: field.name === 'id'
|
|
153
|
-
? ((answers) => `roadmap-${slugify(answers.name)}`)
|
|
154
|
-
: field.default,
|
|
155
|
-
})));
|
|
156
|
-
return {
|
|
157
|
-
name: answers.name,
|
|
158
|
-
id: answers.id || undefined,
|
|
159
|
-
description: answers.description || undefined,
|
|
160
|
-
isDefault: answers.isDefault === true || answers.isDefault === 'true',
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
169
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import inquirer from 'inquirer';
|
|
3
2
|
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
4
3
|
import { styles } from '../../lib/styles.js';
|
|
5
|
-
import { shouldOutputJson,
|
|
4
|
+
import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
6
5
|
export default class RoadmapDelete extends PMOCommand {
|
|
7
6
|
static description = 'Delete a roadmap';
|
|
8
7
|
static examples = [
|
|
@@ -47,23 +46,17 @@ export default class RoadmapDelete extends PMOCommand {
|
|
|
47
46
|
}
|
|
48
47
|
this.error('No roadmaps found.');
|
|
49
48
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
name: `${r.name}${r.isDefault ? ' (default)' : ''}`,
|
|
53
|
-
value: r.id,
|
|
54
|
-
}));
|
|
55
|
-
outputPromptAsJson(buildPromptConfig('list', 'id', 'Select roadmap to delete:', choices), createMetadata('roadmap delete', flags));
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const { selected } = await inquirer.prompt([{
|
|
49
|
+
const jsonModeConfig = jsonMode ? { flags, commandName: 'roadmap delete' } : null;
|
|
50
|
+
const { selected } = await this.prompt([{
|
|
59
51
|
type: 'list',
|
|
60
52
|
name: 'selected',
|
|
61
53
|
message: 'Select roadmap to delete:',
|
|
62
54
|
choices: roadmaps.map(r => ({
|
|
63
55
|
name: `${r.name}${r.isDefault ? ' (default)' : ''}`,
|
|
64
56
|
value: r.id,
|
|
57
|
+
command: `prlt roadmap delete "${r.id}" --json`,
|
|
65
58
|
})),
|
|
66
|
-
}]);
|
|
59
|
+
}], jsonModeConfig);
|
|
67
60
|
roadmapId = selected;
|
|
68
61
|
}
|
|
69
62
|
const roadmap = await this.storage.getRoadmap(roadmapId);
|
|
@@ -87,23 +80,16 @@ export default class RoadmapDelete extends PMOCommand {
|
|
|
87
80
|
// Confirm deletion
|
|
88
81
|
if (!flags.force) {
|
|
89
82
|
const message = `Delete roadmap "${roadmap.name}"${projects.length > 0 ? ` (contains ${projects.length} project reference${projects.length > 1 ? 's' : ''})` : ''}?`;
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
{ name: 'No, cancel', value: 'false' },
|
|
93
|
-
{ name: 'Yes, delete', value: 'true' },
|
|
94
|
-
];
|
|
95
|
-
outputPromptAsJson(buildPromptConfig('list', 'confirmed', message, confirmChoices), createMetadata('roadmap delete', flags));
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
const { confirm } = await inquirer.prompt([{
|
|
83
|
+
const confirmJsonModeConfig = jsonMode ? { flags, commandName: 'roadmap delete' } : null;
|
|
84
|
+
const { confirm } = await this.prompt([{
|
|
99
85
|
type: 'list',
|
|
100
86
|
name: 'confirm',
|
|
101
87
|
message,
|
|
102
88
|
choices: [
|
|
103
|
-
{ name: 'No, cancel', value: false },
|
|
104
|
-
{ name: 'Yes, delete', value: true },
|
|
89
|
+
{ name: 'No, cancel', value: false, command: '' },
|
|
90
|
+
{ name: 'Yes, delete', value: true, command: `prlt roadmap delete "${roadmapId}" --force --json` },
|
|
105
91
|
],
|
|
106
|
-
}]);
|
|
92
|
+
}], confirmJsonModeConfig);
|
|
107
93
|
if (!confirm) {
|
|
108
94
|
this.log(styles.muted('Cancelled.'));
|
|
109
95
|
return;
|
|
@@ -8,6 +8,7 @@ export default class RoadmapGenerate extends PMOCommand {
|
|
|
8
8
|
static flags: {
|
|
9
9
|
all: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
10
10
|
output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'exclude-done': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
11
12
|
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
12
13
|
project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
14
|
};
|