mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-03-17 22:13:08 +00:00
* feat: add GitHub Copilot SDK provider integration Adds comprehensive GitHub Copilot SDK provider support including: - CopilotProvider class with CLI detection and OAuth authentication check - Copilot models definition with GPT-4o, Claude, and o1/o3 series models - Settings UI integration with provider tab, model configuration, and navigation - Onboarding flow integration with Copilot setup step - Model selector integration for all phase-specific model dropdowns - Persistence of enabled models and default model settings via API sync - Server route for Copilot CLI status endpoint https://claude.ai/code/session_01D26w7ZyEzP4H6Dor3ttk9d * chore: update package-lock.json https://claude.ai/code/session_01D26w7ZyEzP4H6Dor3ttk9d * refactor: rename Copilot SDK to Copilot CLI and use GitHub icon - Update all references from "GitHub Copilot SDK" to "GitHub Copilot CLI" - Change install command from @github/copilot-sdk to @github/copilot - Update CopilotIcon to use official GitHub Octocat logo - Update error codes and comments throughout codebase Co-Authored-By: Claude <noreply@anthropic.com> * fix: update Copilot model definitions and add dynamic model discovery - Update COPILOT_MODEL_MAP with correct models from CLI (claude-sonnet-4.5, claude-haiku-4.5, claude-opus-4.5, claude-sonnet-4, gpt-5.x series, gpt-4.1, gemini-3-pro-preview) - Change default Copilot model to copilot-claude-sonnet-4.5 - Add model caching methods to CopilotProvider (hasCachedModels, clearModelCache, refreshModels) - Add API routes for dynamic model discovery: - GET /api/setup/copilot/models - POST /api/setup/copilot/models/refresh - POST /api/setup/copilot/cache/clear Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * refactor: use @github/copilot-sdk instead of direct CLI calls - Install @github/copilot-sdk package for proper SDK integration - Rewrite CopilotProvider to use SDK's CopilotClient API - Use client.createSession() for session management - Handle SDK events (assistant.message, tool.execution_*, session.idle) - Auto-approve permissions for autonomous agent operation - Remove incorrect CLI flags (--mode, --output-format) - Update default model to claude-sonnet-4.5 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: add Copilot and Gemini model support to model resolver - Import isCopilotModel and isGeminiModel from types - Add explicit checks for copilot- and gemini- prefixed models - Pass through Copilot/Gemini models unchanged to their providers - Update resolver documentation to list all supported providers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: pass working directory to Copilot SDK and reduce event noise - Create CopilotClient per execution with correct cwd from options.cwd - This ensures the CLI operates in the correct project directory, not the server's current directory - Skip assistant.message_delta events (they create excessive noise) - Only yield the final assistant.message event which has complete content - Clean up client on completion and error paths Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: simplify Copilot SDK execution with sendAndWait - Use sendAndWait() instead of manual event polling for more reliable execution - Disable streaming (streaming: false) to simplify response handling - Increase timeout to 10 minutes for agentic operations - Still capture tool execution events for UI display - Add more debug logging for troubleshooting - This should fix the "invalid_request_body" error on subsequent calls Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: allow Copilot model IDs with claude-, gemini-, gpt- prefixes Copilot's bare model IDs legitimately contain prefixes like claude-, gemini-, gpt- because those are the actual model names from the Copilot CLI (e.g., claude-sonnet-4.5, gemini-3-pro-preview, gpt-5.1). The generic validateBareModelId function was incorrectly rejecting these valid model IDs. Now we only check that the copilot- prefix has been stripped by the ProviderFactory. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: enable real-time streaming of tool events for Copilot - Switch back to streaming mode (streaming: true) for real-time events - Use async queue pattern to bridge SDK callbacks to async generator - Events are now yielded as they happen, not batched at the end - Tool calls (Read, Write, Edit, Bash, TodoWrite, etc.) show in real-time - Better progress visibility during agentic operations Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat: expand Copilot tool name and input normalization Tool name mapping additions: - view → Read (Copilot's file viewing tool) - create_file → Write - replace, patch → Edit - run_shell_command, terminal → Bash - search_file_content → Grep - list_directory → Ls - google_web_search → WebSearch - report_intent → ReportIntent (Copilot-specific planning) - think, plan → Think, Plan Input normalization improvements: - Read/Write/Edit: Map file, filename, filePath → file_path - Bash: Map cmd, script → command - Grep: Map query, search, regex → pattern Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: convert git+ssh to git+https in package-lock.json The @electron/node-gyp dependency was resolved with a git+ssh URL which fails in CI environments without SSH keys. Convert to HTTPS. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address code review feedback for Copilot SDK provider - Add guard for non-text prompts (vision not yet supported) - Clear runtime model cache on fetch failure - Fix race condition in async queue error handling - Import CopilotAuthStatus from shared types - Fix comment mismatch for default model constant - Add auth-copilot and deauth-copilot routes - Extract shared tool normalization utilities - Create base model configuration UI component - Add comprehensive unit tests for CopilotProvider - Replace magic strings with constants - Add debug logging for cleanup errors * fix: address CodeRabbit review nitpicks - Fix test mocks to include --version check for CLI detection - Add aria-label for accessibility on refresh button - Ensure default model checkbox always appears checked/enabled * fix: address CodeRabbit review feedback - Fix test mocks by creating fresh provider instances after mock setup - Extract COPILOT_DISCONNECTED_MARKER_FILE constant to common.ts - Add AUTONOMOUS MODE comment explaining auto-approval of permissions - Improve tool-normalization with union types and null guards - Handle 'canceled' (American spelling) status in todo normalization * refactor: extract copilot connection logic to service and fix test mocks - Create copilot-connection-service.ts with connect/disconnect logic - Update auth-copilot and deauth-copilot routes to use service - Fix test mocks for CLI detection: - Mock fs.existsSync for CLI path validation - Mock which/where command for CLI path detection --------- Co-authored-by: Claude <noreply@anthropic.com>
287 lines
9.8 KiB
TypeScript
287 lines
9.8 KiB
TypeScript
/**
|
|
* Query Keys Factory
|
|
*
|
|
* Centralized query key definitions for React Query.
|
|
* Following the factory pattern for type-safe, consistent query keys.
|
|
*
|
|
* @see https://tkdodo.eu/blog/effective-react-query-keys
|
|
*/
|
|
|
|
/**
|
|
* Query keys for all API endpoints
|
|
*
|
|
* Structure follows the pattern:
|
|
* - ['entity'] for listing/global
|
|
* - ['entity', id] for single item
|
|
* - ['entity', id, 'sub-resource'] for nested resources
|
|
*/
|
|
export const queryKeys = {
|
|
// ============================================
|
|
// Features
|
|
// ============================================
|
|
features: {
|
|
/** All features for a project */
|
|
all: (projectPath: string) => ['features', projectPath] as const,
|
|
/** Single feature */
|
|
single: (projectPath: string, featureId: string) =>
|
|
['features', projectPath, featureId] as const,
|
|
/** Agent output for a feature */
|
|
agentOutput: (projectPath: string, featureId: string) =>
|
|
['features', projectPath, featureId, 'output'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Worktrees
|
|
// ============================================
|
|
worktrees: {
|
|
/** All worktrees for a project */
|
|
all: (projectPath: string) => ['worktrees', projectPath] as const,
|
|
/** Single worktree info */
|
|
single: (projectPath: string, featureId: string) =>
|
|
['worktrees', projectPath, featureId] as const,
|
|
/** Branches for a worktree */
|
|
branches: (worktreePath: string, includeRemote = false) =>
|
|
['worktrees', 'branches', worktreePath, { includeRemote }] as const,
|
|
/** Worktree status */
|
|
status: (projectPath: string, featureId: string) =>
|
|
['worktrees', projectPath, featureId, 'status'] as const,
|
|
/** Worktree diffs */
|
|
diffs: (projectPath: string, featureId: string) =>
|
|
['worktrees', projectPath, featureId, 'diffs'] as const,
|
|
/** Init script for a project */
|
|
initScript: (projectPath: string) => ['worktrees', projectPath, 'init-script'] as const,
|
|
/** Available editors */
|
|
editors: () => ['worktrees', 'editors'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// GitHub
|
|
// ============================================
|
|
github: {
|
|
/** GitHub issues for a project */
|
|
issues: (projectPath: string) => ['github', 'issues', projectPath] as const,
|
|
/** GitHub PRs for a project */
|
|
prs: (projectPath: string) => ['github', 'prs', projectPath] as const,
|
|
/** GitHub validations for a project */
|
|
validations: (projectPath: string) => ['github', 'validations', projectPath] as const,
|
|
/** Single validation */
|
|
validation: (projectPath: string, issueNumber: number) =>
|
|
['github', 'validations', projectPath, issueNumber] as const,
|
|
/** Issue comments */
|
|
issueComments: (projectPath: string, issueNumber: number) =>
|
|
['github', 'issues', projectPath, issueNumber, 'comments'] as const,
|
|
/** Remote info */
|
|
remote: (projectPath: string) => ['github', 'remote', projectPath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Settings
|
|
// ============================================
|
|
settings: {
|
|
/** Global settings */
|
|
global: () => ['settings', 'global'] as const,
|
|
/** Project-specific settings */
|
|
project: (projectPath: string) => ['settings', 'project', projectPath] as const,
|
|
/** Settings status */
|
|
status: () => ['settings', 'status'] as const,
|
|
/** Credentials (API keys) */
|
|
credentials: () => ['settings', 'credentials'] as const,
|
|
/** Discovered agents */
|
|
agents: (projectPath: string, sources?: Array<'user' | 'project'>) =>
|
|
['settings', 'agents', projectPath, sources ?? []] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Usage & Billing
|
|
// ============================================
|
|
usage: {
|
|
/** Claude API usage */
|
|
claude: () => ['usage', 'claude'] as const,
|
|
/** Codex API usage */
|
|
codex: () => ['usage', 'codex'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Models
|
|
// ============================================
|
|
models: {
|
|
/** Available models */
|
|
available: () => ['models', 'available'] as const,
|
|
/** Codex models */
|
|
codex: () => ['models', 'codex'] as const,
|
|
/** OpenCode models */
|
|
opencode: () => ['models', 'opencode'] as const,
|
|
/** OpenCode providers */
|
|
opencodeProviders: () => ['models', 'opencode', 'providers'] as const,
|
|
/** Provider status */
|
|
providers: () => ['models', 'providers'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Sessions
|
|
// ============================================
|
|
sessions: {
|
|
/** All sessions */
|
|
all: (includeArchived?: boolean) => ['sessions', { includeArchived }] as const,
|
|
/** Session history */
|
|
history: (sessionId: string) => ['sessions', sessionId, 'history'] as const,
|
|
/** Session queue */
|
|
queue: (sessionId: string) => ['sessions', sessionId, 'queue'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Running Agents
|
|
// ============================================
|
|
runningAgents: {
|
|
/** All running agents */
|
|
all: () => ['runningAgents'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Auto Mode
|
|
// ============================================
|
|
autoMode: {
|
|
/** Auto mode status */
|
|
status: (projectPath?: string) => ['autoMode', 'status', projectPath] as const,
|
|
/** Context exists check */
|
|
contextExists: (projectPath: string, featureId: string) =>
|
|
['autoMode', projectPath, featureId, 'context'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Ideation
|
|
// ============================================
|
|
ideation: {
|
|
/** Ideation prompts */
|
|
prompts: () => ['ideation', 'prompts'] as const,
|
|
/** Ideas for a project */
|
|
ideas: (projectPath: string) => ['ideation', 'ideas', projectPath] as const,
|
|
/** Single idea */
|
|
idea: (projectPath: string, ideaId: string) =>
|
|
['ideation', 'ideas', projectPath, ideaId] as const,
|
|
/** Session */
|
|
session: (projectPath: string, sessionId: string) =>
|
|
['ideation', 'session', projectPath, sessionId] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// CLI Status
|
|
// ============================================
|
|
cli: {
|
|
/** Claude CLI status */
|
|
claude: () => ['cli', 'claude'] as const,
|
|
/** Cursor CLI status */
|
|
cursor: () => ['cli', 'cursor'] as const,
|
|
/** Codex CLI status */
|
|
codex: () => ['cli', 'codex'] as const,
|
|
/** OpenCode CLI status */
|
|
opencode: () => ['cli', 'opencode'] as const,
|
|
/** Gemini CLI status */
|
|
gemini: () => ['cli', 'gemini'] as const,
|
|
/** Copilot SDK status */
|
|
copilot: () => ['cli', 'copilot'] as const,
|
|
/** GitHub CLI status */
|
|
github: () => ['cli', 'github'] as const,
|
|
/** API keys status */
|
|
apiKeys: () => ['cli', 'apiKeys'] as const,
|
|
/** Platform info */
|
|
platform: () => ['cli', 'platform'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Cursor Permissions
|
|
// ============================================
|
|
cursorPermissions: {
|
|
/** Cursor permissions for a project */
|
|
permissions: (projectPath?: string) => ['cursorPermissions', projectPath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Workspace
|
|
// ============================================
|
|
workspace: {
|
|
/** Workspace config */
|
|
config: () => ['workspace', 'config'] as const,
|
|
/** Workspace directories */
|
|
directories: () => ['workspace', 'directories'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// MCP (Model Context Protocol)
|
|
// ============================================
|
|
mcp: {
|
|
/** MCP server tools */
|
|
tools: (serverId: string) => ['mcp', 'tools', serverId] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Pipeline
|
|
// ============================================
|
|
pipeline: {
|
|
/** Pipeline config for a project */
|
|
config: (projectPath: string) => ['pipeline', projectPath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Suggestions
|
|
// ============================================
|
|
suggestions: {
|
|
/** Suggestions status */
|
|
status: () => ['suggestions', 'status'] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Spec Regeneration
|
|
// ============================================
|
|
specRegeneration: {
|
|
/** Spec regeneration status */
|
|
status: (projectPath?: string) => ['specRegeneration', 'status', projectPath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Spec
|
|
// ============================================
|
|
spec: {
|
|
/** Spec file content */
|
|
file: (projectPath: string) => ['spec', 'file', projectPath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Context
|
|
// ============================================
|
|
context: {
|
|
/** File description */
|
|
file: (filePath: string) => ['context', 'file', filePath] as const,
|
|
/** Image description */
|
|
image: (imagePath: string) => ['context', 'image', imagePath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// File System
|
|
// ============================================
|
|
fs: {
|
|
/** Directory listing */
|
|
readdir: (dirPath: string) => ['fs', 'readdir', dirPath] as const,
|
|
/** File existence */
|
|
exists: (filePath: string) => ['fs', 'exists', filePath] as const,
|
|
/** File stats */
|
|
stat: (filePath: string) => ['fs', 'stat', filePath] as const,
|
|
},
|
|
|
|
// ============================================
|
|
// Git
|
|
// ============================================
|
|
git: {
|
|
/** Git diffs for a project */
|
|
diffs: (projectPath: string) => ['git', 'diffs', projectPath] as const,
|
|
/** File diff */
|
|
fileDiff: (projectPath: string, filePath: string) =>
|
|
['git', 'diffs', projectPath, filePath] as const,
|
|
},
|
|
} as const;
|
|
|
|
/**
|
|
* Type helper to extract query key types
|
|
*/
|
|
export type QueryKeys = typeof queryKeys;
|