Skip to content

feat: add Coderrr Insights dashboard for productivity tracking and Skills for better workflow#124

Merged
Akash-nath29 merged 6 commits intomainfrom
dev
Jan 30, 2026
Merged

feat: add Coderrr Insights dashboard for productivity tracking and Skills for better workflow#124
Akash-nath29 merged 6 commits intomainfrom
dev

Conversation

@Akash-nath29
Copy link
Owner

This pull request introduces several significant improvements to Coderrr, focusing on enhanced project customization, safer file operations, robust command execution, and better documentation. The most important changes are grouped below:

Project Customization and Documentation:

  • Added a new "Project Customization" section to the README.md, detailing support for Skills.md (project-wide coding guidelines), Coderrr.md (task-specific instructions), and persistent cross-session memory via .coderrr/memory.json. Also, a new docs/insights-guide.md was added to document the Coderrr Insights analytics feature. [1] [2] [3] [4]

File Operation Safety and Guidance:

  • Updated backend and documentation to enforce protection of critical configuration files (Coderrr.md, Skills.md, .coderrr/). Added explicit rules and reminders to never delete these files, clarified when to use patch_file vs update_file, and required reading a file before patching. These rules are now included in both the backend prompt and self-healing instructions. [1] [2] [3] [4]

Command Execution Improvements:

  • Overhauled command execution to run long-running shell commands in separate terminal windows, keeping Coderrr responsive. Added process tracking and cleanup on exit, ensuring that spawned processes are terminated properly. [1] [2] [3] [4]

Self-Healing and Plan Execution Context:

  • Enhanced the self-healing mechanism to include context about already completed steps, preventing repeated or invalid actions (such as re-deleting files). Now, completed steps are tracked and passed to the self-healing logic for more accurate error recovery. [1] [2] [3] [4] [5] [6]

File Patching Robustness:

  • Improved the patchFile method in src/fileOps.js to support more flexible and robust matching, including normalization of line endings and fuzzy line-by-line matching, to better handle differences between AI output and actual file content.

Copilot AI review requested due to automatic review settings January 30, 2026 19:42
@vercel
Copy link

vercel bot commented Jan 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
coderrr-backend Ready Ready Preview, Comment Jan 30, 2026 7:42pm

@github-actions
Copy link

🚀 Thanks for opening a Pull Request!

A maintainer will review this soon.

Meanwhile:
✔ Ensure tests are passing
✔ Link related issues
✔ Code follows the project guidelines

Your contribution helps make this project better!

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request introduces a Coderrr Insights dashboard for productivity tracking, adds support for Skills.md/Coderrr.md customization files, and implements a separate terminal execution feature for long-running commands. However, several critical issues prevent this from being ready for merge.

Changes:

  • Added insights tracking infrastructure (module, UI, metrics utility) but failed to integrate it with the agent - insights are never actually recorded
  • Implemented cross-platform separate terminal execution with process tracking and cleanup
  • Enhanced file patching with multiple matching strategies for better robustness
  • Added protected files rules to backend and self-healing improvements with completed steps context
  • Updated documentation for new features and project customization options

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 19 comments.

Show a summary per file
File Description
src/insights.js New insights tracking module - NOT INTEGRATED with agent
src/insightsUI.js Display dashboard for insights - lacks error handling
src/utils/metrics.js Calculate time savings - NEVER USED
test/insights.test.js Basic test for insights module
src/executor.js Separate terminal execution - CRITICAL SECURITY ISSUES with command injection
src/agent.js Process tracking/cleanup and self-healing - BREAKS ALL COMMANDS by running in separate terminals
src/fileOps.js Enhanced patch matching - bug in empty line handling
backend/main.py Protected files guidance - good additions
bin/coderrr.js Adds insights command - minor ordering issue
docs/insights-guide.md Documentation - claims unimplemented feature
README.md Documentation updates - good additions
test/test-custom-prompt.js Fixed import path
package-lock.json Version bump to 1.1.1
Comments suppressed due to low confidence (1)

src/fileOps.js:247

  • The enhanced patchFile method with three matching strategies adds significant complexity (nearly 90 lines of new logic) but lacks test coverage. Given that this project uses Jest and has test files, you should add tests to verify the different matching strategies work correctly, handle edge cases (e.g., multiple matches, partial matches, files with mixed line endings), and provide helpful error messages when patterns aren't found.
  async patchFile(filePath, oldContent, newContent) {
    try {
      const absolutePath = this.resolvePath(filePath);

      // Check if file exists
      if (!fs.existsSync(absolutePath)) {
        throw new Error(`File not found: ${filePath}`);
      }

      // Read current content
      const originalContent = fs.readFileSync(absolutePath, 'utf8');

      // Try multiple matching strategies
      let patchedContent = null;

      // Strategy 1: Exact match
      if (originalContent.includes(oldContent)) {
        patchedContent = originalContent.replace(oldContent, newContent);
      }

      // Strategy 2: Normalize line endings (CRLF -> LF) and try again
      if (!patchedContent) {
        const normalizedOriginal = originalContent.replace(/\r\n/g, '\n');
        const normalizedOld = oldContent.replace(/\r\n/g, '\n');
        const normalizedNew = newContent.replace(/\r\n/g, '\n');

        if (normalizedOriginal.includes(normalizedOld)) {
          // Found with normalized line endings - apply patch and restore original line endings
          const hasWindowsLineEndings = originalContent.includes('\r\n');
          patchedContent = normalizedOriginal.replace(normalizedOld, normalizedNew);
          if (hasWindowsLineEndings) {
            patchedContent = patchedContent.replace(/\n/g, '\r\n');
          }
        }
      }

      // Strategy 3: Trim whitespace from each line and match
      if (!patchedContent) {
        const trimLines = (str) => str.split('\n').map(line => line.trim()).join('\n');
        const trimmedOriginal = trimLines(originalContent.replace(/\r\n/g, '\n'));
        const trimmedOld = trimLines(oldContent.replace(/\r\n/g, '\n'));

        if (trimmedOriginal.includes(trimmedOld)) {
          // Found with trimmed lines - need to find actual position
          // This is a fallback, so we'll do a line-by-line search
          const originalLines = originalContent.replace(/\r\n/g, '\n').split('\n');
          const oldLines = oldContent.replace(/\r\n/g, '\n').split('\n').filter(l => l.trim());

          // Find the starting line by matching first non-empty line
          let startIdx = -1;
          for (let i = 0; i < originalLines.length; i++) {
            if (originalLines[i].trim() === oldLines[0].trim()) {
              // Check if subsequent lines match
              let matches = true;
              for (let j = 0; j < oldLines.length && (i + j) < originalLines.length; j++) {
                if (originalLines[i + j].trim() !== oldLines[j].trim()) {
                  matches = false;
                  break;
                }
              }
              if (matches) {
                startIdx = i;
                break;
              }
            }
          }

          if (startIdx >= 0) {
            // Replace the lines
            const newLines = newContent.replace(/\r\n/g, '\n').split('\n');
            const beforeLines = originalLines.slice(0, startIdx);
            const afterLines = originalLines.slice(startIdx + oldLines.length);
            const hasWindowsLineEndings = originalContent.includes('\r\n');
            const lineEnding = hasWindowsLineEndings ? '\r\n' : '\n';
            patchedContent = [...beforeLines, ...newLines, ...afterLines].join(lineEnding);
          }
        }
      }

      // If no strategy worked, throw error with helpful message
      if (!patchedContent) {
        // Show what we were looking for to help debug
        const preview = oldContent.substring(0, 100).replace(/\n/g, '\\n');
        throw new Error(`Pattern not found in file: ${filePath}\nLooking for: "${preview}${oldContent.length > 100 ? '...' : ''}"`);
      }

      // Write back
      fs.writeFileSync(absolutePath, patchedContent, 'utf8');
      ui.displayFileOp('patch_file', filePath, 'success');

      return {
        success: true,
        path: absolutePath,
        oldContent: originalContent,
        newContent: patchedContent
      };
    } catch (error) {
      ui.displayFileOp('patch_file', filePath, 'error');
      throw error;
    }
  }

Comment on lines +497 to +500
{ cmd: 'gnome-terminal', args: ['--', 'bash', '-c', `${shellScript}; echo $$ > ${pidFile}`] },
{ cmd: 'konsole', args: ['-e', 'bash', '-c', `${shellScript}; echo $$ > ${pidFile}`] },
{ cmd: 'xfce4-terminal', args: ['-e', `bash -c "${shellScript}; echo $$ > ${pidFile}"`] },
{ cmd: 'xterm', args: ['-e', `bash -c "${shellScript}; echo $$ > ${pidFile}"`] }
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Linux shell script has the same command injection vulnerabilities as macOS. Additionally, the terminal args array (lines 497-500) directly interpolates shellScript and pidFile without proper escaping. If these paths contain shell special characters, they could be interpreted as shell commands. Use proper shell escaping or pass arguments through safer mechanisms.

Suggested change
{ cmd: 'gnome-terminal', args: ['--', 'bash', '-c', `${shellScript}; echo $$ > ${pidFile}`] },
{ cmd: 'konsole', args: ['-e', 'bash', '-c', `${shellScript}; echo $$ > ${pidFile}`] },
{ cmd: 'xfce4-terminal', args: ['-e', `bash -c "${shellScript}; echo $$ > ${pidFile}"`] },
{ cmd: 'xterm', args: ['-e', `bash -c "${shellScript}; echo $$ > ${pidFile}"`] }
{
cmd: 'gnome-terminal',
args: ['--', 'bash', '-c', 'script="$1"; pid="$2"; "$script"; echo $$ > "$pid"', '--', shellScript, pidFile]
},
{
cmd: 'konsole',
args: ['-e', 'bash', '-c', 'script="$1"; pid="$2"; "$script"; echo $$ > "$pid"', '--', shellScript, pidFile]
},
{
cmd: 'xfce4-terminal',
args: ['-e', 'bash', '-c', 'script="$1"; pid="$2"; "$script"; echo $$ > "$pid"', '--', shellScript, pidFile]
},
{
cmd: 'xterm',
args: ['-e', 'bash', '-c', 'script="$1"; pid="$2"; "$script"; echo $$ > "$pid"', '--', shellScript, pidFile]
}

Copilot uses AI. Check for mistakes.
};

// Handle various exit signals
process.on('exit', cleanup);
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup function is defined as async but the 'exit' event handler (line 92) doesn't await it. The Node.js 'exit' event is synchronous and cannot wait for async operations. This means spawned processes might not be properly terminated when the process exits normally. Consider using 'beforeExit' event for async cleanup, or make the cleanup synchronous where possible.

Suggested change
process.on('exit', cleanup);
process.on('beforeExit', cleanup);

Copilot uses AI. Check for mistakes.

## Features
- **Usage Statistics:** Track total tasks, file modifications, and self-healing successes.
- **Productivity Estimation:** See how much manual coding time you've potentially saved.
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation mentions "Productivity Estimation" as a feature (line 7), but the calculateSavings function from src/utils/metrics.js is never actually used in the insights display. This creates a discrepancy between what's documented and what's actually implemented.

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +18
const data = insights.getStats();
console.log('\n' + chalk.cyan.bold('📊 CODERRR INSIGHTS DASHBOARD'));
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));

console.log(`${chalk.white('Total Tasks Processed: ')} ${chalk.green.bold(data.totals.tasks)}`);
console.log(`${chalk.white('Files Modified: ')} ${chalk.yellow.bold(data.totals.filesChanged)}`);
console.log(`${chalk.white('Self-Healing Events: ')} ${chalk.magenta.bold(data.totals.healings)}`);

console.log('\n' + chalk.cyan.bold('🕒 RECENT ACTIVITY'));
data.sessions.slice(-5).reverse().forEach(s => {
const status = s.success ? chalk.green('✔') : chalk.red('✘');
const date = new Date(s.timestamp).toLocaleDateString();
console.log(`${status} ${chalk.gray(`[${date}]`)} ${s.task.substring(0, 40)}...`);
});
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The displayInsights() function can crash if getStats() throws an error or returns undefined/null. Additionally, if there are no sessions yet, data.sessions.slice(-5) will work but iterating may produce an error if sessions is not an array. Add error handling to gracefully handle cases where insights data is missing or corrupted.

Suggested change
const data = insights.getStats();
console.log('\n' + chalk.cyan.bold('📊 CODERRR INSIGHTS DASHBOARD'));
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
console.log(`${chalk.white('Total Tasks Processed: ')} ${chalk.green.bold(data.totals.tasks)}`);
console.log(`${chalk.white('Files Modified: ')} ${chalk.yellow.bold(data.totals.filesChanged)}`);
console.log(`${chalk.white('Self-Healing Events: ')} ${chalk.magenta.bold(data.totals.healings)}`);
console.log('\n' + chalk.cyan.bold('🕒 RECENT ACTIVITY'));
data.sessions.slice(-5).reverse().forEach(s => {
const status = s.success ? chalk.green('✔') : chalk.red('✘');
const date = new Date(s.timestamp).toLocaleDateString();
console.log(`${status} ${chalk.gray(`[${date}]`)} ${s.task.substring(0, 40)}...`);
});
let data;
try {
data = insights.getStats();
} catch (error) {
console.error(chalk.red('Failed to load insights data:'), error && error.message ? error.message : error);
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
return;
}
if (!data || typeof data !== 'object') {
console.error(chalk.red('Insights data is missing or invalid.'));
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
return;
}
const totals = (data.totals && typeof data.totals === 'object') ? data.totals : {};
const totalTasks = Number.isFinite(totals.tasks) ? totals.tasks : 0;
const filesChanged = Number.isFinite(totals.filesChanged) ? totals.filesChanged : 0;
const healings = Number.isFinite(totals.healings) ? totals.healings : 0;
console.log('\n' + chalk.cyan.bold('📊 CODERRR INSIGHTS DASHBOARD'));
console.log(chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
console.log(`${chalk.white('Total Tasks Processed: ')} ${chalk.green.bold(totalTasks)}`);
console.log(`${chalk.white('Files Modified: ')} ${chalk.yellow.bold(filesChanged)}`);
console.log(`${chalk.white('Self-Healing Events: ')} ${chalk.magenta.bold(healings)}`);
console.log('\n' + chalk.cyan.bold('🕒 RECENT ACTIVITY'));
const sessions = Array.isArray(data.sessions) ? data.sessions : [];
if (sessions.length === 0) {
console.log(chalk.gray('No recent activity available.'));
} else {
sessions.slice(-5).reverse().forEach(s => {
const status = s && s.success ? chalk.green('✔') : chalk.red('✘');
const date = s && s.timestamp ? new Date(s.timestamp).toLocaleDateString() : 'Unknown date';
const task = s && typeof s.task === 'string' ? s.task : 'Unknown task';
console.log(`${status} ${chalk.gray(`[${date}]`)} ${task.substring(0, 40)}${task.length > 40 ? '...' : ''}`);
});
}

Copilot uses AI. Check for mistakes.
Comment on lines +314 to +324
Write-Host "Command: ${command.replace(/"/g, '\\"')}" -ForegroundColor Yellow
Write-Host "Started at: $(Get-Date)" -ForegroundColor Gray
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""

# Log start to file
"Command started at $(Get-Date)" | Out-File -FilePath "${outputFile.replace(/\\/g, '\\\\')}" -Encoding UTF8

try {
# Run command and tee output to both console and file
Invoke-Expression "${command.replace(/"/g, '\\"')}" 2>&1 | Tee-Object -FilePath "${outputFile.replace(/\\/g, '\\\\')}" -Append
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command string interpolation in the PowerShell script is vulnerable to command injection. If the command parameter contains backticks, dollar signs, or other PowerShell special characters, they could be interpreted as PowerShell code. The .replace(/"/g, '\\"') only escapes double quotes but doesn't handle other special characters. Consider using PowerShell's -Command parameter with proper escaping or writing the command to a temporary file instead of embedding it in the script.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +3
const fs = require('fs');

Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused variable fs.

Suggested change
const fs = require('fs');

Copilot uses AI. Check for mistakes.
ui.info('The terminal window will show the command output.');
} else {
const errorMsg = result.error || 'Unknown error';
stepResult = `Failed to start command: "${step.command}". Error: ${errorMsg}`;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value assigned to stepResult here is unused.

Suggested change
stepResult = `Failed to start command: "${step.command}". Error: ${errorMsg}`;
stepResult = `Failed to start command: "${step.command}". Error: ${errorMsg}`;
ui.error(stepResult);

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +205
let terminalProcess = null;
let childPid = null;

try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value assigned to terminalProcess here is unused.

Suggested change
let terminalProcess = null;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +205
let terminalProcess = null;
let childPid = null;

try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value assigned to terminalProcess here is unused.

Suggested change
let terminalProcess = null;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +205
let terminalProcess = null;
let childPid = null;

try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value assigned to terminalProcess here is unused.

Suggested change
let terminalProcess = null;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);
terminalProcess = result.process;
let childPid = null;
try {
if (platform === 'win32') {
// Windows: Use start command with cmd.exe
const result = await this.spawnWindowsTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else if (platform === 'darwin') {
// macOS: Use osascript to open Terminal.app
const result = await this.spawnMacTerminal(normalizedCommand, cwd, outputFile, pidFile);
childPid = result.pid;
} else {
// Linux: Try gnome-terminal, konsole, or xterm
const result = await this.spawnLinuxTerminal(normalizedCommand, cwd, outputFile, pidFile);

Copilot uses AI. Check for mistakes.
@Akash-nath29 Akash-nath29 merged commit 3c45703 into main Jan 30, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments