Skip to content

Commit 3977a1c

Browse files
committed
fixing more lint & type issues
1 parent f262ae1 commit 3977a1c

File tree

9 files changed

+172
-137
lines changed

9 files changed

+172
-137
lines changed

.cursor/rules/derived-cursor-rules.mdc

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ The project follows a standard structure:
2929
- All commands should be defined in the `src/commands` directory.
3030
- Unit tests should be written for every command. Tests should accurately reflect command functionality. Avoid simple string matching in tests; instead verify behavior.
3131
- The `package.json` file should clearly define the entry point for the CLI.
32+
- Avoid using `any` type; explicitly define types for all variables to prevent runtime errors. (Added 2025-03-12)
33+
- Interface properties should be sorted alphabetically to satisfy `perfectionist/sort-object-types` linting rule. (Added 2025-03-12)
3234

3335

3436
## WORKFLOW & RELEASE RULES
@@ -42,6 +44,7 @@ The project follows a standard structure:
4244
## REFERENCE EXAMPLES
4345
- Running the CLI from source: See instructions in `2025-03-11_12-54-running-a-package-from-source-instructions.md`
4446
- Fixing TypeScript errors and missing modules: See `2025-03-12_14-21-fixing-typescript-errors-and-missing-modules.md`
47+
- Fixing type issues in `uninstall.ts`: See `2025-03-12_15-33-fixing-type-issues-in-uninstall-ts.md`
4548

4649

4750
## PROJECT DOCUMENTATION & CONTEXT SYSTEM
@@ -55,6 +58,8 @@ Documentation will be maintained using markdown files and integrated into the re
5558
- Test failures often indicate a mismatch between test expectations and actual command output. Refactor tests to reflect actual command behavior.
5659
- Deprecation warnings related to `fs.Stats` constructor indicate outdated code. Update the relevant code sections.
5760
- Use `npm run lint -- --fix` to automatically fix many linting errors.
61+
- `any` type errors indicate a need for explicit type definitions. Properly type variables to resolve these errors. (Added 2025-03-12)
62+
- `perfectionist/sort-object-types` linting errors indicate improperly ordered object properties. Ensure properties are alphabetically ordered. (Added 2025-03-12)
5863

5964

6065
## FINAL DOs AND DON'Ts
@@ -63,8 +68,12 @@ Documentation will be maintained using markdown files and integrated into the re
6368
- **DO** build the project using `npm run build` before running.
6469
- **DO** follow the folder organization guidelines.
6570
- **DO** install all necessary dependencies using `npm install`.
71+
- **DO** explicitly define types for all variables to avoid runtime errors. (Added 2025-03-12)
72+
- **DO** sort object properties alphabetically to satisfy linting rules. (Added 2025-03-12)
6673
- **DON'T** run the CLI without building the TypeScript code first.
6774
- **DON'T** leave variables untyped; ensure proper type declarations to avoid runtime errors.
6875
- **DON'T** write tests that rely on simple string matching of command output. Focus on verifying actual command behavior.
6976
- **DON'T** ignore deprecation warnings; address them promptly to maintain code quality and avoid future compatibility issues.
70-
- **DON'T** ignore linting errors; address them using `npm run lint -- --fix` or manually.
77+
- **DON'T** ignore linting errors; address them using `npm run lint -- --fix` or manually.
78+
- **DON'T** use `any` type unless absolutely necessary and with clear justification. (Added 2025-03-12)
79+
- **DON'T** leave object properties unsorted; maintain alphabetical order for consistency and to satisfy linting rules. (Added 2025-03-12)

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"oclif": "^4",
3131
"shx": "^0.3.3",
3232
"ts-node": "^10",
33-
"typescript": "^5"
33+
"typescript": "~5.3.3"
3434
},
3535
"engines": {
3636
"node": ">=18.0.0"

src/commands/install.ts

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,22 @@ export default class Install extends Command {
112112
}
113113

114114
private async installMCPServer(configPath: string, serverName: string, client: string): Promise<void> {
115-
let config: any = {}
115+
interface ConfigType {
116+
experimental?: {
117+
modelContextProtocolServers?: Array<{
118+
transport: {
119+
args: string[];
120+
command: string;
121+
env: Record<string, string>;
122+
type: string;
123+
};
124+
}>;
125+
useTools?: boolean;
126+
};
127+
mcpServers?: Record<string, unknown>;
128+
}
129+
130+
let config: ConfigType = {}
116131

117132
try {
118133
// Check if file exists
@@ -128,7 +143,7 @@ export default class Install extends Command {
128143
// Create empty config
129144
config = {}
130145
} else {
131-
throw error // Re-throw if it's not a missing file error
146+
throw error
132147
}
133148
}
134149

@@ -140,7 +155,7 @@ export default class Install extends Command {
140155
const finalArgs = [...serverConfig.args]
141156
if (serverConfig.runtimeArgs) {
142157
const runtimeArg = serverConfig.runtimeArgs
143-
let answer: any
158+
let answer: string | string[]
144159

145160
// Special case for filesystem-ref server
146161
let defaultValue = runtimeArg.default
@@ -152,26 +167,35 @@ export default class Install extends Command {
152167

153168
if (runtimeArg.multiple) {
154169
// First get the default path
155-
answer = await inquirer.input({
170+
const initialAnswer = await inquirer.input({
156171
default: Array.isArray(defaultValue) ? defaultValue.join(', ') : defaultValue,
157172
message: runtimeArg.description,
158173
})
159-
const paths = answer.split(',').map((s: string) => s.trim())
174+
const paths = initialAnswer.split(',').map((s: string) => s.trim())
160175

161-
// Keep asking for additional paths
162-
while (true) {
163-
const additionalPath = await inquirer.input({
176+
// Keep asking for additional paths until empty input
177+
const getAdditionalPaths = async (): Promise<string[]> => {
178+
const additionalPaths: string[] = []
179+
let input = await inquirer.input({
164180
default: "",
165181
message: "Add another allowed directory path? (press Enter to finish)",
166182
})
167183

168-
if (!additionalPath.trim()) {
169-
break
184+
while (input.trim()) {
185+
additionalPaths.push(input.trim())
186+
// eslint-disable-next-line no-await-in-loop
187+
input = await inquirer.input({
188+
default: "",
189+
message: "Add another allowed directory path? (press Enter to finish)",
190+
})
170191
}
171192

172-
paths.push(additionalPath.trim())
193+
return additionalPaths
173194
}
174195

196+
const additionalPaths = await getAdditionalPaths()
197+
paths.push(...additionalPaths)
198+
175199
answer = paths
176200
} else {
177201
answer = await inquirer.input({
@@ -193,6 +217,7 @@ export default class Install extends Command {
193217
const answers: Record<string, string> = {}
194218

195219
for (const [key, value] of Object.entries(envVars)) {
220+
// eslint-disable-next-line no-await-in-loop
196221
const answer = await inquirer.input({
197222
message: value.description,
198223
validate(input: string) {
@@ -238,8 +263,8 @@ export default class Install extends Command {
238263

239264
// Find if server already exists in the array
240265
const existingServerIndex = config.experimental.modelContextProtocolServers.findIndex(
241-
(s: any) => s.transport.command === serverConfig.command &&
242-
JSON.stringify(s.transport.args) === JSON.stringify(finalArgs)
266+
(s) => s.transport.command === serverConfig.command &&
267+
JSON.stringify(s.transport.args) === JSON.stringify(finalArgs)
243268
)
244269

245270
if (existingServerIndex >= 0) {
@@ -274,7 +299,7 @@ export default class Install extends Command {
274299
}
275300
}
276301

277-
private async installOnWindows(serverName: string, client: string): Promise<void> {
302+
private async installOnWindows(_serverName: string, _client: string): Promise<void> {
278303
// TODO: Implement Windows-specific installation logic
279304
throw new Error('Windows installation not implemented yet')
280305
}
@@ -297,73 +322,23 @@ export default class Install extends Command {
297322
throw new Error(`Unknown client: ${client}`)
298323
}
299324

325+
const sleep = (ms: number) => new Promise(resolve => { setTimeout(resolve, ms) })
326+
300327
try {
301328
const {platform} = process
302329
if (platform === 'darwin') {
303330
if (client === 'continue') {
304-
try {
305-
// First, find VS Code's installation location
306-
const findVSCode = await execAsync('mdfind "kMDItemCFBundleIdentifier == \'com.microsoft.VSCode\'" | head -n1')
307-
const vscodePath = findVSCode.stdout.trim()
308-
309-
if (vscodePath) {
310-
const electronPath = path.join(vscodePath, 'Contents/MacOS/Electron')
311-
// Check if VS Code is running using the found path
312-
const vscodeProcesses = await execAsync(`pgrep -fl "${electronPath}"`)
313-
if (vscodeProcesses.stdout.trim().length > 0) {
314-
// Use pkill with full path to ensure we only kill VS Code's Electron
315-
await execAsync(`pkill -f "${electronPath}"`)
316-
await new Promise(resolve => setTimeout(resolve, 2000))
317-
await execAsync(`open -a "Visual Studio Code"`)
318-
this.log(`✨ Continue (VS Code) has been restarted`)
319-
return
320-
}
321-
}
322-
} catch {
323-
// VS Code not found or error in detection, try JetBrains
324-
try {
325-
const jetbrainsProcesses = await execAsync('pgrep -fl "IntelliJ IDEA.app"')
326-
if (jetbrainsProcesses.stdout.trim().length > 0) {
327-
await execAsync(`killall "idea"`)
328-
await new Promise(resolve => setTimeout(resolve, 2000))
329-
await execAsync(`open -a "IntelliJ IDEA"`)
330-
this.log(`✨ Continue (IntelliJ IDEA) has been restarted`)
331-
return
332-
}
333-
} catch {
334-
// JetBrains not found
335-
}
336-
}
337-
338-
throw new Error('Could not detect running IDE (VS Code or JetBrains) for Continue')
331+
await this.restartContinueClient()
339332
} else {
340333
// For other clients like Claude, use the normal process
341334
await execAsync(`killall "${processName}"`)
342-
await new Promise(resolve => setTimeout(resolve, 2000))
335+
await sleep(2000)
343336
await execAsync(`open -a "${processName}"`)
344337
this.log(`✨ ${this.clientDisplayNames[client]} has been restarted`)
345338
}
346339
} else if (platform === 'win32') {
347340
if (client === 'continue') {
348-
try {
349-
const vscodeProcess = await execAsync('tasklist /FI "IMAGENAME eq Code.exe" /FO CSV /NH')
350-
if (vscodeProcess.stdout.includes('Code.exe')) {
351-
await execAsync('taskkill /F /IM "Code.exe" && start "" "Visual Studio Code"')
352-
this.log(`✨ VS Code has been restarted`)
353-
return
354-
}
355-
356-
const jetbrainsProcess = await execAsync('tasklist /FI "IMAGENAME eq idea64.exe" /FO CSV /NH')
357-
if (jetbrainsProcess.stdout.includes('idea64.exe')) {
358-
await execAsync('taskkill /F /IM "idea64.exe" && start "" "IntelliJ IDEA"')
359-
this.log(`✨ IntelliJ IDEA has been restarted`)
360-
return
361-
}
362-
} catch {
363-
// Process detection failed
364-
}
365-
366-
throw new Error('Could not detect running IDE (VS Code or JetBrains) for Continue')
341+
await this.restartContinueClientWindows()
367342
} else {
368343
// For other clients
369344
await execAsync(`taskkill /F /IM "${processName}.exe" && start "" "${processName}.exe"`)
@@ -386,6 +361,68 @@ export default class Install extends Command {
386361
}
387362
}
388363

364+
private async restartContinueClient(): Promise<void> {
365+
const sleep = (ms: number) => new Promise(resolve => { setTimeout(resolve, ms) })
366+
367+
try {
368+
// First, find VS Code's installation location
369+
const findVSCode = await execAsync('mdfind "kMDItemCFBundleIdentifier == \'com.microsoft.VSCode\'" | head -n1')
370+
const vscodePath = findVSCode.stdout.trim()
371+
372+
if (vscodePath) {
373+
const electronPath = path.join(vscodePath, 'Contents/MacOS/Electron')
374+
// Check if VS Code is running using the found path
375+
const vscodeProcesses = await execAsync(`pgrep -fl "${electronPath}"`)
376+
if (vscodeProcesses.stdout.trim().length > 0) {
377+
// Use pkill with full path to ensure we only kill VS Code's Electron
378+
await execAsync(`pkill -f "${electronPath}"`)
379+
await sleep(2000)
380+
await execAsync(`open -a "Visual Studio Code"`)
381+
this.log(`✨ Continue (VS Code) has been restarted`)
382+
return
383+
}
384+
}
385+
} catch {
386+
// VS Code not found or error in detection, try JetBrains
387+
try {
388+
const jetbrainsProcesses = await execAsync('pgrep -fl "IntelliJ IDEA.app"')
389+
if (jetbrainsProcesses.stdout.trim().length > 0) {
390+
await execAsync(`killall "idea"`)
391+
await sleep(2000)
392+
await execAsync(`open -a "IntelliJ IDEA"`)
393+
this.log(`✨ Continue (IntelliJ IDEA) has been restarted`)
394+
return
395+
}
396+
} catch {
397+
// JetBrains not found
398+
}
399+
}
400+
401+
throw new Error('Could not detect running IDE (VS Code or JetBrains) for Continue')
402+
}
403+
404+
private async restartContinueClientWindows(): Promise<void> {
405+
try {
406+
const vscodeProcess = await execAsync('tasklist /FI "IMAGENAME eq Code.exe" /FO CSV /NH')
407+
if (vscodeProcess.stdout.includes('Code.exe')) {
408+
await execAsync('taskkill /F /IM "Code.exe" && start "" "Visual Studio Code"')
409+
this.log(`✨ VS Code has been restarted`)
410+
return
411+
}
412+
413+
const jetbrainsProcess = await execAsync('tasklist /FI "IMAGENAME eq idea64.exe" /FO CSV /NH')
414+
if (jetbrainsProcess.stdout.includes('idea64.exe')) {
415+
await execAsync('taskkill /F /IM "idea64.exe" && start "" "IntelliJ IDEA"')
416+
this.log(`✨ IntelliJ IDEA has been restarted`)
417+
return
418+
}
419+
} catch {
420+
// Process detection failed
421+
}
422+
423+
throw new Error('Could not detect running IDE (VS Code or JetBrains) for Continue')
424+
}
425+
389426
private async validateServer(serverName: string): Promise<MCPServerType> {
390427
const server = servers.find(s => s.id === serverName)
391428
if (!server) {

0 commit comments

Comments
 (0)