@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,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
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { PMOCommand, pmoBaseFlags } from '../../lib/pmo/index.js';
|
|
5
|
+
import { styles } from '../../lib/styles.js';
|
|
6
|
+
import { isMachineOutput, outputSuccessAsJson, createMetadata, } from '../../lib/prompt-json.js';
|
|
7
|
+
export default class SupportLogs extends PMOCommand {
|
|
8
|
+
static description = 'Collect diagnostic info for troubleshooting';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %>',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> --clipboard',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
...pmoBaseFlags,
|
|
16
|
+
clipboard: Flags.boolean({
|
|
17
|
+
description: 'Copy diagnostics to clipboard',
|
|
18
|
+
default: false,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
async execute() {
|
|
22
|
+
const { flags } = await this.parse(SupportLogs);
|
|
23
|
+
const diagnostics = await this.collectDiagnostics();
|
|
24
|
+
// In JSON mode, return structured object
|
|
25
|
+
if (isMachineOutput(flags)) {
|
|
26
|
+
outputSuccessAsJson(diagnostics, createMetadata('support logs', flags));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Format as readable text
|
|
30
|
+
const text = this.formatDiagnostics(diagnostics);
|
|
31
|
+
// Copy to clipboard if requested
|
|
32
|
+
if (flags.clipboard) {
|
|
33
|
+
const copied = this.copyToClipboard(text);
|
|
34
|
+
if (copied) {
|
|
35
|
+
this.log(styles.success('Diagnostics copied to clipboard!'));
|
|
36
|
+
this.log('');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Display diagnostics
|
|
40
|
+
this.log(text);
|
|
41
|
+
}
|
|
42
|
+
async collectDiagnostics() {
|
|
43
|
+
const diagnostics = {
|
|
44
|
+
prlt: {
|
|
45
|
+
version: this.config.version,
|
|
46
|
+
},
|
|
47
|
+
node: {
|
|
48
|
+
version: process.version,
|
|
49
|
+
},
|
|
50
|
+
os: {
|
|
51
|
+
platform: process.platform,
|
|
52
|
+
release: os.release(),
|
|
53
|
+
arch: os.arch(),
|
|
54
|
+
},
|
|
55
|
+
shell: process.env.SHELL,
|
|
56
|
+
tools: {
|
|
57
|
+
gh: this.checkGh(),
|
|
58
|
+
docker: this.checkDocker(),
|
|
59
|
+
tmux: this.checkTmux(),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
// Add workspace info if available
|
|
63
|
+
try {
|
|
64
|
+
const workspaceInfo = await this.getWorkspaceInfo();
|
|
65
|
+
if (workspaceInfo) {
|
|
66
|
+
diagnostics.workspace = workspaceInfo;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// PMO may not be initialized
|
|
71
|
+
}
|
|
72
|
+
return diagnostics;
|
|
73
|
+
}
|
|
74
|
+
checkGh() {
|
|
75
|
+
try {
|
|
76
|
+
const versionOutput = execSync('gh --version', {
|
|
77
|
+
encoding: 'utf-8',
|
|
78
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
79
|
+
});
|
|
80
|
+
const version = versionOutput.split('\n')[0]?.replace('gh version ', '').trim();
|
|
81
|
+
let authenticated = false;
|
|
82
|
+
try {
|
|
83
|
+
execSync('gh auth status', { stdio: 'ignore' });
|
|
84
|
+
authenticated = true;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
authenticated = false;
|
|
88
|
+
}
|
|
89
|
+
return { installed: true, version, authenticated };
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return { installed: false };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
checkDocker() {
|
|
96
|
+
try {
|
|
97
|
+
execSync('docker --version', { stdio: 'ignore' });
|
|
98
|
+
let running = false;
|
|
99
|
+
try {
|
|
100
|
+
execSync('docker info', { stdio: 'ignore' });
|
|
101
|
+
running = true;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
running = false;
|
|
105
|
+
}
|
|
106
|
+
return { installed: true, running };
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return { installed: false };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
checkTmux() {
|
|
113
|
+
try {
|
|
114
|
+
const versionOutput = execSync('tmux -V', {
|
|
115
|
+
encoding: 'utf-8',
|
|
116
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
117
|
+
});
|
|
118
|
+
const version = versionOutput.trim();
|
|
119
|
+
return { installed: true, version };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return { installed: false };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async getWorkspaceInfo() {
|
|
126
|
+
try {
|
|
127
|
+
const projects = await this.storage.listProjects();
|
|
128
|
+
let totalTickets = 0;
|
|
129
|
+
for (const project of projects) {
|
|
130
|
+
// eslint-disable-next-line no-await-in-loop
|
|
131
|
+
const tickets = await this.storage.listTickets(project.id);
|
|
132
|
+
totalTickets += tickets.length;
|
|
133
|
+
}
|
|
134
|
+
// Get agents count by checking for agents directory
|
|
135
|
+
let agentCount = 0;
|
|
136
|
+
try {
|
|
137
|
+
const { getWorkspaceInfo } = await import('../../lib/agents/commands.js');
|
|
138
|
+
const wsInfo = getWorkspaceInfo();
|
|
139
|
+
agentCount = wsInfo.agents?.length || 0;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Agents module may not be available
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
path: this.pmoPath,
|
|
146
|
+
name: projects[0]?.name,
|
|
147
|
+
repoCount: projects.length,
|
|
148
|
+
agentCount,
|
|
149
|
+
ticketCount: totalTickets,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
formatDiagnostics(d) {
|
|
157
|
+
const lines = [];
|
|
158
|
+
lines.push(styles.title('Diagnostic Information'));
|
|
159
|
+
lines.push('');
|
|
160
|
+
// System info
|
|
161
|
+
lines.push(styles.header('System'));
|
|
162
|
+
lines.push(` prlt version: ${d.prlt.version}`);
|
|
163
|
+
lines.push(` Node version: ${d.node.version}`);
|
|
164
|
+
lines.push(` OS: ${d.os.platform} ${d.os.release} (${d.os.arch})`);
|
|
165
|
+
lines.push(` Shell: ${d.shell || 'unknown'}`);
|
|
166
|
+
lines.push('');
|
|
167
|
+
// Tools
|
|
168
|
+
lines.push(styles.header('Tools'));
|
|
169
|
+
// gh
|
|
170
|
+
if (d.tools.gh.installed) {
|
|
171
|
+
const authStatus = d.tools.gh.authenticated ? styles.success('authenticated') : styles.warning('not authenticated');
|
|
172
|
+
lines.push(` gh CLI: ${styles.success('installed')} (${d.tools.gh.version}) - ${authStatus}`);
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
lines.push(` gh CLI: ${styles.warning('not installed')}`);
|
|
176
|
+
}
|
|
177
|
+
// docker
|
|
178
|
+
if (d.tools.docker.installed) {
|
|
179
|
+
const runStatus = d.tools.docker.running ? styles.success('running') : styles.warning('not running');
|
|
180
|
+
lines.push(` Docker: ${styles.success('installed')} - ${runStatus}`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
lines.push(` Docker: ${styles.warning('not installed')}`);
|
|
184
|
+
}
|
|
185
|
+
// tmux
|
|
186
|
+
if (d.tools.tmux.installed) {
|
|
187
|
+
lines.push(` tmux: ${styles.success('installed')} (${d.tools.tmux.version})`);
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
lines.push(` tmux: ${styles.muted('not installed')}`);
|
|
191
|
+
}
|
|
192
|
+
lines.push('');
|
|
193
|
+
// Workspace
|
|
194
|
+
if (d.workspace) {
|
|
195
|
+
lines.push(styles.header('Workspace'));
|
|
196
|
+
lines.push(` Path: ${d.workspace.path}`);
|
|
197
|
+
if (d.workspace.name) {
|
|
198
|
+
lines.push(` Name: ${d.workspace.name}`);
|
|
199
|
+
}
|
|
200
|
+
lines.push(` Projects: ${d.workspace.repoCount ?? 0}`);
|
|
201
|
+
lines.push(` Agents: ${d.workspace.agentCount ?? 0}`);
|
|
202
|
+
lines.push(` Tickets: ${d.workspace.ticketCount ?? 0}`);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
lines.push(styles.header('Workspace'));
|
|
206
|
+
lines.push(styles.muted(' No workspace initialized'));
|
|
207
|
+
}
|
|
208
|
+
return lines.join('\n');
|
|
209
|
+
}
|
|
210
|
+
copyToClipboard(text) {
|
|
211
|
+
const platform = process.platform;
|
|
212
|
+
// Strip ANSI codes for clipboard
|
|
213
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional ANSI escape code stripping
|
|
214
|
+
const plainText = text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
215
|
+
try {
|
|
216
|
+
if (platform === 'darwin') {
|
|
217
|
+
execSync('pbcopy', { input: plainText, encoding: 'utf-8' });
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
else if (platform === 'linux') {
|
|
221
|
+
// Try xclip first, then xsel
|
|
222
|
+
try {
|
|
223
|
+
execSync('xclip -selection clipboard', { input: plainText, encoding: 'utf-8' });
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
catch {
|
|
227
|
+
try {
|
|
228
|
+
execSync('xsel --clipboard --input', { input: plainText, encoding: 'utf-8' });
|
|
229
|
+
return true;
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
this.log(styles.warning('Install xclip or xsel to enable clipboard support.'));
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
else if (platform === 'win32') {
|
|
238
|
+
execSync('clip', { input: plainText, encoding: 'utf-8' });
|
|
239
|
+
return true;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch {
|
|
243
|
+
this.log(styles.warning('Could not copy to clipboard.'));
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|