@proletariat/cli 0.3.24 → 0.3.25

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 (75) hide show
  1. package/dist/commands/action/create.js +3 -3
  2. package/dist/commands/action/update.js +3 -3
  3. package/dist/commands/epic/activate.js +9 -17
  4. package/dist/commands/epic/archive.js +13 -24
  5. package/dist/commands/epic/create.js +7 -6
  6. package/dist/commands/epic/move.js +28 -47
  7. package/dist/commands/epic/progress.js +10 -14
  8. package/dist/commands/epic/project.js +42 -59
  9. package/dist/commands/epic/reorder.js +25 -30
  10. package/dist/commands/epic/spec.d.ts +1 -0
  11. package/dist/commands/epic/spec.js +39 -40
  12. package/dist/commands/epic/ticket.d.ts +2 -0
  13. package/dist/commands/epic/ticket.js +63 -37
  14. package/dist/commands/feedback/index.d.ts +10 -0
  15. package/dist/commands/feedback/index.js +60 -0
  16. package/dist/commands/feedback/list.d.ts +12 -0
  17. package/dist/commands/feedback/list.js +126 -0
  18. package/dist/commands/feedback/submit.d.ts +16 -0
  19. package/dist/commands/feedback/submit.js +220 -0
  20. package/dist/commands/feedback/view.d.ts +15 -0
  21. package/dist/commands/feedback/view.js +109 -0
  22. package/dist/commands/gh/index.js +4 -0
  23. package/dist/commands/repo/create.d.ts +38 -0
  24. package/dist/commands/repo/create.js +283 -0
  25. package/dist/commands/repo/index.js +7 -0
  26. package/dist/commands/roadmap/add-project.js +9 -22
  27. package/dist/commands/roadmap/create.d.ts +0 -1
  28. package/dist/commands/roadmap/create.js +46 -40
  29. package/dist/commands/roadmap/delete.js +10 -24
  30. package/dist/commands/roadmap/generate.d.ts +1 -0
  31. package/dist/commands/roadmap/generate.js +21 -22
  32. package/dist/commands/roadmap/remove-project.js +14 -34
  33. package/dist/commands/roadmap/reorder.js +19 -26
  34. package/dist/commands/roadmap/update.js +27 -26
  35. package/dist/commands/roadmap/view.js +5 -12
  36. package/dist/commands/session/attach.d.ts +1 -8
  37. package/dist/commands/session/attach.js +93 -59
  38. package/dist/commands/session/list.d.ts +0 -8
  39. package/dist/commands/session/list.js +130 -81
  40. package/dist/commands/spec/create.js +1 -1
  41. package/dist/commands/spec/edit.js +63 -33
  42. package/dist/commands/support/book.d.ts +10 -0
  43. package/dist/commands/support/book.js +54 -0
  44. package/dist/commands/support/discord.d.ts +10 -0
  45. package/dist/commands/support/discord.js +54 -0
  46. package/dist/commands/support/docs.d.ts +10 -0
  47. package/dist/commands/support/docs.js +54 -0
  48. package/dist/commands/support/index.d.ts +19 -0
  49. package/dist/commands/support/index.js +81 -0
  50. package/dist/commands/support/issues.d.ts +11 -0
  51. package/dist/commands/support/issues.js +77 -0
  52. package/dist/commands/support/logs.d.ts +18 -0
  53. package/dist/commands/support/logs.js +247 -0
  54. package/dist/commands/ticket/create.js +21 -13
  55. package/dist/commands/ticket/edit.js +44 -13
  56. package/dist/commands/ticket/move.d.ts +7 -0
  57. package/dist/commands/ticket/move.js +132 -0
  58. package/dist/commands/work/spawn.d.ts +1 -0
  59. package/dist/commands/work/spawn.js +71 -7
  60. package/dist/commands/work/start.js +6 -0
  61. package/dist/lib/execution/runners.js +21 -17
  62. package/dist/lib/execution/session-utils.d.ts +60 -0
  63. package/dist/lib/execution/session-utils.js +162 -0
  64. package/dist/lib/execution/spawner.d.ts +2 -0
  65. package/dist/lib/execution/spawner.js +42 -0
  66. package/dist/lib/flags/resolver.d.ts +2 -2
  67. package/dist/lib/flags/resolver.js +15 -0
  68. package/dist/lib/init/index.js +18 -0
  69. package/dist/lib/multiline-input.d.ts +63 -0
  70. package/dist/lib/multiline-input.js +360 -0
  71. package/dist/lib/prompt-json.d.ts +5 -5
  72. package/dist/lib/repos/git.d.ts +7 -0
  73. package/dist/lib/repos/git.js +20 -0
  74. package/oclif.manifest.json +2206 -1607
  75. package/package.json +1 -1
@@ -4,6 +4,7 @@ import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
4
4
  import { styles } from '../../lib/styles.js';
5
5
  import { shouldOutputJson, outputErrorAsJson, createMetadata, } from '../../lib/prompt-json.js';
6
6
  import { FlagResolver } from '../../lib/flags/index.js';
7
+ import { multiLineInput } from '../../lib/multiline-input.js';
7
8
  export default class SpecEdit extends PMOCommand {
8
9
  static description = 'Edit an existing spec';
9
10
  static examples = [
@@ -114,6 +115,25 @@ export default class SpecEdit extends PMOCommand {
114
115
  const hasFlags = flags.title || flags.status || flags.type || flags.problem ||
115
116
  flags.solution || flags.decisions;
116
117
  if (flags.interactive || !hasFlags) {
118
+ // In JSON mode without flags, output a form prompt instead of interactive prompts
119
+ if (jsonMode) {
120
+ const { outputPromptAsJson, buildFormPromptConfig } = await import('../../lib/prompt-json.js');
121
+ const formConfig = buildFormPromptConfig([
122
+ { type: 'input', name: 'title', message: 'Title:', default: spec.title },
123
+ { type: 'list', name: 'status', message: 'Status:', choices: statusChoices, default: spec.status },
124
+ { type: 'list', name: 'type', message: 'Type:', choices: typeChoices, default: spec.type || '' },
125
+ { type: 'multiline', name: 'problem', message: 'Problem statement:', default: spec.problem || '' },
126
+ { type: 'multiline', name: 'solution', message: 'Solution:', default: spec.solution || '' },
127
+ { type: 'multiline', name: 'decisions', message: 'Design decisions:', default: spec.decisions || '' },
128
+ ]);
129
+ formConfig.context = {
130
+ hint: `Edit spec with: prlt spec edit ${specId} --title "..." --problem "..." --json`,
131
+ specId,
132
+ currentValues: { title: spec.title, status: spec.status, type: spec.type, problem: spec.problem, solution: spec.solution, decisions: spec.decisions },
133
+ };
134
+ outputPromptAsJson(formConfig, createMetadata('spec edit', flags));
135
+ return; // outputPromptAsJson exits, but TypeScript doesn't know
136
+ }
117
137
  // Interactive mode - prompt for editable fields
118
138
  updates = await this.promptForEdits(spec, typeChoices, statusChoices);
119
139
  }
@@ -162,7 +182,8 @@ export default class SpecEdit extends PMOCommand {
162
182
  this.log(styles.muted(`View spec: prlt spec view ${updatedSpec.id}`));
163
183
  }
164
184
  async promptForEdits(spec, typeChoices, statusChoices) {
165
- const answers = await inquirer.prompt([
185
+ // First prompt for title, status, and type
186
+ const basicAnswers = await inquirer.prompt([
166
187
  {
167
188
  type: 'input',
168
189
  name: 'title',
@@ -184,48 +205,57 @@ export default class SpecEdit extends PMOCommand {
184
205
  choices: typeChoices,
185
206
  default: spec.type || '',
186
207
  },
187
- {
188
- type: 'editor',
189
- name: 'problem',
190
- message: 'Problem statement (opens $EDITOR):',
191
- default: spec.problem || '',
192
- waitForUseInput: false,
193
- },
194
- {
195
- type: 'editor',
196
- name: 'solution',
197
- message: 'Solution (opens $EDITOR):',
198
- default: spec.solution || '',
199
- waitForUseInput: false,
200
- },
201
- {
202
- type: 'editor',
203
- name: 'decisions',
204
- message: 'Design decisions (opens $EDITOR):',
205
- default: spec.decisions || '',
206
- waitForUseInput: false,
207
- },
208
208
  ]);
209
+ // Prompt for problem statement using multiline input
210
+ const problemResult = await multiLineInput({
211
+ message: 'Problem statement:',
212
+ default: spec.problem || '',
213
+ hint: 'Describe the problem this spec addresses. Ctrl+D to finish, Ctrl+C to cancel',
214
+ });
215
+ if (problemResult.cancelled) {
216
+ throw new Error('Edit cancelled');
217
+ }
218
+ // Prompt for solution using multiline input
219
+ const solutionResult = await multiLineInput({
220
+ message: 'Solution:',
221
+ default: spec.solution || '',
222
+ hint: 'Describe the proposed solution. Ctrl+D to finish, Ctrl+C to cancel',
223
+ });
224
+ if (solutionResult.cancelled) {
225
+ throw new Error('Edit cancelled');
226
+ }
227
+ // Prompt for decisions using multiline input
228
+ const decisionsResult = await multiLineInput({
229
+ message: 'Design decisions:',
230
+ default: spec.decisions || '',
231
+ hint: 'Document key design decisions. Ctrl+D to finish, Ctrl+C to cancel',
232
+ });
233
+ if (decisionsResult.cancelled) {
234
+ throw new Error('Edit cancelled');
235
+ }
209
236
  // Build updates object with only changed fields
210
237
  const updates = {};
211
- if (answers.title !== spec.title) {
212
- updates.title = answers.title;
238
+ if (basicAnswers.title !== spec.title) {
239
+ updates.title = basicAnswers.title;
213
240
  }
214
- if (answers.status !== spec.status) {
215
- updates.status = answers.status;
241
+ if (basicAnswers.status !== spec.status) {
242
+ updates.status = basicAnswers.status;
216
243
  }
217
- const newType = answers.type === '' ? undefined : answers.type;
244
+ const newType = basicAnswers.type === '' ? undefined : basicAnswers.type;
218
245
  if (newType !== spec.type) {
219
246
  updates.type = newType;
220
247
  }
221
- if (answers.problem !== (spec.problem || '')) {
222
- updates.problem = answers.problem || undefined;
248
+ if (problemResult.value !== (spec.problem || '')) {
249
+ // Preserve empty string to allow clearing the field
250
+ updates.problem = problemResult.value;
223
251
  }
224
- if (answers.solution !== (spec.solution || '')) {
225
- updates.solution = answers.solution || undefined;
252
+ if (solutionResult.value !== (spec.solution || '')) {
253
+ // Preserve empty string to allow clearing the field
254
+ updates.solution = solutionResult.value;
226
255
  }
227
- if (answers.decisions !== (spec.decisions || '')) {
228
- updates.decisions = answers.decisions || undefined;
256
+ if (decisionsResult.value !== (spec.decisions || '')) {
257
+ // Preserve empty string to allow clearing the field
258
+ updates.decisions = decisionsResult.value;
229
259
  }
230
260
  return updates;
231
261
  }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class SupportBook extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ private openUrl;
10
+ }
@@ -0,0 +1,54 @@
1
+ import { Command } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import { styles } from '../../lib/styles.js';
4
+ import { isMachineOutput, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
5
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
6
+ import { SUPPORT_URLS } from './index.js';
7
+ export default class SupportBook extends Command {
8
+ static description = 'Book a call for support';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %>',
11
+ '<%= config.bin %> <%= command.id %> --json',
12
+ ];
13
+ static flags = {
14
+ ...machineOutputFlags,
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(SupportBook);
18
+ const url = SUPPORT_URLS.calcom;
19
+ // In JSON mode, return the URL
20
+ if (isMachineOutput(flags)) {
21
+ outputSuccessAsJson({
22
+ action: 'book',
23
+ url,
24
+ message: 'Book a call for support',
25
+ }, createMetadata('support book', flags));
26
+ return;
27
+ }
28
+ // Open the URL in the browser
29
+ this.openUrl(url);
30
+ this.log(styles.success('Opening cal.com booking page...'));
31
+ this.log(styles.muted(`URL: ${url}`));
32
+ }
33
+ openUrl(url) {
34
+ const platform = process.platform;
35
+ try {
36
+ if (platform === 'darwin') {
37
+ execSync(`open "${url}"`);
38
+ }
39
+ else if (platform === 'linux') {
40
+ execSync(`xdg-open "${url}"`);
41
+ }
42
+ else if (platform === 'win32') {
43
+ execSync(`start "" "${url}"`);
44
+ }
45
+ else {
46
+ throw new Error(`Unsupported platform: ${platform}`);
47
+ }
48
+ }
49
+ catch {
50
+ this.log(styles.warning('Could not open browser automatically.'));
51
+ this.log(styles.info(`Please visit: ${url}`));
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class SupportDiscord extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ private openUrl;
10
+ }
@@ -0,0 +1,54 @@
1
+ import { Command } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import { styles } from '../../lib/styles.js';
4
+ import { isMachineOutput, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
5
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
6
+ import { SUPPORT_URLS } from './index.js';
7
+ export default class SupportDiscord extends Command {
8
+ static description = 'Join the Discord community';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %>',
11
+ '<%= config.bin %> <%= command.id %> --json',
12
+ ];
13
+ static flags = {
14
+ ...machineOutputFlags,
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(SupportDiscord);
18
+ const url = SUPPORT_URLS.discord;
19
+ // In JSON mode, return the URL
20
+ if (isMachineOutput(flags)) {
21
+ outputSuccessAsJson({
22
+ action: 'discord',
23
+ url,
24
+ message: 'Join Discord community',
25
+ }, createMetadata('support discord', flags));
26
+ return;
27
+ }
28
+ // Open the URL in the browser
29
+ this.openUrl(url);
30
+ this.log(styles.success('Opening Discord invite...'));
31
+ this.log(styles.muted(`URL: ${url}`));
32
+ }
33
+ openUrl(url) {
34
+ const platform = process.platform;
35
+ try {
36
+ if (platform === 'darwin') {
37
+ execSync(`open "${url}"`);
38
+ }
39
+ else if (platform === 'linux') {
40
+ execSync(`xdg-open "${url}"`);
41
+ }
42
+ else if (platform === 'win32') {
43
+ execSync(`start "" "${url}"`);
44
+ }
45
+ else {
46
+ throw new Error(`Unsupported platform: ${platform}`);
47
+ }
48
+ }
49
+ catch {
50
+ this.log(styles.warning('Could not open browser automatically.'));
51
+ this.log(styles.info(`Please visit: ${url}`));
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class SupportDocs extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ };
8
+ run(): Promise<void>;
9
+ private openUrl;
10
+ }
@@ -0,0 +1,54 @@
1
+ import { Command } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import { styles } from '../../lib/styles.js';
4
+ import { isMachineOutput, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
5
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
6
+ import { SUPPORT_URLS } from './index.js';
7
+ export default class SupportDocs extends Command {
8
+ static description = 'Open documentation in browser';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %>',
11
+ '<%= config.bin %> <%= command.id %> --json',
12
+ ];
13
+ static flags = {
14
+ ...machineOutputFlags,
15
+ };
16
+ async run() {
17
+ const { flags } = await this.parse(SupportDocs);
18
+ const url = SUPPORT_URLS.docs;
19
+ // In JSON mode, return the URL
20
+ if (isMachineOutput(flags)) {
21
+ outputSuccessAsJson({
22
+ action: 'docs',
23
+ url,
24
+ message: 'Open documentation',
25
+ }, createMetadata('support docs', flags));
26
+ return;
27
+ }
28
+ // Open the URL in the browser
29
+ this.openUrl(url);
30
+ this.log(styles.success('Opening documentation...'));
31
+ this.log(styles.muted(`URL: ${url}`));
32
+ }
33
+ openUrl(url) {
34
+ const platform = process.platform;
35
+ try {
36
+ if (platform === 'darwin') {
37
+ execSync(`open "${url}"`);
38
+ }
39
+ else if (platform === 'linux') {
40
+ execSync(`xdg-open "${url}"`);
41
+ }
42
+ else if (platform === 'win32') {
43
+ execSync(`start "" "${url}"`);
44
+ }
45
+ else {
46
+ throw new Error(`Unsupported platform: ${platform}`);
47
+ }
48
+ }
49
+ catch {
50
+ this.log(styles.warning('Could not open browser automatically.'));
51
+ this.log(styles.info(`Please visit: ${url}`));
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,19 @@
1
+ import { Command } from '@oclif/core';
2
+ /**
3
+ * Support URLs - centralized for consistency
4
+ */
5
+ export declare const SUPPORT_URLS: {
6
+ calcom: string;
7
+ discord: string;
8
+ issues: string;
9
+ docs: string;
10
+ npm: string;
11
+ };
12
+ export default class Support extends Command {
13
+ static description: string;
14
+ static examples: string[];
15
+ static flags: {
16
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ };
18
+ run(): Promise<void>;
19
+ }
@@ -0,0 +1,81 @@
1
+ import { Command } from '@oclif/core';
2
+ import { FlagResolver, shouldOutputJson } from '../../lib/flags/index.js';
3
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
4
+ /**
5
+ * Support URLs - centralized for consistency
6
+ */
7
+ export const SUPPORT_URLS = {
8
+ calcom: 'https://cal.com/chrismcdermut',
9
+ discord: 'https://discord.gg/tmZyjNNSvw',
10
+ issues: 'https://github.com/chrismcdermut/proletariat/issues',
11
+ docs: 'https://github.com/chrismcdermut/proletariat#readme',
12
+ npm: 'https://www.npmjs.com/package/@proletariat/cli',
13
+ };
14
+ export default class Support extends Command {
15
+ static description = 'Get help, troubleshoot, and connect with the community';
16
+ static examples = [
17
+ '<%= config.bin %> <%= command.id %>',
18
+ '<%= config.bin %> <%= command.id %> book',
19
+ '<%= config.bin %> <%= command.id %> docs',
20
+ '<%= config.bin %> <%= command.id %> discord',
21
+ '<%= config.bin %> <%= command.id %> issues',
22
+ '<%= config.bin %> <%= command.id %> logs',
23
+ ];
24
+ static flags = {
25
+ ...machineOutputFlags,
26
+ };
27
+ async run() {
28
+ const { flags } = await this.parse(Support);
29
+ // Check if JSON output mode is active
30
+ const jsonMode = shouldOutputJson(flags);
31
+ // Use FlagResolver for the menu selection
32
+ const resolver = new FlagResolver({
33
+ commandName: 'support',
34
+ baseCommand: 'prlt support',
35
+ jsonMode,
36
+ flags: {},
37
+ });
38
+ // Add prompt for action selection
39
+ resolver.addPrompt({
40
+ flagName: 'action',
41
+ type: 'list',
42
+ message: 'How can we help?',
43
+ choices: () => [
44
+ { name: 'Book a call', value: 'book', command: 'prlt support book --json' },
45
+ { name: 'Documentation', value: 'docs', command: 'prlt support docs --json' },
46
+ { name: 'Report a bug', value: 'bug', command: 'prlt feedback submit --category bug --json' },
47
+ { name: 'Request a feature', value: 'feature', command: 'prlt feedback submit --category feature --json' },
48
+ { name: 'Join Discord', value: 'discord', command: 'prlt support discord --json' },
49
+ { name: 'Browse issues', value: 'issues', command: 'prlt support issues --json' },
50
+ { name: 'Collect diagnostics', value: 'logs', command: 'prlt support logs --json' },
51
+ ],
52
+ skipAutoCommand: true,
53
+ });
54
+ // Resolve - in JSON mode this outputs the prompt and exits
55
+ const resolved = await resolver.resolve();
56
+ // Execute the selected action
57
+ switch (resolved.action) {
58
+ case 'book':
59
+ await this.config.runCommand('support book');
60
+ break;
61
+ case 'docs':
62
+ await this.config.runCommand('support docs');
63
+ break;
64
+ case 'bug':
65
+ await this.config.runCommand('feedback submit', ['--category', 'bug']);
66
+ break;
67
+ case 'feature':
68
+ await this.config.runCommand('feedback submit', ['--category', 'feature']);
69
+ break;
70
+ case 'discord':
71
+ await this.config.runCommand('support discord');
72
+ break;
73
+ case 'issues':
74
+ await this.config.runCommand('support issues');
75
+ break;
76
+ case 'logs':
77
+ await this.config.runCommand('support logs');
78
+ break;
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,11 @@
1
+ import { Command } from '@oclif/core';
2
+ export default class SupportIssues extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ browser: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ run(): Promise<void>;
10
+ private openUrl;
11
+ }
@@ -0,0 +1,77 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import { execSync } from 'node:child_process';
3
+ import { styles } from '../../lib/styles.js';
4
+ import { isMachineOutput, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
5
+ import { machineOutputFlags } from '../../lib/pmo/index.js';
6
+ import { SUPPORT_URLS } from './index.js';
7
+ export default class SupportIssues extends Command {
8
+ static description = 'Browse GitHub Issues';
9
+ static examples = [
10
+ '<%= config.bin %> <%= command.id %>',
11
+ '<%= config.bin %> <%= command.id %> --browser',
12
+ '<%= config.bin %> <%= command.id %> --json',
13
+ ];
14
+ static flags = {
15
+ ...machineOutputFlags,
16
+ browser: Flags.boolean({
17
+ description: 'Open issues in browser (default behavior)',
18
+ default: true,
19
+ allowNo: true,
20
+ }),
21
+ };
22
+ async run() {
23
+ const { flags } = await this.parse(SupportIssues);
24
+ const url = SUPPORT_URLS.issues;
25
+ // In JSON mode, return the URL
26
+ if (isMachineOutput(flags)) {
27
+ outputSuccessAsJson({
28
+ action: 'issues',
29
+ url,
30
+ message: 'Browse GitHub Issues',
31
+ }, createMetadata('support issues', flags));
32
+ return;
33
+ }
34
+ // Open in browser (default)
35
+ if (flags.browser) {
36
+ this.openUrl(url);
37
+ this.log(styles.success('Opening GitHub Issues...'));
38
+ this.log(styles.muted(`URL: ${url}`));
39
+ }
40
+ else {
41
+ // List issues via gh CLI when --no-browser is set
42
+ try {
43
+ const output = execSync('gh issue list --repo chrismcdermut/proletariat', {
44
+ encoding: 'utf-8',
45
+ stdio: ['ignore', 'pipe', 'pipe'],
46
+ });
47
+ this.log(styles.header('Open Issues'));
48
+ this.log(output.trim() || styles.muted('No open issues found.'));
49
+ }
50
+ catch {
51
+ this.log(styles.warning('Could not list issues via gh CLI.'));
52
+ this.log(styles.info(`Please visit: ${url}`));
53
+ }
54
+ }
55
+ }
56
+ openUrl(url) {
57
+ const platform = process.platform;
58
+ try {
59
+ if (platform === 'darwin') {
60
+ execSync(`open "${url}"`);
61
+ }
62
+ else if (platform === 'linux') {
63
+ execSync(`xdg-open "${url}"`);
64
+ }
65
+ else if (platform === 'win32') {
66
+ execSync(`start "" "${url}"`);
67
+ }
68
+ else {
69
+ throw new Error(`Unsupported platform: ${platform}`);
70
+ }
71
+ }
72
+ catch {
73
+ this.log(styles.warning('Could not open browser automatically.'));
74
+ this.log(styles.info(`Please visit: ${url}`));
75
+ }
76
+ }
77
+ }
@@ -0,0 +1,18 @@
1
+ import { PMOCommand } from '../../lib/pmo/index.js';
2
+ export default class SupportLogs extends PMOCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ clipboard: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ project: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ };
10
+ protected execute(): Promise<void>;
11
+ private collectDiagnostics;
12
+ private checkGh;
13
+ private checkDocker;
14
+ private checkTmux;
15
+ private getWorkspaceInfo;
16
+ private formatDiagnostics;
17
+ private copyToClipboard;
18
+ }