Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/cli/src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { logError } from './logger';

export function getApiKey(): string {
// 1. Check environment variable
Expand All @@ -20,10 +21,10 @@ export function getApiKey(): string {
}
}
} catch (error) {
console.error('Warning: could not read config file:', configPath);
logError('Warning: could not read config file: ' + configPath, error);
}

// 3. Neither found, exit with error message
console.error('No API key found. Set JULES_API_KEY or run: jules_cli setup');
logError('No API key found. Set JULES_API_KEY or run: jules_cli setup');
process.exit(1);
}
30 changes: 20 additions & 10 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { Command } from 'commander';
import { JulesClient } from './client';
import { logError } from './logger';
import inquirer from 'inquirer';
import * as fs from 'fs';
import * as path from 'path';
Expand All @@ -13,13 +14,15 @@ const program = new Command();
program
.name('jules_cli')
.description('Jules CLI')
.version(version);
.version(version)
.option('-d, --debug', 'Enable debug logging');

program
.command('list')
.description('List Jules sessions')
.option('--json', 'Output raw JSON')
.action(async (options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
const response = await client.getSessions();
Expand All @@ -45,7 +48,7 @@ program
});
}
} catch (error: any) {
console.error('Error listing sessions:', error.message);
logError('Error listing sessions.', error, debug);
process.exit(1);
}
});
Expand All @@ -54,6 +57,7 @@ program
.command('setup')
.description('Setup Jules API key')
.action(async () => {
const debug = program.opts().debug;
try {
const answers = await inquirer.prompt([
{
Expand All @@ -67,7 +71,7 @@ program
const apiKey = answers.apiKey;

if (!apiKey) {
console.error('API key is required.');
logError('API key is required.', null, debug);
process.exit(1);
}

Expand All @@ -84,7 +88,7 @@ program

console.log('Setup complete. API key saved to ~/.config/jules/config.json');
} catch (error: any) {
console.error('Setup failed:', error.message);
logError('Setup failed.', error, debug);
process.exit(1);
}
});
Expand All @@ -98,6 +102,7 @@ program
.option('--approve-plan', 'Require plan approval')
.option('--json', 'Output raw JSON')
.action(async (options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();

Expand Down Expand Up @@ -128,7 +133,7 @@ program
console.log(`State: ${state}`);
}
} catch (error: any) {
console.error('Error creating session:', error.message);
logError('Error creating session.', error, debug);
process.exit(1);
}
});
Expand All @@ -138,6 +143,7 @@ program
.description('Show details of a Jules session')
.option('--json', 'Output raw JSON')
.action(async (sessionId, options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
const session = await client.getSession(sessionId);
Expand All @@ -155,7 +161,7 @@ program
console.log(`Last Updated: ${lastUpdated}`);
}
} catch (error: any) {
console.error('Error fetching session:', error.message);
logError('Error fetching session.', error, debug);
process.exit(1);
}
});
Expand All @@ -164,12 +170,13 @@ program
.command('approve <session-id>')
.description('Approve a Jules session plan')
.action(async (sessionId) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
await client.approvePlan(sessionId);
console.log(`Successfully approved plan for session ${sessionId}`);
} catch (error: any) {
console.error('Error approving plan:', error.message);
logError('Error approving plan.', error, debug);
process.exit(1);
}
});
Expand All @@ -180,6 +187,7 @@ program
.requiredOption('--message <message>', 'Message to send')
.option('--json', 'Output raw JSON')
.action(async (sessionId, options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
const response = await client.sendMessage(sessionId, options.message);
Expand All @@ -190,7 +198,7 @@ program
console.log(`Successfully sent message to session ${sessionId}`);
}
} catch (error: any) {
console.error('Error sending message:', error.message);
logError('Error sending message.', error, debug);
process.exit(1);
}
});
Expand All @@ -200,6 +208,7 @@ program
.description('Get the last message sent by Jules')
.option('--json', 'Output raw JSON')
.action(async (sessionId, options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
const response = await client.getActivities(sessionId);
Expand Down Expand Up @@ -229,7 +238,7 @@ program
}
}
} catch (error: any) {
console.error('Error fetching activities:', error.message);
logError('Error fetching activities.', error, debug);
process.exit(1);
}
});
Expand All @@ -239,6 +248,7 @@ program
.description('Get the PR URL for a completed session')
.option('--json', 'Output raw JSON')
.action(async (sessionId, options) => {
const debug = program.opts().debug;
try {
const client = new JulesClient();
const session = await client.getSession(sessionId);
Expand All @@ -257,7 +267,7 @@ program
}
}
} catch (error: any) {
console.error('Error fetching session:', error.message);
logError('Error fetching session.', error, debug);
process.exit(1);
}
});
Expand Down
14 changes: 14 additions & 0 deletions packages/cli/src/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export function logError(message: string, error?: any, debug?: boolean) {
const isDebug = debug || process.env.DEBUG === 'true' || process.env.DEBUG === '1';

console.error(message);

if (isDebug && error) {
if (error.message) {
console.error(`Debug info: ${error.message}`);
}
if (error.stack) {
console.error(error.stack);
}
}
Comment on lines +6 to +13

Choose a reason for hiding this comment

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

medium

The current implementation for logging debug information can be improved. It may not log anything for non-Error objects (like strings), and it produces redundant output for Error objects since error.stack usually includes error.message.

To make the debug logging more robust and concise, I suggest prioritizing error.stack, then falling back to error.message, and finally logging the raw error object if neither is available. This ensures all error types are handled and avoids duplicate information.

  if (isDebug && error) {
    if (error.stack) {
      console.error(error.stack);
    } else if (error.message) {
      console.error(`Debug info: ${error.message}`);
    } else {
      console.error('Debug info:', error);
    }
  }

Copy link
Owner Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi! I see you mentioned me on the logError implementation. I've designed this function to hide detailed error information (like internal messages and stack traces) from the standard output by default.

Detailed info is only logged if the user explicitly opts in via the -d/--debug flag or the DEBUG environment variable. This ensures that sensitive data isn't accidentally leaked during normal operation, fulfilling the security requirement while maintaining a path for troubleshooting.

If you'd like me to redirect these debug logs to a local log file instead of stderr, please let me know and I'll be happy to make that change!

}
Loading