Skip to content
Merged
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
23 changes: 23 additions & 0 deletions app/components/@settings/core/AvatarDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,29 @@ export const AvatarDropdown = ({ onSelectTab }: AvatarDropdownProps) => {
Report Bug
</DropdownMenu.Item>

<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
'text-sm text-gray-700 dark:text-gray-200',
'hover:bg-purple-50 dark:hover:bg-purple-500/10',
'hover:text-purple-500 dark:hover:text-purple-400',
'cursor-pointer transition-all duration-200',
'outline-none',
'group',
)}
onClick={async () => {
try {
const { downloadDebugLog } = await import('~/utils/debugLogger');
await downloadDebugLog();
} catch (error) {
console.error('Failed to download debug log:', error);
}
}}
>
<div className="i-ph:download w-4 h-4 text-gray-400 group-hover:text-purple-500 dark:group-hover:text-purple-400 transition-colors" />
Download Debug Log
</DropdownMenu.Item>

<DropdownMenu.Item
className={classNames(
'flex items-center gap-2 px-4 py-2.5',
Expand Down
20 changes: 18 additions & 2 deletions app/components/header/HeaderActionButtons.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,35 @@ export function HeaderActionButtons({ chatStarted: _chatStarted }: HeaderActionB
{/* Deploy Button */}
{shouldShowButtons && <DeployButton />}

{/* Bug Report Button */}
{/* Debug Tools */}
{shouldShowButtons && (
<div className="flex border border-bolt-elements-borderColor rounded-md overflow-hidden text-sm">
<button
onClick={() =>
window.open('https://github.com/stackblitz-labs/bolt.diy/issues/new?template=bug_report.yml', '_blank')
}
className="rounded-md items-center justify-center [&:is(:disabled,.disabled)]:cursor-not-allowed [&:is(:disabled,.disabled)]:opacity-60 px-3 py-1.5 text-xs bg-accent-500 text-white hover:text-bolt-elements-item-contentAccent [&:not(:disabled,.disabled)]:hover:bg-bolt-elements-button-primary-backgroundHover outline-accent-500 flex gap-1.5"
className="rounded-l-md items-center justify-center [&:is(:disabled,.disabled)]:cursor-not-allowed [&:is(:disabled,.disabled)]:opacity-60 px-3 py-1.5 text-xs bg-accent-500 text-white hover:text-bolt-elements-item-contentAccent [&:not(:disabled,.disabled)]:hover:bg-bolt-elements-button-primary-backgroundHover outline-accent-500 flex gap-1.5"
title="Report Bug"
>
<div className="i-ph:bug" />
<span>Report Bug</span>
</button>
<div className="w-px bg-bolt-elements-borderColor" />
<button
onClick={async () => {
try {
const { downloadDebugLog } = await import('~/utils/debugLogger');
await downloadDebugLog();
} catch (error) {
console.error('Failed to download debug log:', error);
}
}}
className="rounded-r-md items-center justify-center [&:is(:disabled,.disabled)]:cursor-not-allowed [&:is(:disabled,.disabled)]:opacity-60 px-3 py-1.5 text-xs bg-accent-500 text-white hover:text-bolt-elements-item-contentAccent [&:not(:disabled,.disabled)]:hover:bg-bolt-elements-button-primary-backgroundHover outline-accent-500 flex gap-1.5"
title="Download Debug Log"
>
<div className="i-ph:download" />
<span>Debug Log</span>
</button>
</div>
)}
</div>
Expand Down
18 changes: 18 additions & 0 deletions app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,24 @@ export default function App() {
userAgent: navigator.userAgent,
timestamp: new Date().toISOString(),
});

// Initialize debug logging with improved error handling
import('./utils/debugLogger')
.then(({ debugLogger }) => {
/*
* The debug logger initializes itself and starts disabled by default
* It will only start capturing when enableDebugMode() is called
*/
const status = debugLogger.getStatus();
logStore.logSystem('Debug logging ready', {
initialized: status.initialized,
capturing: status.capturing,
enabled: status.enabled,
});
})
.catch((error) => {
logStore.logError('Failed to initialize debug logging', error);
});
}, []);

return (
Expand Down
69 changes: 69 additions & 0 deletions app/routes/api.git-info.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { json } from '@remix-run/cloudflare';
import { execSync } from 'child_process';
import { existsSync } from 'fs';

export async function loader() {
try {
// Check if we're in a git repository
if (!existsSync('.git')) {
return json({
branch: 'unknown',
commit: 'unknown',
isDirty: false,
});
}

// Get current branch
const branch = execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf8' }).trim();

// Get current commit hash
const commit = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();

// Check if working directory is dirty
const statusOutput = execSync('git status --porcelain', { encoding: 'utf8' });
const isDirty = statusOutput.trim().length > 0;

// Get remote URL
let remoteUrl: string | undefined;

try {
remoteUrl = execSync('git remote get-url origin', { encoding: 'utf8' }).trim();
} catch {
// No remote origin, leave as undefined
}

// Get last commit info
let lastCommit: { message: string; date: string; author: string } | undefined;

try {
const commitInfo = execSync('git log -1 --pretty=format:"%s|%ci|%an"', { encoding: 'utf8' }).trim();
const [message, date, author] = commitInfo.split('|');
lastCommit = {
message: message || 'unknown',
date: date || 'unknown',
author: author || 'unknown',
};
} catch {
// Could not get commit info
}

return json({
branch,
commit,
isDirty,
remoteUrl,
lastCommit,
});
} catch (error) {
console.error('Error fetching git info:', error);
return json(
{
branch: 'error',
commit: 'error',
isDirty: false,
error: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 },
);
}
}
Loading
Loading