@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.
Files changed (134) hide show
  1. package/dist/commands/action/create.js +3 -3
  2. package/dist/commands/action/index.js +2 -2
  3. package/dist/commands/action/update.js +3 -3
  4. package/dist/commands/agent/auth.js +1 -1
  5. package/dist/commands/agent/cleanup.js +6 -6
  6. package/dist/commands/agent/discover.js +1 -1
  7. package/dist/commands/agent/remove.js +4 -4
  8. package/dist/commands/autocomplete/setup.d.ts +2 -2
  9. package/dist/commands/autocomplete/setup.js +5 -5
  10. package/dist/commands/branch/create.js +31 -30
  11. package/dist/commands/category/create.js +4 -5
  12. package/dist/commands/category/delete.js +2 -3
  13. package/dist/commands/category/rename.js +2 -3
  14. package/dist/commands/claude.d.ts +2 -8
  15. package/dist/commands/claude.js +26 -26
  16. package/dist/commands/commit.d.ts +2 -8
  17. package/dist/commands/commit.js +4 -26
  18. package/dist/commands/config/index.d.ts +2 -10
  19. package/dist/commands/config/index.js +8 -34
  20. package/dist/commands/docker/index.d.ts +2 -2
  21. package/dist/commands/docker/index.js +8 -8
  22. package/dist/commands/epic/activate.js +9 -17
  23. package/dist/commands/epic/archive.js +13 -24
  24. package/dist/commands/epic/create.js +7 -6
  25. package/dist/commands/epic/delete.js +4 -5
  26. package/dist/commands/epic/move.js +28 -47
  27. package/dist/commands/epic/progress.js +10 -14
  28. package/dist/commands/epic/project.js +42 -59
  29. package/dist/commands/epic/reorder.js +25 -30
  30. package/dist/commands/epic/spec.d.ts +1 -0
  31. package/dist/commands/epic/spec.js +39 -40
  32. package/dist/commands/epic/ticket.d.ts +2 -0
  33. package/dist/commands/epic/ticket.js +63 -37
  34. package/dist/commands/feedback/index.d.ts +10 -0
  35. package/dist/commands/feedback/index.js +60 -0
  36. package/dist/commands/feedback/list.d.ts +12 -0
  37. package/dist/commands/feedback/list.js +126 -0
  38. package/dist/commands/feedback/submit.d.ts +16 -0
  39. package/dist/commands/feedback/submit.js +220 -0
  40. package/dist/commands/feedback/view.d.ts +15 -0
  41. package/dist/commands/feedback/view.js +109 -0
  42. package/dist/commands/gh/index.js +4 -0
  43. package/dist/commands/link/index.js +2 -2
  44. package/dist/commands/pmo/init.d.ts +2 -2
  45. package/dist/commands/pmo/init.js +7 -7
  46. package/dist/commands/project/spec.js +6 -6
  47. package/dist/commands/repo/create.d.ts +38 -0
  48. package/dist/commands/repo/create.js +283 -0
  49. package/dist/commands/repo/index.js +7 -0
  50. package/dist/commands/roadmap/add-project.js +9 -22
  51. package/dist/commands/roadmap/create.d.ts +0 -1
  52. package/dist/commands/roadmap/create.js +46 -40
  53. package/dist/commands/roadmap/delete.js +10 -24
  54. package/dist/commands/roadmap/generate.d.ts +1 -0
  55. package/dist/commands/roadmap/generate.js +21 -22
  56. package/dist/commands/roadmap/remove-project.js +14 -34
  57. package/dist/commands/roadmap/reorder.js +19 -26
  58. package/dist/commands/roadmap/update.js +27 -26
  59. package/dist/commands/roadmap/view.js +5 -12
  60. package/dist/commands/session/attach.d.ts +1 -8
  61. package/dist/commands/session/attach.js +93 -59
  62. package/dist/commands/session/health.d.ts +29 -0
  63. package/dist/commands/session/health.js +495 -0
  64. package/dist/commands/session/index.js +4 -0
  65. package/dist/commands/session/list.d.ts +0 -8
  66. package/dist/commands/session/list.js +130 -81
  67. package/dist/commands/spec/create.js +1 -1
  68. package/dist/commands/spec/edit.js +64 -35
  69. package/dist/commands/staff/add.d.ts +2 -2
  70. package/dist/commands/staff/add.js +15 -14
  71. package/dist/commands/staff/index.js +2 -2
  72. package/dist/commands/staff/remove.js +4 -4
  73. package/dist/commands/status/index.js +6 -7
  74. package/dist/commands/support/book.d.ts +10 -0
  75. package/dist/commands/support/book.js +54 -0
  76. package/dist/commands/support/discord.d.ts +10 -0
  77. package/dist/commands/support/discord.js +54 -0
  78. package/dist/commands/support/docs.d.ts +10 -0
  79. package/dist/commands/support/docs.js +54 -0
  80. package/dist/commands/support/index.d.ts +19 -0
  81. package/dist/commands/support/index.js +81 -0
  82. package/dist/commands/support/issues.d.ts +11 -0
  83. package/dist/commands/support/issues.js +77 -0
  84. package/dist/commands/support/logs.d.ts +18 -0
  85. package/dist/commands/support/logs.js +247 -0
  86. package/dist/commands/template/apply.js +10 -11
  87. package/dist/commands/template/create.js +18 -17
  88. package/dist/commands/template/index.d.ts +2 -2
  89. package/dist/commands/template/index.js +6 -6
  90. package/dist/commands/template/save.js +8 -7
  91. package/dist/commands/template/update.js +6 -7
  92. package/dist/commands/terminal/title.d.ts +2 -26
  93. package/dist/commands/terminal/title.js +4 -33
  94. package/dist/commands/theme/index.d.ts +2 -2
  95. package/dist/commands/theme/index.js +19 -18
  96. package/dist/commands/theme/set.d.ts +2 -2
  97. package/dist/commands/theme/set.js +5 -5
  98. package/dist/commands/ticket/create.js +52 -26
  99. package/dist/commands/ticket/delete.js +15 -13
  100. package/dist/commands/ticket/edit.js +59 -20
  101. package/dist/commands/ticket/epic.js +12 -10
  102. package/dist/commands/ticket/move.d.ts +7 -0
  103. package/dist/commands/ticket/move.js +132 -0
  104. package/dist/commands/ticket/project.js +11 -9
  105. package/dist/commands/ticket/reassign.js +23 -19
  106. package/dist/commands/ticket/spec.js +7 -5
  107. package/dist/commands/ticket/update.js +55 -53
  108. package/dist/commands/whoami.js +1 -0
  109. package/dist/commands/work/ready.js +7 -7
  110. package/dist/commands/work/revise.js +13 -11
  111. package/dist/commands/work/spawn.d.ts +1 -0
  112. package/dist/commands/work/spawn.js +225 -64
  113. package/dist/commands/work/start.d.ts +1 -0
  114. package/dist/commands/work/start.js +301 -173
  115. package/dist/hooks/init.js +4 -0
  116. package/dist/lib/execution/runners.js +21 -17
  117. package/dist/lib/execution/session-utils.d.ts +60 -0
  118. package/dist/lib/execution/session-utils.js +162 -0
  119. package/dist/lib/execution/spawner.d.ts +2 -0
  120. package/dist/lib/execution/spawner.js +42 -0
  121. package/dist/lib/flags/resolver.d.ts +2 -2
  122. package/dist/lib/flags/resolver.js +15 -0
  123. package/dist/lib/init/index.js +18 -0
  124. package/dist/lib/multiline-input.d.ts +63 -0
  125. package/dist/lib/multiline-input.js +360 -0
  126. package/dist/lib/pr/index.d.ts +4 -0
  127. package/dist/lib/pr/index.js +32 -14
  128. package/dist/lib/prompt-command.d.ts +3 -0
  129. package/dist/lib/prompt-json.d.ts +77 -6
  130. package/dist/lib/prompt-json.js +46 -0
  131. package/dist/lib/repos/git.d.ts +7 -0
  132. package/dist/lib/repos/git.js +20 -0
  133. package/oclif.manifest.json +2913 -2246
  134. 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, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
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
- if (jsonMode) {
54
- const choices = roadmaps.map(r => ({
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
- if (jsonMode) {
97
- const choices = availableProjects.map(p => ({
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
@@ -18,5 +18,4 @@ export default class RoadmapCreate extends PMOCommand {
18
18
  promptIfMultiple: boolean;
19
19
  };
20
20
  execute(): Promise<void>;
21
- private promptRoadmapData;
22
21
  }
@@ -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, outputPromptAsJson, createMetadata, buildFormPromptConfig, } from '../../lib/prompt-json.js';
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 fields = [
58
- { type: 'input', name: 'name', message: 'Roadmap name:', default: flags.name },
59
- { type: 'input', name: 'id', message: 'Roadmap ID (leave blank to auto-generate):' },
60
- { type: 'input', name: 'description', message: 'Description (optional):', default: flags.description },
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
- if (jsonMode) {
73
- outputPromptAsJson(buildFormPromptConfig(fields), createMetadata('roadmap create', flags));
74
- return;
75
- }
76
- roadmapData = await this.promptRoadmapData(fields);
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 inquirer.prompt([{
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 inquirer.prompt([{
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 => ({ name: p.name, value: p.id })),
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, outputPromptAsJson, outputErrorAsJson, createMetadata, buildPromptConfig, } from '../../lib/prompt-json.js';
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
- if (jsonMode) {
51
- const choices = roadmaps.map(r => ({
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
- if (jsonMode) {
91
- const confirmChoices = [
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
  };