prr-kit 1.1.0 → 1.1.1
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/README.md +235 -235
- package/package.json +60 -60
- package/src/prr/workflows/2-analyze/describe-pr/templates/pr-description.template.md +51 -51
- package/src/prr/workflows/3-review/architecture-review/workflow.yaml +18 -18
- package/src/prr/workflows/3-review/general-review/workflow.yaml +18 -18
- package/src/prr/workflows/3-review/performance-review/workflow.yaml +18 -18
- package/src/prr/workflows/3-review/security-review/workflow.yaml +19 -19
- package/src/prr/workflows/4-improve/improve-code/workflow.yaml +18 -18
- package/src/prr/workflows/6-report/generate-report/templates/review-report.template.md +78 -78
- package/tools/cli/installers/lib/core/installer.js +162 -162
- package/tools/cli/installers/lib/ide/github-copilot.js +262 -262
- package/tools/cli/prr-cli.js +36 -36
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Installer — main installation orchestrator
|
|
3
|
-
* Main installation orchestrator for PR Review
|
|
4
|
-
*/
|
|
5
|
-
const path = require('node:path');
|
|
6
|
-
const fs = require('fs-extra');
|
|
7
|
-
const { Manifest } = require('./manifest');
|
|
8
|
-
const { ManifestGenerator } = require('./manifest-generator');
|
|
9
|
-
const { ConfigCollector } = require('./config-collector');
|
|
10
|
-
const { Detector, PRR_FOLDER_NAME } = require('./detector');
|
|
11
|
-
const { IdeManager } = require('../ide/manager');
|
|
12
|
-
const { compileAgent } = require('../../../lib/agent/compiler');
|
|
13
|
-
const prompts = require('../../../lib/prompts');
|
|
14
|
-
const packageJson = require('../../../../../package.json');
|
|
15
|
-
|
|
16
|
-
const SRC_DIR = path.join(__dirname, '..', '..', '..', '..', '..', 'src');
|
|
17
|
-
const TEXT_EXTENSIONS = new Set(['.md', '.yaml', '.yml', '.txt', '.json', '.js', '.csv', '.xml', '.toml']);
|
|
18
|
-
|
|
19
|
-
class Installer {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.manifest = new Manifest();
|
|
22
|
-
this.manifestGenerator = new ManifestGenerator();
|
|
23
|
-
this.configCollector = new ConfigCollector();
|
|
24
|
-
this.detector = new Detector();
|
|
25
|
-
this.ideManager = new IdeManager();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async install(config) {
|
|
29
|
-
const { projectDir, selectedModules = ['prr'], selectedIdes = [], actionType = 'install' } = config;
|
|
30
|
-
|
|
31
|
-
await this.ideManager.ensureInitialized();
|
|
32
|
-
|
|
33
|
-
const prrDir = path.join(projectDir, PRR_FOLDER_NAME);
|
|
34
|
-
await fs.ensureDir(prrDir);
|
|
35
|
-
|
|
36
|
-
await prompts.log.step(`Installing PR Review to ${projectDir}...`);
|
|
37
|
-
|
|
38
|
-
// Copy module files from src/
|
|
39
|
-
const modulesToInstall = ['core', ...selectedModules.filter((m) => m !== 'core')];
|
|
40
|
-
for (const mod of modulesToInstall) {
|
|
41
|
-
const srcModDir = path.join(SRC_DIR, mod === 'core' ? 'core' : mod);
|
|
42
|
-
const dstModDir = path.join(prrDir, mod);
|
|
43
|
-
|
|
44
|
-
if (!(await fs.pathExists(srcModDir))) {
|
|
45
|
-
await prompts.log.warn(`Module '${mod}' not found in src/ — skipping`);
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
await fs.remove(dstModDir);
|
|
50
|
-
await this.copyModuleFiles(srcModDir, dstModDir);
|
|
51
|
-
await prompts.log.info(` ✓ Module '${mod}' installed`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Compile agents (YAML → XML/MD)
|
|
55
|
-
await this.compileModuleAgents(prrDir, modulesToInstall);
|
|
56
|
-
|
|
57
|
-
// Write config files
|
|
58
|
-
await this.configCollector.writeConfigs(prrDir, config);
|
|
59
|
-
await prompts.log.info(' ✓ Configuration written');
|
|
60
|
-
|
|
61
|
-
// Create output directories
|
|
62
|
-
const outputFolderAbs = path.join(projectDir, config.outputFolder || '_prr-output');
|
|
63
|
-
await fs.ensureDir(path.join(outputFolderAbs, 'reviews'));
|
|
64
|
-
await prompts.log.info(' ✓ Output directories created');
|
|
65
|
-
|
|
66
|
-
// Generate manifests
|
|
67
|
-
const cfgDir = path.join(prrDir, '_config');
|
|
68
|
-
await fs.ensureDir(cfgDir);
|
|
69
|
-
await this.manifestGenerator.generateManifests(prrDir, selectedModules);
|
|
70
|
-
await this.manifest.create(prrDir, {
|
|
71
|
-
version: packageJson.version,
|
|
72
|
-
modules: modulesToInstall,
|
|
73
|
-
ides: selectedIdes,
|
|
74
|
-
});
|
|
75
|
-
await prompts.log.info(' ✓ Manifests generated');
|
|
76
|
-
|
|
77
|
-
// Configure IDEs
|
|
78
|
-
for (const ide of selectedIdes) {
|
|
79
|
-
const result = await this.ideManager.setup(ide, projectDir, prrDir, { selectedModules: modulesToInstall });
|
|
80
|
-
if (result.success) {
|
|
81
|
-
await prompts.log.info(` ✓ ${ide} configured (${result.detail || 'done'})`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
await prompts.log.success('PR Review installed successfully!');
|
|
86
|
-
await prompts.log.info('Open your AI IDE and use the reviewer agents to start reviewing PRs.');
|
|
87
|
-
|
|
88
|
-
return { success: true };
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async copyModuleFiles(srcDir, dstDir) {
|
|
92
|
-
await fs.ensureDir(dstDir);
|
|
93
|
-
const entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
94
|
-
|
|
95
|
-
for (const entry of entries) {
|
|
96
|
-
const srcPath = path.join(srcDir, entry.name);
|
|
97
|
-
const dstPath = path.join(dstDir, entry.name);
|
|
98
|
-
|
|
99
|
-
if (entry.isDirectory()) {
|
|
100
|
-
await this.copyModuleFiles(srcPath, dstPath);
|
|
101
|
-
} else {
|
|
102
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
103
|
-
if (TEXT_EXTENSIONS.has(ext)) {
|
|
104
|
-
const content = await fs.readFile(srcPath, 'utf8');
|
|
105
|
-
await fs.ensureDir(path.dirname(dstPath));
|
|
106
|
-
await fs.writeFile(dstPath, content, 'utf8');
|
|
107
|
-
} else {
|
|
108
|
-
await fs.copy(srcPath, dstPath, { overwrite: true });
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
async compileModuleAgents(prrDir, modules) {
|
|
115
|
-
for (const mod of modules) {
|
|
116
|
-
const agentsYamlDir = path.join(prrDir, mod, 'agents');
|
|
117
|
-
if (!(await fs.pathExists(agentsYamlDir))) continue;
|
|
118
|
-
|
|
119
|
-
const files = await fs.readdir(agentsYamlDir);
|
|
120
|
-
for (const file of files) {
|
|
121
|
-
if (!file.endsWith('.agent.yaml')) continue;
|
|
122
|
-
|
|
123
|
-
const yamlPath = path.join(agentsYamlDir, file);
|
|
124
|
-
const baseName = file.replace('.agent.yaml', '');
|
|
125
|
-
const outputPath = path.join(agentsYamlDir, `${baseName}.md`);
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
const yamlContent = await fs.readFile(yamlPath, 'utf8');
|
|
129
|
-
const { xml } = await compileAgent(yamlContent, {}, baseName, `_prr/${mod}/agents/${baseName}.md`);
|
|
130
|
-
await fs.writeFile(outputPath, xml, 'utf8');
|
|
131
|
-
} catch (err) {
|
|
132
|
-
await prompts.log.warn(` Warning: Could not compile agent ${file}: ${err.message}`);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async uninstall(projectDir) {
|
|
139
|
-
const prrDir = path.join(projectDir, PRR_FOLDER_NAME);
|
|
140
|
-
if (await fs.pathExists(prrDir)) {
|
|
141
|
-
await fs.remove(prrDir);
|
|
142
|
-
}
|
|
143
|
-
// Also clean IDE configurations
|
|
144
|
-
await this.ideManager.ensureInitialized();
|
|
145
|
-
await this.ideManager.cleanup(projectDir);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async quickUpdate(config) {
|
|
149
|
-
const { projectDir } = config;
|
|
150
|
-
const existing = await this.detector.detect(projectDir);
|
|
151
|
-
if (!existing.installed) {
|
|
152
|
-
throw new Error('PR Review is not installed in this directory.');
|
|
153
|
-
}
|
|
154
|
-
return this.install({ ...config, selectedModules: existing.modules, selectedIdes: existing.ides });
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async status(projectDir) {
|
|
158
|
-
return this.detector.detect(projectDir);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
module.exports = { Installer };
|
|
1
|
+
/**
|
|
2
|
+
* Installer — main installation orchestrator
|
|
3
|
+
* Main installation orchestrator for PR Review Kit
|
|
4
|
+
*/
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const { Manifest } = require('./manifest');
|
|
8
|
+
const { ManifestGenerator } = require('./manifest-generator');
|
|
9
|
+
const { ConfigCollector } = require('./config-collector');
|
|
10
|
+
const { Detector, PRR_FOLDER_NAME } = require('./detector');
|
|
11
|
+
const { IdeManager } = require('../ide/manager');
|
|
12
|
+
const { compileAgent } = require('../../../lib/agent/compiler');
|
|
13
|
+
const prompts = require('../../../lib/prompts');
|
|
14
|
+
const packageJson = require('../../../../../package.json');
|
|
15
|
+
|
|
16
|
+
const SRC_DIR = path.join(__dirname, '..', '..', '..', '..', '..', 'src');
|
|
17
|
+
const TEXT_EXTENSIONS = new Set(['.md', '.yaml', '.yml', '.txt', '.json', '.js', '.csv', '.xml', '.toml']);
|
|
18
|
+
|
|
19
|
+
class Installer {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.manifest = new Manifest();
|
|
22
|
+
this.manifestGenerator = new ManifestGenerator();
|
|
23
|
+
this.configCollector = new ConfigCollector();
|
|
24
|
+
this.detector = new Detector();
|
|
25
|
+
this.ideManager = new IdeManager();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async install(config) {
|
|
29
|
+
const { projectDir, selectedModules = ['prr'], selectedIdes = [], actionType = 'install' } = config;
|
|
30
|
+
|
|
31
|
+
await this.ideManager.ensureInitialized();
|
|
32
|
+
|
|
33
|
+
const prrDir = path.join(projectDir, PRR_FOLDER_NAME);
|
|
34
|
+
await fs.ensureDir(prrDir);
|
|
35
|
+
|
|
36
|
+
await prompts.log.step(`Installing PR Review to ${projectDir}...`);
|
|
37
|
+
|
|
38
|
+
// Copy module files from src/
|
|
39
|
+
const modulesToInstall = ['core', ...selectedModules.filter((m) => m !== 'core')];
|
|
40
|
+
for (const mod of modulesToInstall) {
|
|
41
|
+
const srcModDir = path.join(SRC_DIR, mod === 'core' ? 'core' : mod);
|
|
42
|
+
const dstModDir = path.join(prrDir, mod);
|
|
43
|
+
|
|
44
|
+
if (!(await fs.pathExists(srcModDir))) {
|
|
45
|
+
await prompts.log.warn(`Module '${mod}' not found in src/ — skipping`);
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
await fs.remove(dstModDir);
|
|
50
|
+
await this.copyModuleFiles(srcModDir, dstModDir);
|
|
51
|
+
await prompts.log.info(` ✓ Module '${mod}' installed`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Compile agents (YAML → XML/MD)
|
|
55
|
+
await this.compileModuleAgents(prrDir, modulesToInstall);
|
|
56
|
+
|
|
57
|
+
// Write config files
|
|
58
|
+
await this.configCollector.writeConfigs(prrDir, config);
|
|
59
|
+
await prompts.log.info(' ✓ Configuration written');
|
|
60
|
+
|
|
61
|
+
// Create output directories
|
|
62
|
+
const outputFolderAbs = path.join(projectDir, config.outputFolder || '_prr-output');
|
|
63
|
+
await fs.ensureDir(path.join(outputFolderAbs, 'reviews'));
|
|
64
|
+
await prompts.log.info(' ✓ Output directories created');
|
|
65
|
+
|
|
66
|
+
// Generate manifests
|
|
67
|
+
const cfgDir = path.join(prrDir, '_config');
|
|
68
|
+
await fs.ensureDir(cfgDir);
|
|
69
|
+
await this.manifestGenerator.generateManifests(prrDir, selectedModules);
|
|
70
|
+
await this.manifest.create(prrDir, {
|
|
71
|
+
version: packageJson.version,
|
|
72
|
+
modules: modulesToInstall,
|
|
73
|
+
ides: selectedIdes,
|
|
74
|
+
});
|
|
75
|
+
await prompts.log.info(' ✓ Manifests generated');
|
|
76
|
+
|
|
77
|
+
// Configure IDEs
|
|
78
|
+
for (const ide of selectedIdes) {
|
|
79
|
+
const result = await this.ideManager.setup(ide, projectDir, prrDir, { selectedModules: modulesToInstall });
|
|
80
|
+
if (result.success) {
|
|
81
|
+
await prompts.log.info(` ✓ ${ide} configured (${result.detail || 'done'})`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await prompts.log.success('PR Review installed successfully!');
|
|
86
|
+
await prompts.log.info('Open your AI IDE and use the reviewer agents to start reviewing PRs.');
|
|
87
|
+
|
|
88
|
+
return { success: true };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async copyModuleFiles(srcDir, dstDir) {
|
|
92
|
+
await fs.ensureDir(dstDir);
|
|
93
|
+
const entries = await fs.readdir(srcDir, { withFileTypes: true });
|
|
94
|
+
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
97
|
+
const dstPath = path.join(dstDir, entry.name);
|
|
98
|
+
|
|
99
|
+
if (entry.isDirectory()) {
|
|
100
|
+
await this.copyModuleFiles(srcPath, dstPath);
|
|
101
|
+
} else {
|
|
102
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
103
|
+
if (TEXT_EXTENSIONS.has(ext)) {
|
|
104
|
+
const content = await fs.readFile(srcPath, 'utf8');
|
|
105
|
+
await fs.ensureDir(path.dirname(dstPath));
|
|
106
|
+
await fs.writeFile(dstPath, content, 'utf8');
|
|
107
|
+
} else {
|
|
108
|
+
await fs.copy(srcPath, dstPath, { overwrite: true });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async compileModuleAgents(prrDir, modules) {
|
|
115
|
+
for (const mod of modules) {
|
|
116
|
+
const agentsYamlDir = path.join(prrDir, mod, 'agents');
|
|
117
|
+
if (!(await fs.pathExists(agentsYamlDir))) continue;
|
|
118
|
+
|
|
119
|
+
const files = await fs.readdir(agentsYamlDir);
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
if (!file.endsWith('.agent.yaml')) continue;
|
|
122
|
+
|
|
123
|
+
const yamlPath = path.join(agentsYamlDir, file);
|
|
124
|
+
const baseName = file.replace('.agent.yaml', '');
|
|
125
|
+
const outputPath = path.join(agentsYamlDir, `${baseName}.md`);
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const yamlContent = await fs.readFile(yamlPath, 'utf8');
|
|
129
|
+
const { xml } = await compileAgent(yamlContent, {}, baseName, `_prr/${mod}/agents/${baseName}.md`);
|
|
130
|
+
await fs.writeFile(outputPath, xml, 'utf8');
|
|
131
|
+
} catch (err) {
|
|
132
|
+
await prompts.log.warn(` Warning: Could not compile agent ${file}: ${err.message}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async uninstall(projectDir) {
|
|
139
|
+
const prrDir = path.join(projectDir, PRR_FOLDER_NAME);
|
|
140
|
+
if (await fs.pathExists(prrDir)) {
|
|
141
|
+
await fs.remove(prrDir);
|
|
142
|
+
}
|
|
143
|
+
// Also clean IDE configurations
|
|
144
|
+
await this.ideManager.ensureInitialized();
|
|
145
|
+
await this.ideManager.cleanup(projectDir);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async quickUpdate(config) {
|
|
149
|
+
const { projectDir } = config;
|
|
150
|
+
const existing = await this.detector.detect(projectDir);
|
|
151
|
+
if (!existing.installed) {
|
|
152
|
+
throw new Error('PR Review is not installed in this directory.');
|
|
153
|
+
}
|
|
154
|
+
return this.install({ ...config, selectedModules: existing.modules, selectedIdes: existing.ides });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async status(projectDir) {
|
|
158
|
+
return this.detector.detect(projectDir);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = { Installer };
|