prsmith 2.0.0 → 2.1.0
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/bin/cli.js +13 -0
- package/package.json +1 -1
- package/src/batch.js +13 -0
- package/src/config.js +24 -0
- package/src/prompts.js +8 -4
- package/tests/features.test.js +43 -0
package/bin/cli.js
CHANGED
|
@@ -135,6 +135,19 @@ program
|
|
|
135
135
|
|
|
136
136
|
// Post to GitHub if specified
|
|
137
137
|
if (options.github || options.pr || options.repo) {
|
|
138
|
+
const token = config.githubToken || process.env.GITHUB_TOKEN;
|
|
139
|
+
if (!token) {
|
|
140
|
+
console.error(
|
|
141
|
+
chalk.red('\n❌ Error: GitHub Personal Access Token not found!')
|
|
142
|
+
);
|
|
143
|
+
console.error(
|
|
144
|
+
chalk.yellow(
|
|
145
|
+
"Please configure 'githubToken' in your local ~/.prsmith.json file or set the GITHUB_TOKEN environment variable.\n"
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
|
|
138
151
|
const detectedRepo = detectGithubRepo();
|
|
139
152
|
let owner = '';
|
|
140
153
|
let repoName = '';
|
package/package.json
CHANGED
package/src/batch.js
CHANGED
|
@@ -113,6 +113,19 @@ export async function runBatchReview(config = {}) {
|
|
|
113
113
|
console.error(chalk.red(`Failed to write file: ${err.message}`));
|
|
114
114
|
}
|
|
115
115
|
} else if (action.includes('Post')) {
|
|
116
|
+
const token = config.githubToken || process.env.GITHUB_TOKEN;
|
|
117
|
+
if (!token) {
|
|
118
|
+
console.log(
|
|
119
|
+
chalk.red('\n❌ Error: GitHub Personal Access Token not found!')
|
|
120
|
+
);
|
|
121
|
+
console.log(
|
|
122
|
+
chalk.yellow(
|
|
123
|
+
"Please configure 'githubToken' in your local ~/.prsmith.json file or set the GITHUB_TOKEN environment variable.\n"
|
|
124
|
+
)
|
|
125
|
+
);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
116
129
|
const repo = config.githubRepo || detectGithubRepo();
|
|
117
130
|
const defaultOwner = repo ? repo.owner : '';
|
|
118
131
|
const defaultRepo = repo ? repo.repo : '';
|
package/src/config.js
CHANGED
|
@@ -15,12 +15,24 @@ export function loadConfig() {
|
|
|
15
15
|
try {
|
|
16
16
|
const fileContent = fs.readFileSync(configPath, 'utf-8');
|
|
17
17
|
const parsed = JSON.parse(fileContent);
|
|
18
|
+
|
|
18
19
|
if (parsed.templates) {
|
|
19
20
|
mergedConfig.templates = {
|
|
20
21
|
...mergedConfig.templates,
|
|
21
22
|
...parsed.templates,
|
|
22
23
|
};
|
|
23
24
|
}
|
|
25
|
+
|
|
26
|
+
if (parsed.editor) {
|
|
27
|
+
mergedConfig.editor = parsed.editor;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Also merge any other config properties (tokens, providers, etc.)
|
|
31
|
+
Object.keys(parsed).forEach((key) => {
|
|
32
|
+
if (key !== 'templates') {
|
|
33
|
+
mergedConfig[key] = parsed[key];
|
|
34
|
+
}
|
|
35
|
+
});
|
|
24
36
|
} catch (err) {
|
|
25
37
|
console.warn(
|
|
26
38
|
`Warning: Could not parse config at ${configPath} - ${err.message}`
|
|
@@ -29,5 +41,17 @@ export function loadConfig() {
|
|
|
29
41
|
}
|
|
30
42
|
}
|
|
31
43
|
|
|
44
|
+
// Senior Guardrail: Prevent the general public from getting stuck in Vim (no instructions)
|
|
45
|
+
// If the user has not set EDITOR/VISUAL globally, and did not set 'editor' in .prsmith.json,
|
|
46
|
+
// we default the spawned editor in our process to 'nano' on macOS/Linux.
|
|
47
|
+
// 'nano' has friendly, visible exit instructions at the bottom of the terminal by default!
|
|
48
|
+
if (mergedConfig.editor) {
|
|
49
|
+
process.env.EDITOR = mergedConfig.editor;
|
|
50
|
+
} else if (!process.env.EDITOR && !process.env.VISUAL) {
|
|
51
|
+
if (process.platform !== 'win32') {
|
|
52
|
+
process.env.EDITOR = 'nano';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
32
56
|
return mergedConfig;
|
|
33
57
|
}
|
package/src/prompts.js
CHANGED
|
@@ -35,7 +35,8 @@ export async function getReviewData(options = {}, config = {}) {
|
|
|
35
35
|
coreQuestions.push({
|
|
36
36
|
type: 'editor',
|
|
37
37
|
name: 'issue',
|
|
38
|
-
message:
|
|
38
|
+
message:
|
|
39
|
+
'Describe the issue (Vim: i to write, Esc then :wq to save & exit. Nano: Ctrl+O, Enter, Ctrl+X):',
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -43,7 +44,8 @@ export async function getReviewData(options = {}, config = {}) {
|
|
|
43
44
|
coreQuestions.push({
|
|
44
45
|
type: 'editor',
|
|
45
46
|
name: 'fix',
|
|
46
|
-
message:
|
|
47
|
+
message:
|
|
48
|
+
'Suggested fix (Vim: i to write, Esc then :wq to save & exit. Nano: Ctrl+O, Enter, Ctrl+X):',
|
|
47
49
|
});
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -102,12 +104,14 @@ export async function getReviewData(options = {}, config = {}) {
|
|
|
102
104
|
{
|
|
103
105
|
type: 'editor',
|
|
104
106
|
name: 'before',
|
|
105
|
-
message:
|
|
107
|
+
message:
|
|
108
|
+
'Original Code (Before) (Vim: i to write, Esc then :wq to save & exit. Nano: Ctrl+O, Enter, Ctrl+X):',
|
|
106
109
|
},
|
|
107
110
|
{
|
|
108
111
|
type: 'editor',
|
|
109
112
|
name: 'after',
|
|
110
|
-
message:
|
|
113
|
+
message:
|
|
114
|
+
'Proposed Code (After) (Vim: i to write, Esc then :wq to save & exit. Nano: Ctrl+O, Enter, Ctrl+X):',
|
|
111
115
|
},
|
|
112
116
|
]);
|
|
113
117
|
}
|
package/tests/features.test.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'fs';
|
|
|
3
3
|
import { generateMarkdown } from '../src/formatter.js';
|
|
4
4
|
import { detectGithubRepo } from '../src/github.js';
|
|
5
5
|
import { polishText } from '../src/ai.js';
|
|
6
|
+
import { loadConfig } from '../src/config.js';
|
|
6
7
|
|
|
7
8
|
describe('v2.0.0 Features Test Suite', () => {
|
|
8
9
|
let existsSyncSpy;
|
|
@@ -207,4 +208,46 @@ describe('v2.0.0 Features Test Suite', () => {
|
|
|
207
208
|
);
|
|
208
209
|
});
|
|
209
210
|
});
|
|
211
|
+
|
|
212
|
+
describe('Editor Config Guardrails', () => {
|
|
213
|
+
it('should dynamically set process.env.EDITOR to nano on non-windows systems if not defined', () => {
|
|
214
|
+
const originalPlatform = Object.getOwnPropertyDescriptor(
|
|
215
|
+
process,
|
|
216
|
+
'platform'
|
|
217
|
+
);
|
|
218
|
+
const originalEditor = process.env.EDITOR;
|
|
219
|
+
const originalVisual = process.env.VISUAL;
|
|
220
|
+
|
|
221
|
+
delete process.env.EDITOR;
|
|
222
|
+
delete process.env.VISUAL;
|
|
223
|
+
|
|
224
|
+
Object.defineProperty(process, 'platform', {
|
|
225
|
+
value: 'darwin',
|
|
226
|
+
configurable: true,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
existsSyncSpy.mockReturnValue(false);
|
|
230
|
+
|
|
231
|
+
loadConfig();
|
|
232
|
+
|
|
233
|
+
expect(process.env.EDITOR).toBe('nano');
|
|
234
|
+
|
|
235
|
+
// Restore original state
|
|
236
|
+
Object.defineProperty(process, 'platform', originalPlatform);
|
|
237
|
+
if (originalEditor !== undefined) process.env.EDITOR = originalEditor;
|
|
238
|
+
if (originalVisual !== undefined) process.env.VISUAL = originalVisual;
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should respect editor defined in config', () => {
|
|
242
|
+
const originalEditor = process.env.EDITOR;
|
|
243
|
+
existsSyncSpy.mockReturnValue(true);
|
|
244
|
+
readFileSyncSpy.mockReturnValue(JSON.stringify({ editor: 'vim-mock' }));
|
|
245
|
+
|
|
246
|
+
loadConfig();
|
|
247
|
+
|
|
248
|
+
expect(process.env.EDITOR).toBe('vim-mock');
|
|
249
|
+
|
|
250
|
+
if (originalEditor !== undefined) process.env.EDITOR = originalEditor;
|
|
251
|
+
});
|
|
252
|
+
});
|
|
210
253
|
});
|