centaurus-cli 2.7.2 → 2.8.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.
Files changed (86) hide show
  1. package/dist/cli-adapter.d.ts +8 -0
  2. package/dist/cli-adapter.d.ts.map +1 -1
  3. package/dist/cli-adapter.js +104 -37
  4. package/dist/cli-adapter.js.map +1 -1
  5. package/dist/config/mcp-config-manager.d.ts +53 -0
  6. package/dist/config/mcp-config-manager.d.ts.map +1 -0
  7. package/dist/config/mcp-config-manager.js +210 -0
  8. package/dist/config/mcp-config-manager.js.map +1 -0
  9. package/dist/config/slash-commands.d.ts +14 -0
  10. package/dist/config/slash-commands.d.ts.map +1 -0
  11. package/dist/config/slash-commands.js +65 -0
  12. package/dist/config/slash-commands.js.map +1 -0
  13. package/dist/context/handlers/wsl-handler.d.ts.map +1 -1
  14. package/dist/context/handlers/wsl-handler.js +2 -1
  15. package/dist/context/handlers/wsl-handler.js.map +1 -1
  16. package/dist/index.js +20 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp/mcp-command-handler.d.ts +16 -0
  19. package/dist/mcp/mcp-command-handler.d.ts.map +1 -0
  20. package/dist/mcp/mcp-command-handler.js +196 -0
  21. package/dist/mcp/mcp-command-handler.js.map +1 -0
  22. package/dist/mcp/mcp-server-manager.d.ts +30 -0
  23. package/dist/mcp/mcp-server-manager.d.ts.map +1 -0
  24. package/dist/mcp/mcp-server-manager.js +165 -0
  25. package/dist/mcp/mcp-server-manager.js.map +1 -0
  26. package/dist/mcp/mcp-tool-wrapper.d.ts +12 -0
  27. package/dist/mcp/mcp-tool-wrapper.d.ts.map +1 -0
  28. package/dist/mcp/mcp-tool-wrapper.js +57 -0
  29. package/dist/mcp/mcp-tool-wrapper.js.map +1 -0
  30. package/dist/services/ai-service-client.d.ts.map +1 -1
  31. package/dist/services/ai-service-client.js +20 -2
  32. package/dist/services/ai-service-client.js.map +1 -1
  33. package/dist/tools/command.js.map +1 -1
  34. package/dist/tools/file-ops.d.ts.map +1 -1
  35. package/dist/tools/file-ops.js +18 -10
  36. package/dist/tools/file-ops.js.map +1 -1
  37. package/dist/ui/components/App.d.ts +4 -0
  38. package/dist/ui/components/App.d.ts.map +1 -1
  39. package/dist/ui/components/App.js +235 -138
  40. package/dist/ui/components/App.js.map +1 -1
  41. package/dist/ui/components/FileCreationPreview.d.ts +8 -0
  42. package/dist/ui/components/FileCreationPreview.d.ts.map +1 -0
  43. package/dist/ui/components/FileCreationPreview.js +63 -0
  44. package/dist/ui/components/FileCreationPreview.js.map +1 -0
  45. package/dist/ui/components/InputBox.d.ts.map +1 -1
  46. package/dist/ui/components/InputBox.js +132 -4
  47. package/dist/ui/components/InputBox.js.map +1 -1
  48. package/dist/ui/components/InteractiveShell.d.ts +3 -1
  49. package/dist/ui/components/InteractiveShell.d.ts.map +1 -1
  50. package/dist/ui/components/InteractiveShell.js +46 -89
  51. package/dist/ui/components/InteractiveShell.js.map +1 -1
  52. package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -1
  53. package/dist/ui/components/MarkdownRenderer.js +16 -34
  54. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  55. package/dist/ui/components/MessageDisplay.d.ts.map +1 -1
  56. package/dist/ui/components/MessageDisplay.js +10 -2
  57. package/dist/ui/components/MessageDisplay.js.map +1 -1
  58. package/dist/ui/components/SlashCommandAutocomplete.d.ts +11 -0
  59. package/dist/ui/components/SlashCommandAutocomplete.d.ts.map +1 -0
  60. package/dist/ui/components/SlashCommandAutocomplete.js +15 -0
  61. package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -0
  62. package/dist/ui/components/StreamingMessageDisplay.d.ts.map +1 -1
  63. package/dist/ui/components/StreamingMessageDisplay.js +5 -5
  64. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  65. package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
  66. package/dist/ui/components/ToolExecutionMessage.js +96 -32
  67. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  68. package/dist/ui/components/ToolExecutionStatus.d.ts.map +1 -1
  69. package/dist/ui/components/ToolExecutionStatus.js +28 -1
  70. package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
  71. package/dist/utils/editor-utils.d.ts +50 -0
  72. package/dist/utils/editor-utils.d.ts.map +1 -0
  73. package/dist/utils/editor-utils.js +501 -0
  74. package/dist/utils/editor-utils.js.map +1 -0
  75. package/dist/utils/input-classifier.d.ts.map +1 -1
  76. package/dist/utils/input-classifier.js +4 -2
  77. package/dist/utils/input-classifier.js.map +1 -1
  78. package/dist/utils/shell.d.ts +34 -1
  79. package/dist/utils/shell.d.ts.map +1 -1
  80. package/dist/utils/shell.js +130 -123
  81. package/dist/utils/shell.js.map +1 -1
  82. package/dist/utils/syntax-checker.d.ts +24 -0
  83. package/dist/utils/syntax-checker.d.ts.map +1 -0
  84. package/dist/utils/syntax-checker.js +320 -0
  85. package/dist/utils/syntax-checker.js.map +1 -0
  86. package/package.json +5 -3
@@ -1,149 +1,156 @@
1
1
  import * as os from 'os';
2
- import spawn from 'cross-spawn'; // Use cross-spawn for better Windows support
2
+ import { exec } from 'child_process';
3
+ import { createRequire } from 'module';
4
+ // Use createRequire for ESM compatibility with native modules
5
+ const require = createRequire(import.meta.url);
6
+ const nodePty = require('@homebridge/node-pty-prebuilt-multiarch');
7
+ /**
8
+ * Check if PTY is available on this system
9
+ */
10
+ export function isPtyAvailable() {
11
+ return nodePty !== null;
12
+ }
13
+ export function killProcessTree(pid, signal) {
14
+ if (os.platform() === 'win32') {
15
+ exec(`taskkill /pid ${pid} /T /F`, (error, stdout, stderr) => {
16
+ if (error) {
17
+ // Fallback to normal kill if taskkill fails
18
+ try {
19
+ process.kill(pid, signal);
20
+ }
21
+ catch (e) {
22
+ // Ignore if process already gone
23
+ }
24
+ }
25
+ });
26
+ }
27
+ else {
28
+ // POSIX: Kill process group
29
+ try {
30
+ process.kill(-pid, signal);
31
+ }
32
+ catch (e) {
33
+ // Fallback to normal kill
34
+ try {
35
+ process.kill(pid, signal);
36
+ }
37
+ catch (e2) {
38
+ // Ignore
39
+ }
40
+ }
41
+ }
42
+ }
3
43
  export function getShellCommand() {
4
44
  return os.platform() === 'win32' ? 'powershell.exe' : (process.env.SHELL || '/bin/bash');
5
45
  }
6
- export function executeCommandInteractive(command, cwd, onData, onExit) {
46
+ /**
47
+ * Execute a command using node-pty for full terminal emulation.
48
+ * This provides true PTY support with colors, cursor positioning, and interactive programs.
49
+ */
50
+ export function executePtyCommand(command, cwd, onData, onExit) {
7
51
  const shell = getShellCommand();
8
- // cross-spawn handles the args parsing automatically/safely
9
- const args = os.platform() === 'win32' ? ['-Command', command] : ['-c', command];
10
- const childProcess = spawn(shell, args, {
52
+ const isWindows = os.platform() === 'win32';
53
+ const args = isWindows ? ['-Command', command] : ['-c', command];
54
+ // Get initial terminal dimensions
55
+ const cols = process.stdout.columns || 80;
56
+ const rows = process.stdout.rows || 24;
57
+ // Spawn PTY process
58
+ const ptyProcess = nodePty.spawn(shell, args, {
59
+ name: 'xterm-256color',
60
+ cols,
61
+ rows,
11
62
  cwd,
12
- stdio: ['pipe', 'pipe', 'pipe'], // CRITICAL: All pipes must be open
13
63
  env: {
14
64
  ...process.env,
15
- // Force Unbuffered Output so Python/Ruby print immediately
16
- PYTHONUNBUFFERED: '1',
17
- // Force Color Output (Many tools check this)
65
+ TERM: 'xterm-256color',
66
+ COLORTERM: 'truecolor',
18
67
  FORCE_COLOR: '1',
19
68
  CLICOLOR: '1',
20
- TERM: 'xterm-256color'
21
- }
69
+ PYTHONUNBUFFERED: '1',
70
+ },
22
71
  });
23
- // Throttling Logic (Keep this from your previous code)
24
- let buffer = '';
25
- let throttleTimer = null;
26
- const flush = () => {
27
- if (buffer) {
28
- onData(buffer, 'stdout'); // Merge to single stream for UI simplicity
29
- buffer = '';
72
+ let isRunning = true;
73
+ // Stream data as it comes
74
+ ptyProcess.onData((data) => {
75
+ onData(data);
76
+ });
77
+ // Handle exit
78
+ ptyProcess.onExit(({ exitCode }) => {
79
+ isRunning = false;
80
+ if (onExit) {
81
+ onExit(exitCode);
30
82
  }
31
- throttleTimer = null;
32
- };
33
- const handleData = (data) => {
34
- buffer += data.toString();
35
- if (!throttleTimer)
36
- throttleTimer = setTimeout(flush, 50); // 50ms debounce
37
- };
38
- childProcess.stdout?.on('data', handleData);
39
- childProcess.stderr?.on('data', handleData); // Merge stderr so user sees errors inline
40
- childProcess.on('close', (code) => {
41
- if (throttleTimer)
42
- clearTimeout(throttleTimer);
43
- flush();
44
- if (onExit)
45
- onExit(code ?? 0);
46
83
  });
47
84
  return {
48
- process: childProcess,
49
- // Simple write wrapper
50
- write: (input) => {
51
- if (childProcess.stdin && !childProcess.stdin.destroyed) {
52
- childProcess.stdin.write(input);
85
+ write: (data) => {
86
+ if (isRunning) {
87
+ ptyProcess.write(data);
88
+ }
89
+ },
90
+ resize: (cols, rows) => {
91
+ if (isRunning) {
92
+ ptyProcess.resize(cols, rows);
53
93
  }
54
94
  },
55
95
  kill: () => {
56
- childProcess.kill();
57
- }
96
+ if (isRunning) {
97
+ ptyProcess.kill();
98
+ isRunning = false;
99
+ }
100
+ },
101
+ isRunning: () => isRunning,
102
+ pid: ptyProcess.pid,
58
103
  };
59
104
  }
60
- export async function executeCommand(command, cwd, onData) {
61
- return new Promise((resolve) => {
62
- const platform = os.platform();
63
- const isWindows = platform === 'win32';
64
- // Determine shell and command format
65
- const shell = isWindows ? 'powershell.exe' : (process.env.SHELL || '/bin/bash');
66
- const shellArgs = isWindows ? ['-Command', command] : ['-c', command];
67
- // Spawn the process with explicit pipe mode
68
- const childProcess = spawn(shell, shellArgs, {
69
- cwd,
70
- windowsHide: true,
71
- stdio: ['pipe', 'pipe', 'pipe'], // Explicit pipe mode - no inheritance
72
- });
73
- let stdout = '';
74
- let stderr = '';
75
- let isResolved = false;
76
- // Throttling buffers
77
- let stdoutBuffer = '';
78
- let stderrBuffer = '';
79
- let throttleTimer = null;
80
- // Flush function - sends buffered data to callback
81
- const flush = () => {
82
- if (onData) {
83
- if (stdoutBuffer) {
84
- onData(stdoutBuffer, 'stdout');
85
- stdoutBuffer = '';
86
- }
87
- if (stderrBuffer) {
88
- onData(stderrBuffer, 'stderr');
89
- stderrBuffer = '';
90
- }
105
+ /**
106
+ * Execute a command interactively using PTY.
107
+ * Now exclusively uses node-pty for production-grade terminal experience.
108
+ */
109
+ export function executeCommandInteractive(command, cwd, onData, onExit) {
110
+ const ptyProc = executePtyCommand(command, cwd, (chunk) => onData(chunk, 'stdout'), onExit);
111
+ return {
112
+ process: null,
113
+ ptyProcess: ptyProc,
114
+ write: (input) => {
115
+ ptyProc.write(input);
116
+ },
117
+ kill: () => ptyProc.kill(),
118
+ signal: (signal) => {
119
+ // For PTY, send control characters for signals
120
+ if (signal === 'SIGINT') {
121
+ ptyProc.write('\x03'); // Ctrl+C
122
+ // Also try to kill after a short delay if it doesn't respond
123
+ setTimeout(() => {
124
+ if (ptyProc.isRunning()) {
125
+ ptyProc.kill();
126
+ }
127
+ }, 500);
91
128
  }
92
- throttleTimer = null;
93
- };
94
- // Capture stdout with throttled streaming
95
- childProcess.stdout?.on('data', (data) => {
96
- const chunk = data.toString();
97
- stdout += chunk;
98
- // Buffer the chunk
99
- stdoutBuffer += chunk;
100
- // Set throttle timer if not already running
101
- if (!throttleTimer && onData) {
102
- throttleTimer = setTimeout(flush, 50); // 50ms throttle
129
+ else if (signal === 'SIGTERM') {
130
+ ptyProc.kill();
103
131
  }
104
- });
105
- // Capture stderr with throttled streaming
106
- childProcess.stderr?.on('data', (data) => {
107
- const chunk = data.toString();
108
- stderr += chunk;
109
- // Buffer the chunk
110
- stderrBuffer += chunk;
111
- // Set throttle timer if not already running
112
- if (!throttleTimer && onData) {
113
- throttleTimer = setTimeout(flush, 50); // 50ms throttle
132
+ else {
133
+ ptyProc.kill();
114
134
  }
115
- });
116
- // Handle process completion
117
- childProcess.on('close', (exitCode) => {
118
- if (!isResolved) {
119
- isResolved = true;
120
- // Clear throttle timer and flush remaining data
121
- if (throttleTimer) {
122
- clearTimeout(throttleTimer);
123
- }
124
- flush();
125
- resolve({
126
- stdout,
127
- stderr,
128
- exitCode: exitCode ?? 0,
129
- });
130
- }
131
- });
132
- // Handle process errors
133
- childProcess.on('error', (error) => {
134
- if (!isResolved) {
135
- isResolved = true;
136
- // Clear throttle timer and flush remaining data
137
- if (throttleTimer) {
138
- clearTimeout(throttleTimer);
139
- }
140
- flush();
141
- resolve({
142
- stdout,
143
- stderr: stderr || error.message,
144
- exitCode: 1,
145
- });
135
+ },
136
+ resize: (cols, rows) => ptyProc.resize(cols, rows),
137
+ isPty: true,
138
+ };
139
+ }
140
+ export async function executeCommand(command, cwd, onData) {
141
+ return new Promise((resolve) => {
142
+ let output = '';
143
+ const proc = executeCommandInteractive(command, cwd, (chunk) => {
144
+ output += chunk;
145
+ if (onData) {
146
+ onData(chunk, 'stdout');
146
147
  }
148
+ }, (exitCode) => {
149
+ resolve({
150
+ stdout: output,
151
+ stderr: '',
152
+ exitCode,
153
+ });
147
154
  });
148
155
  });
149
156
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Result of a syntax check operation
3
+ */
4
+ export interface SyntaxCheckResult {
5
+ success: boolean;
6
+ language: string;
7
+ error?: string;
8
+ skipped?: boolean;
9
+ skipReason?: string;
10
+ }
11
+ /**
12
+ * Detect language from file path
13
+ */
14
+ export declare function detectLanguage(filePath: string): string;
15
+ /**
16
+ * Main syntax check function
17
+ * Checks the syntax of a file based on its extension
18
+ */
19
+ export declare function checkSyntax(filePath: string, content?: string): Promise<SyntaxCheckResult>;
20
+ /**
21
+ * Format syntax check result as a human-readable string
22
+ */
23
+ export declare function formatSyntaxCheckResult(result: SyntaxCheckResult): string;
24
+ //# sourceMappingURL=syntax-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syntax-checker.d.ts","sourceRoot":"","sources":["../../src/utils/syntax-checker.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AA6ED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgBvD;AA8KD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA6DhG;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAUzE"}
@@ -0,0 +1,320 @@
1
+ import * as vm from 'vm';
2
+ import * as path from 'path';
3
+ import * as fs from 'fs';
4
+ import { spawn } from 'child_process';
5
+ import * as ts from 'typescript';
6
+ /**
7
+ * File extension to language mapping
8
+ */
9
+ const LANGUAGE_MAP = {
10
+ // JavaScript
11
+ '.js': 'javascript',
12
+ '.mjs': 'javascript',
13
+ '.cjs': 'javascript',
14
+ '.jsx': 'javascript',
15
+ // TypeScript
16
+ '.ts': 'typescript',
17
+ '.tsx': 'typescript',
18
+ '.mts': 'typescript',
19
+ '.cts': 'typescript',
20
+ // Python
21
+ '.py': 'python',
22
+ '.pyw': 'python',
23
+ // JSON
24
+ '.json': 'json',
25
+ '.jsonc': 'json',
26
+ // Skip syntax checking for these (text/markup/config)
27
+ '.txt': 'text',
28
+ '.md': 'markdown',
29
+ '.markdown': 'markdown',
30
+ '.log': 'log',
31
+ '.csv': 'csv',
32
+ '.html': 'html',
33
+ '.htm': 'html',
34
+ '.css': 'css',
35
+ '.scss': 'scss',
36
+ '.sass': 'sass',
37
+ '.less': 'less',
38
+ '.xml': 'xml',
39
+ '.yaml': 'yaml',
40
+ '.yml': 'yaml',
41
+ '.toml': 'toml',
42
+ '.ini': 'ini',
43
+ '.cfg': 'config',
44
+ '.conf': 'config',
45
+ '.env': 'env',
46
+ '.gitignore': 'gitignore',
47
+ '.dockerignore': 'dockerignore',
48
+ '.editorconfig': 'config',
49
+ '.prettierrc': 'config',
50
+ '.eslintrc': 'config',
51
+ '.babelrc': 'config',
52
+ };
53
+ /**
54
+ * Languages that should skip syntax checking
55
+ */
56
+ const SKIP_SYNTAX_CHECK = new Set([
57
+ 'text',
58
+ 'markdown',
59
+ 'log',
60
+ 'csv',
61
+ 'html',
62
+ 'css',
63
+ 'scss',
64
+ 'sass',
65
+ 'less',
66
+ 'xml',
67
+ 'yaml',
68
+ 'toml',
69
+ 'ini',
70
+ 'config',
71
+ 'env',
72
+ 'gitignore',
73
+ 'dockerignore',
74
+ ]);
75
+ /**
76
+ * Detect language from file path
77
+ */
78
+ export function detectLanguage(filePath) {
79
+ const ext = path.extname(filePath).toLowerCase();
80
+ const basename = path.basename(filePath).toLowerCase();
81
+ // Check for special filenames without extensions
82
+ if (!ext) {
83
+ // Common config files without extensions
84
+ if (basename === 'dockerfile')
85
+ return 'dockerfile';
86
+ if (basename === 'makefile')
87
+ return 'makefile';
88
+ if (basename === '.gitignore')
89
+ return 'gitignore';
90
+ if (basename === '.dockerignore')
91
+ return 'dockerignore';
92
+ if (basename === '.env')
93
+ return 'env';
94
+ return 'unknown';
95
+ }
96
+ return LANGUAGE_MAP[ext] || 'unknown';
97
+ }
98
+ /**
99
+ * Check JavaScript syntax using vm.Script
100
+ */
101
+ function checkJavaScriptSyntax(content) {
102
+ try {
103
+ // Use vm.Script to parse and check syntax without execution
104
+ new vm.Script(content, { filename: 'syntax-check.js' });
105
+ return {
106
+ success: true,
107
+ language: 'JavaScript',
108
+ };
109
+ }
110
+ catch (error) {
111
+ const err = error;
112
+ return {
113
+ success: false,
114
+ language: 'JavaScript',
115
+ error: err.message,
116
+ };
117
+ }
118
+ }
119
+ /**
120
+ * Check TypeScript syntax using the TypeScript compiler API
121
+ */
122
+ function checkTypeScriptSyntax(content, filePath) {
123
+ try {
124
+ const isTsx = filePath.endsWith('.tsx');
125
+ const compilerOptions = {
126
+ noEmit: true,
127
+ target: ts.ScriptTarget.ESNext,
128
+ module: ts.ModuleKind.ESNext,
129
+ jsx: isTsx ? ts.JsxEmit.React : undefined,
130
+ strict: false, // Don't enforce strict mode for syntax checking
131
+ skipLibCheck: true,
132
+ allowJs: true,
133
+ };
134
+ // Create a simple in-memory source file
135
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.ESNext, true, isTsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS);
136
+ // Check for parse errors (syntax errors)
137
+ const parseErrors = [];
138
+ // Walk through the source file to find syntax errors
139
+ // TypeScript's createSourceFile doesn't throw on syntax errors,
140
+ // but we can check for diagnostic messages
141
+ const parseDiagnostics = sourceFile.parseDiagnostics;
142
+ if (parseDiagnostics && parseDiagnostics.length > 0) {
143
+ for (const diag of parseDiagnostics) {
144
+ const message = ts.flattenDiagnosticMessageText(diag.messageText, '\n');
145
+ const lineAndChar = sourceFile.getLineAndCharacterOfPosition(diag.start || 0);
146
+ parseErrors.push(`Line ${lineAndChar.line + 1}: ${message}`);
147
+ }
148
+ }
149
+ if (parseErrors.length > 0) {
150
+ return {
151
+ success: false,
152
+ language: 'TypeScript',
153
+ error: parseErrors.join('\n'),
154
+ };
155
+ }
156
+ return {
157
+ success: true,
158
+ language: 'TypeScript',
159
+ };
160
+ }
161
+ catch (error) {
162
+ const err = error;
163
+ return {
164
+ success: false,
165
+ language: 'TypeScript',
166
+ error: err.message,
167
+ };
168
+ }
169
+ }
170
+ /**
171
+ * Check Python syntax using the py_compile module
172
+ */
173
+ async function checkPythonSyntax(filePath) {
174
+ return new Promise((resolve) => {
175
+ // Use python -m py_compile to check syntax
176
+ const pythonCommands = process.platform === 'win32'
177
+ ? ['python', 'python3', 'py']
178
+ : ['python3', 'python'];
179
+ let attemptIndex = 0;
180
+ const tryNextCommand = () => {
181
+ if (attemptIndex >= pythonCommands.length) {
182
+ // No Python found
183
+ resolve({
184
+ success: true,
185
+ language: 'Python',
186
+ skipped: true,
187
+ skipReason: 'Python interpreter not found. Syntax check skipped.',
188
+ });
189
+ return;
190
+ }
191
+ const pythonCmd = pythonCommands[attemptIndex];
192
+ attemptIndex++;
193
+ const proc = spawn(pythonCmd, ['-m', 'py_compile', filePath], {
194
+ stdio: ['pipe', 'pipe', 'pipe'],
195
+ timeout: 5000, // 5 second timeout
196
+ });
197
+ let stderr = '';
198
+ proc.stderr.on('data', (data) => {
199
+ stderr += data.toString();
200
+ });
201
+ proc.on('error', () => {
202
+ // This python command failed, try next
203
+ tryNextCommand();
204
+ });
205
+ proc.on('close', (code) => {
206
+ if (code === 0) {
207
+ resolve({
208
+ success: true,
209
+ language: 'Python',
210
+ });
211
+ }
212
+ else {
213
+ // Parse the error message
214
+ const errorLines = stderr.trim().split('\n');
215
+ const relevantError = errorLines.length > 0
216
+ ? errorLines[errorLines.length - 1]
217
+ : 'Syntax error detected';
218
+ resolve({
219
+ success: false,
220
+ language: 'Python',
221
+ error: relevantError,
222
+ });
223
+ }
224
+ });
225
+ };
226
+ tryNextCommand();
227
+ });
228
+ }
229
+ /**
230
+ * Check JSON syntax using JSON.parse
231
+ */
232
+ function checkJsonSyntax(content) {
233
+ try {
234
+ JSON.parse(content);
235
+ return {
236
+ success: true,
237
+ language: 'JSON',
238
+ };
239
+ }
240
+ catch (error) {
241
+ const err = error;
242
+ return {
243
+ success: false,
244
+ language: 'JSON',
245
+ error: err.message,
246
+ };
247
+ }
248
+ }
249
+ /**
250
+ * Main syntax check function
251
+ * Checks the syntax of a file based on its extension
252
+ */
253
+ export async function checkSyntax(filePath, content) {
254
+ const language = detectLanguage(filePath);
255
+ // Skip syntax checking for text/config files
256
+ if (SKIP_SYNTAX_CHECK.has(language)) {
257
+ return {
258
+ success: true,
259
+ language: language.charAt(0).toUpperCase() + language.slice(1),
260
+ skipped: true,
261
+ skipReason: `Syntax check skipped for ${language} files`,
262
+ };
263
+ }
264
+ // Skip unknown file types
265
+ if (language === 'unknown') {
266
+ return {
267
+ success: true,
268
+ language: 'Unknown',
269
+ skipped: true,
270
+ skipReason: 'Syntax check skipped for unknown file type',
271
+ };
272
+ }
273
+ // Read content from file if not provided
274
+ let fileContent = content;
275
+ if (!fileContent) {
276
+ try {
277
+ fileContent = fs.readFileSync(filePath, 'utf-8');
278
+ }
279
+ catch (error) {
280
+ return {
281
+ success: true,
282
+ language: language.charAt(0).toUpperCase() + language.slice(1),
283
+ skipped: true,
284
+ skipReason: 'Could not read file for syntax check',
285
+ };
286
+ }
287
+ }
288
+ // Perform language-specific syntax check
289
+ switch (language) {
290
+ case 'javascript':
291
+ return checkJavaScriptSyntax(fileContent);
292
+ case 'typescript':
293
+ return checkTypeScriptSyntax(fileContent, filePath);
294
+ case 'python':
295
+ // Python requires the file to be on disk for py_compile
296
+ return await checkPythonSyntax(filePath);
297
+ case 'json':
298
+ return checkJsonSyntax(fileContent);
299
+ default:
300
+ return {
301
+ success: true,
302
+ language: language.charAt(0).toUpperCase() + language.slice(1),
303
+ skipped: true,
304
+ skipReason: `Syntax check not implemented for ${language}`,
305
+ };
306
+ }
307
+ }
308
+ /**
309
+ * Format syntax check result as a human-readable string
310
+ */
311
+ export function formatSyntaxCheckResult(result) {
312
+ if (result.skipped) {
313
+ return `(${result.skipReason})`;
314
+ }
315
+ if (result.success) {
316
+ return `✓ Syntax check passed (${result.language})`;
317
+ }
318
+ return `✗ Syntax error (${result.language}): ${result.error}`;
319
+ }
320
+ //# sourceMappingURL=syntax-checker.js.map