fix: resolve CI lint and TypeScript errors

- Fix Python formatting (ruff) in workspace.py, display.py, menu.py
- Fix TypeScript errors:
  - Add missing CompetitorAnalysis import in types.ts
  - Add type annotations to RoadmapHeader.tsx map callback
  - Add cn import and fix EnvConfigModal OAuth token handling
  - Add type annotations to InvestigationDialog.tsx
  - Add missing stopRoadmap and onRoadmapStopped to browser-mock
  - Add getIssueComments to ElectronAPI type and mocks
  - Update investigateGitHubIssue to accept optional selectedCommentIds
  - Fix CLAUDE_CODE_OAUTH_TOKEN access in agent-queue.ts
- Include pending bug fixes:
  - Add .trim() to git status parsing in worktree-handlers.ts
  - Change Accept header to application/octet-stream in http-client.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
AndyMik90
2025-12-18 20:22:55 +01:00
parent a6dad428e9
commit 2e3a5d9de5
14 changed files with 68 additions and 49 deletions
+10 -8
View File
@@ -195,14 +195,15 @@ export class AgentQueueManager {
};
// Debug: Show OAuth token source
const tokenSource = profileEnv.CLAUDE_CODE_OAUTH_TOKEN
const tokenSource = profileEnv['CLAUDE_CODE_OAUTH_TOKEN']
? 'Electron app profile'
: (combinedEnv.CLAUDE_CODE_OAUTH_TOKEN ? 'auto-claude/.env' : 'not found');
const hasToken = !!finalEnv.CLAUDE_CODE_OAUTH_TOKEN;
: (combinedEnv['CLAUDE_CODE_OAUTH_TOKEN'] ? 'auto-claude/.env' : 'not found');
const oauthToken = (finalEnv as Record<string, string | undefined>)['CLAUDE_CODE_OAUTH_TOKEN'];
const hasToken = !!oauthToken;
debugLog('[Agent Queue] OAuth token status:', {
source: tokenSource,
hasToken,
tokenPreview: hasToken ? finalEnv.CLAUDE_CODE_OAUTH_TOKEN?.substring(0, 20) + '...' : 'none'
tokenPreview: hasToken ? oauthToken?.substring(0, 20) + '...' : 'none'
});
const childProcess = spawn(pythonPath, args, {
@@ -428,14 +429,15 @@ export class AgentQueueManager {
};
// Debug: Show OAuth token source
const tokenSource = profileEnv.CLAUDE_CODE_OAUTH_TOKEN
const tokenSource = profileEnv['CLAUDE_CODE_OAUTH_TOKEN']
? 'Electron app profile'
: (combinedEnv.CLAUDE_CODE_OAUTH_TOKEN ? 'auto-claude/.env' : 'not found');
const hasToken = !!finalEnv.CLAUDE_CODE_OAUTH_TOKEN;
: (combinedEnv['CLAUDE_CODE_OAUTH_TOKEN'] ? 'auto-claude/.env' : 'not found');
const oauthToken = (finalEnv as Record<string, string | undefined>)['CLAUDE_CODE_OAUTH_TOKEN'];
const hasToken = !!oauthToken;
debugLog('[Agent Queue] OAuth token status:', {
source: tokenSource,
hasToken,
tokenPreview: hasToken ? finalEnv.CLAUDE_CODE_OAUTH_TOKEN?.substring(0, 20) + '...' : 'none'
tokenPreview: hasToken ? oauthToken?.substring(0, 20) + '...' : 'none'
});
const childProcess = spawn(pythonPath, args, {
@@ -541,7 +541,7 @@ export function registerWorktreeHandlers(
uncommittedFiles = gitStatus
.split('\n')
.filter(line => line.trim())
.map(line => line.substring(3)); // Skip 2 status chars + 1 space
.map(line => line.substring(3).trim()); // Skip 2 status chars + 1 space, trim any trailing whitespace
hasUncommittedChanges = uncommittedFiles.length > 0;
}
@@ -70,7 +70,7 @@ export function downloadFile(
const headers = {
'User-Agent': 'Auto-Claude-UI',
'Accept': 'application/vnd.github+json'
'Accept': 'application/octet-stream'
};
const request = https.get(url, { headers }, (response) => {
@@ -29,6 +29,7 @@ import {
TooltipContent,
TooltipTrigger
} from './ui/tooltip';
import { cn } from '../lib/utils';
interface EnvConfigModalProps {
open: boolean;
@@ -36,6 +37,7 @@ interface EnvConfigModalProps {
onConfigured?: () => void;
title?: string;
description?: string;
projectId?: string;
}
export function EnvConfigModal({
@@ -43,7 +45,8 @@ export function EnvConfigModal({
onOpenChange,
onConfigured,
title = 'Claude Authentication Required',
description = 'A Claude Code OAuth token is required to use AI features like Ideation and Roadmap generation.'
description = 'A Claude Code OAuth token is required to use AI features like Ideation and Roadmap generation.',
projectId
}: EnvConfigModalProps) {
const [token, setToken] = useState('');
const [showToken, setShowToken] = useState(false);
@@ -123,28 +126,18 @@ export function EnvConfigModal({
if (!open) return;
const cleanup = window.electronAPI.onTerminalOAuthToken(async (info) => {
if (info.success && info.token) {
// Save the OAuth token
try {
const result = await window.electronAPI.updateSourceEnv({
claudeOAuthToken: info.token
});
if (info.success) {
// Token is auto-saved to the profile by the main process
// Just update UI state to reflect authentication success
setSuccess(true);
setHasExistingToken(true);
setIsAuthenticating(false);
if (result.success) {
setSuccess(true);
setHasExistingToken(true);
setIsAuthenticating(false);
// Notify parent
setTimeout(() => {
onConfigured?.();
onOpenChange(false);
}, 1500);
}
} catch (err) {
setError('Failed to save authentication token');
setIsAuthenticating(false);
}
// Notify parent
setTimeout(() => {
onConfigured?.();
onOpenChange(false);
}, 1500);
}
});
@@ -191,12 +184,17 @@ export function EnvConfigModal({
};
const handleAuthenticateWithBrowser = async () => {
if (!projectId) {
setError('No project selected. Please select a project first.');
return;
}
setIsAuthenticating(true);
setError(null);
try {
// Invoke the Claude setup-token flow in terminal
const result = await window.electronAPI.invokeClaudeSetup();
const result = await window.electronAPI.invokeClaudeSetup(projectId);
if (!result.success) {
setError(result.error || 'Failed to start authentication');
@@ -44,14 +44,14 @@ export function InvestigationDialog({
setSelectedCommentIds([]);
window.electronAPI.getIssueComments(projectId, selectedIssue.number)
.then((result) => {
.then((result: { success: boolean; data?: GitHubComment[] }) => {
if (result.success && result.data) {
setComments(result.data);
// By default, select all comments
setSelectedCommentIds(result.data.map(c => c.id));
setSelectedCommentIds(result.data.map((c: GitHubComment) => c.id));
}
})
.catch((err) => {
.catch((err: unknown) => {
console.error('Failed to fetch comments:', err);
})
.finally(() => {
@@ -116,6 +116,7 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) {
onConfigured={handleEnvConfigured}
title="Claude Authentication Required"
description="A Claude Code OAuth token is required to generate AI-powered feature ideas."
projectId={projectId}
/>
</>
);
@@ -239,6 +240,7 @@ export function Ideation({ projectId, onGoToTask }: IdeationProps) {
onConfigured={handleEnvConfigured}
title="Claude Authentication Required"
description="A Claude Code OAuth token is required to generate AI-powered feature ideas."
projectId={projectId}
/>
</div>
);
@@ -28,7 +28,7 @@ export function RoadmapHeader({ roadmap, competitorAnalysis, onAddFeature, onRef
<TooltipContent className="max-w-md">
<div className="space-y-2">
<div className="font-semibold">Analyzed {competitorAnalysis.competitors.length} competitors:</div>
{competitorAnalysis.competitors.map((comp, idx) => (
{competitorAnalysis.competitors.map((comp: { name: string; painPoints: unknown[] }, idx: number) => (
<div key={idx} className="text-sm">
<div className="font-medium"> {comp.name}</div>
<div className="text-muted-foreground ml-3">{comp.painPoints.length} pain points identified</div>
@@ -1,4 +1,4 @@
import type { RoadmapFeature, RoadmapPhase, Roadmap, CompetitorPainPoint } from '../../../shared/types';
import type { RoadmapFeature, RoadmapPhase, Roadmap, CompetitorPainPoint, CompetitorAnalysis } from '../../../shared/types';
export interface RoadmapProps {
projectId: string;
@@ -83,10 +83,13 @@ const browserMockAPI: ElectronAPI = {
}
}),
stopRoadmap: async () => ({ success: true }),
// Roadmap Event Listeners
onRoadmapProgress: () => () => {},
onRoadmapComplete: () => () => {},
onRoadmapError: () => () => {},
onRoadmapStopped: () => () => {},
// Context Operations
...contextMock,
@@ -117,6 +117,11 @@ export const integrationMock = {
console.warn('[Browser Mock] investigateGitHubIssue called');
},
getIssueComments: async () => ({
success: true,
data: []
}),
importGitHubIssues: async () => ({
success: false,
error: 'Not available in browser mock'
+2 -1
View File
@@ -304,7 +304,8 @@ export interface ElectronAPI {
getGitHubIssues: (projectId: string, state?: 'open' | 'closed' | 'all') => Promise<IPCResult<GitHubIssue[]>>;
getGitHubIssue: (projectId: string, issueNumber: number) => Promise<IPCResult<GitHubIssue>>;
checkGitHubConnection: (projectId: string) => Promise<IPCResult<GitHubSyncStatus>>;
investigateGitHubIssue: (projectId: string, issueNumber: number) => void;
investigateGitHubIssue: (projectId: string, issueNumber: number, selectedCommentIds?: number[]) => void;
getIssueComments: (projectId: string, issueNumber: number) => Promise<IPCResult<Array<{ id: number; body: string; user: { login: string; avatar_url?: string }; created_at: string; updated_at: string }>>>;
importGitHubIssues: (projectId: string, issueNumbers: number[]) => Promise<IPCResult<GitHubImportResult>>;
createGitHubRelease: (
projectId: string,
+6 -2
View File
@@ -197,7 +197,9 @@ def merge_existing_build(
if had_conflicts:
# Git conflicts were resolved (via AI or lock file exclusion) - changes are already staged
_print_merge_success(no_commit, stats, spec_name=spec_name, keep_worktree=True)
_print_merge_success(
no_commit, stats, spec_name=spec_name, keep_worktree=True
)
# Don't auto-delete worktree - let user test and manually cleanup
# User can delete with: python auto-claude/run.py --spec <name> --discard
@@ -210,7 +212,9 @@ def merge_existing_build(
spec_name, delete_after=False, no_commit=no_commit
)
if success_result:
_print_merge_success(no_commit, stats, spec_name=spec_name, keep_worktree=True)
_print_merge_success(
no_commit, stats, spec_name=spec_name, keep_worktree=True
)
return True
elif smart_result.get("git_conflicts"):
# Had git conflicts that AI couldn't fully resolve
+4 -2
View File
@@ -74,7 +74,7 @@ def print_merge_success(
no_commit: bool,
stats: dict | None = None,
spec_name: str | None = None,
keep_worktree: bool = False
keep_worktree: bool = False,
) -> None:
"""Print a success message after merge."""
from ui import Icons, box, icon
@@ -131,7 +131,9 @@ def print_merge_success(
]
)
if spec_name:
lines.append(f" python auto-claude/run.py --spec {spec_name} --discard")
lines.append(
f" python auto-claude/run.py --spec {spec_name} --discard"
)
else:
lines.extend(
[
+8 -6
View File
@@ -12,12 +12,14 @@ from dataclasses import dataclass
try:
import termios
import tty
_HAS_TERMIOS = True
except ImportError:
_HAS_TERMIOS = False
try:
import msvcrt
_HAS_MSVCRT = True
except ImportError:
_HAS_MSVCRT = False
@@ -45,18 +47,18 @@ def _getch() -> str:
# Windows implementation
ch = msvcrt.getch()
# Handle special keys (arrow keys return two bytes)
if ch in (b'\x00', b'\xe0'):
if ch in (b"\x00", b"\xe0"):
ch2 = msvcrt.getch()
if ch2 == b'H':
if ch2 == b"H":
return "UP"
elif ch2 == b'P':
elif ch2 == b"P":
return "DOWN"
elif ch2 == b'M':
elif ch2 == b"M":
return "RIGHT"
elif ch2 == b'K':
elif ch2 == b"K":
return "LEFT"
return ""
return ch.decode('utf-8', errors='replace')
return ch.decode("utf-8", errors="replace")
elif _HAS_TERMIOS:
# Unix implementation
fd = sys.stdin.fileno()