mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
Merge origin/main into feat/cursor-cli
Merges latest main branch changes including: - MCP server support and configuration - Pipeline configuration system - Prompt customization settings - GitHub issue comments in validation - Auth middleware improvements - Various UI/UX improvements All Cursor CLI features preserved: - Multi-provider support (Claude + Cursor) - Model override capabilities - Phase model configuration - Provider tabs in settings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
437
libs/prompts/src/defaults.ts
Normal file
437
libs/prompts/src/defaults.ts
Normal file
@@ -0,0 +1,437 @@
|
||||
/**
|
||||
* Default Prompts Library
|
||||
*
|
||||
* Central repository for all default AI prompts used throughout the application.
|
||||
* These prompts can be overridden by user customization in settings.
|
||||
*
|
||||
* Extracted from:
|
||||
* - apps/server/src/services/auto-mode-service.ts (Auto Mode planning prompts)
|
||||
* - apps/server/src/services/agent-service.ts (Agent Runner system prompt)
|
||||
* - apps/server/src/routes/backlog-plan/generate-plan.ts (Backlog planning prompts)
|
||||
*/
|
||||
|
||||
import type {
|
||||
ResolvedAutoModePrompts,
|
||||
ResolvedAgentPrompts,
|
||||
ResolvedBacklogPlanPrompts,
|
||||
ResolvedEnhancementPrompts,
|
||||
} from '@automaker/types';
|
||||
|
||||
/**
|
||||
* ========================================================================
|
||||
* AUTO MODE PROMPTS
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
export const DEFAULT_AUTO_MODE_PLANNING_LITE = `## Planning Phase (Lite Mode)
|
||||
|
||||
IMPORTANT: Do NOT output exploration text, tool usage, or thinking before the plan. Start DIRECTLY with the planning outline format below. Silently analyze the codebase first, then output ONLY the structured plan.
|
||||
|
||||
Create a brief planning outline:
|
||||
|
||||
1. **Goal**: What are we accomplishing? (1 sentence)
|
||||
2. **Approach**: How will we do it? (2-3 sentences)
|
||||
3. **Files to Touch**: List files and what changes
|
||||
4. **Tasks**: Numbered task list (3-7 items)
|
||||
5. **Risks**: Any gotchas to watch for
|
||||
|
||||
After generating the outline, output:
|
||||
"[PLAN_GENERATED] Planning outline complete."
|
||||
|
||||
Then proceed with implementation.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_PLANNING_LITE_WITH_APPROVAL = `## Planning Phase (Lite Mode)
|
||||
|
||||
IMPORTANT: Do NOT output exploration text, tool usage, or thinking before the plan. Start DIRECTLY with the planning outline format below. Silently analyze the codebase first, then output ONLY the structured plan.
|
||||
|
||||
Create a brief planning outline:
|
||||
|
||||
1. **Goal**: What are we accomplishing? (1 sentence)
|
||||
2. **Approach**: How will we do it? (2-3 sentences)
|
||||
3. **Files to Touch**: List files and what changes
|
||||
4. **Tasks**: Numbered task list (3-7 items)
|
||||
5. **Risks**: Any gotchas to watch for
|
||||
|
||||
After generating the outline, output:
|
||||
"[SPEC_GENERATED] Please review the planning outline above. Reply with 'approved' to proceed or provide feedback for revisions."
|
||||
|
||||
DO NOT proceed with implementation until you receive explicit approval.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_PLANNING_SPEC = `## Specification Phase (Spec Mode)
|
||||
|
||||
IMPORTANT: Do NOT output exploration text, tool usage, or thinking before the spec. Start DIRECTLY with the specification format below. Silently analyze the codebase first, then output ONLY the structured specification.
|
||||
|
||||
Generate a specification with an actionable task breakdown. WAIT for approval before implementing.
|
||||
|
||||
### Specification Format
|
||||
|
||||
1. **Problem**: What problem are we solving? (user perspective)
|
||||
|
||||
2. **Solution**: Brief approach (1-2 sentences)
|
||||
|
||||
3. **Acceptance Criteria**: 3-5 items in GIVEN-WHEN-THEN format
|
||||
- GIVEN [context], WHEN [action], THEN [outcome]
|
||||
|
||||
4. **Files to Modify**:
|
||||
| File | Purpose | Action |
|
||||
|------|---------|--------|
|
||||
| path/to/file | description | create/modify/delete |
|
||||
|
||||
5. **Implementation Tasks**:
|
||||
Use this EXACT format for each task (the system will parse these):
|
||||
\`\`\`tasks
|
||||
- [ ] T001: [Description] | File: [path/to/file]
|
||||
- [ ] T002: [Description] | File: [path/to/file]
|
||||
- [ ] T003: [Description] | File: [path/to/file]
|
||||
\`\`\`
|
||||
|
||||
Task ID rules:
|
||||
- Sequential: T001, T002, T003, etc.
|
||||
- Description: Clear action (e.g., "Create user model", "Add API endpoint")
|
||||
- File: Primary file affected (helps with context)
|
||||
- Order by dependencies (foundational tasks first)
|
||||
|
||||
6. **Verification**: How to confirm feature works
|
||||
|
||||
After generating the spec, output on its own line:
|
||||
"[SPEC_GENERATED] Please review the specification above. Reply with 'approved' to proceed or provide feedback for revisions."
|
||||
|
||||
DO NOT proceed with implementation until you receive explicit approval.
|
||||
|
||||
When approved, execute tasks SEQUENTIALLY in order. For each task:
|
||||
1. BEFORE starting, output: "[TASK_START] T###: Description"
|
||||
2. Implement the task
|
||||
3. AFTER completing, output: "[TASK_COMPLETE] T###: Brief summary"
|
||||
|
||||
This allows real-time progress tracking during implementation.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_PLANNING_FULL = `## Full Specification Phase (Full SDD Mode)
|
||||
|
||||
IMPORTANT: Do NOT output exploration text, tool usage, or thinking before the spec. Start DIRECTLY with the specification format below. Silently analyze the codebase first, then output ONLY the structured specification.
|
||||
|
||||
Generate a comprehensive specification with phased task breakdown. WAIT for approval before implementing.
|
||||
|
||||
### Specification Format
|
||||
|
||||
1. **Problem Statement**: 2-3 sentences from user perspective
|
||||
|
||||
2. **User Story**: As a [user], I want [goal], so that [benefit]
|
||||
|
||||
3. **Acceptance Criteria**: Multiple scenarios with GIVEN-WHEN-THEN
|
||||
- **Happy Path**: GIVEN [context], WHEN [action], THEN [expected outcome]
|
||||
- **Edge Cases**: GIVEN [edge condition], WHEN [action], THEN [handling]
|
||||
- **Error Handling**: GIVEN [error condition], WHEN [action], THEN [error response]
|
||||
|
||||
4. **Technical Context**:
|
||||
| Aspect | Value |
|
||||
|--------|-------|
|
||||
| Affected Files | list of files |
|
||||
| Dependencies | external libs if any |
|
||||
| Constraints | technical limitations |
|
||||
| Patterns to Follow | existing patterns in codebase |
|
||||
|
||||
5. **Non-Goals**: What this feature explicitly does NOT include
|
||||
|
||||
6. **Implementation Tasks**:
|
||||
Use this EXACT format for each task (the system will parse these):
|
||||
\`\`\`tasks
|
||||
## Phase 1: Foundation
|
||||
- [ ] T001: [Description] | File: [path/to/file]
|
||||
- [ ] T002: [Description] | File: [path/to/file]
|
||||
|
||||
## Phase 2: Core Implementation
|
||||
- [ ] T003: [Description] | File: [path/to/file]
|
||||
- [ ] T004: [Description] | File: [path/to/file]
|
||||
|
||||
## Phase 3: Integration & Testing
|
||||
- [ ] T005: [Description] | File: [path/to/file]
|
||||
- [ ] T006: [Description] | File: [path/to/file]
|
||||
\`\`\`
|
||||
|
||||
Task ID rules:
|
||||
- Sequential across all phases: T001, T002, T003, etc.
|
||||
- Description: Clear action verb + target
|
||||
- File: Primary file affected
|
||||
- Order by dependencies within each phase
|
||||
- Phase structure helps organize complex work
|
||||
|
||||
7. **Success Metrics**: How we know it's done (measurable criteria)
|
||||
|
||||
8. **Risks & Mitigations**:
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| description | approach |
|
||||
|
||||
After generating the spec, output on its own line:
|
||||
"[SPEC_GENERATED] Please review the comprehensive specification above. Reply with 'approved' to proceed or provide feedback for revisions."
|
||||
|
||||
DO NOT proceed with implementation until you receive explicit approval.
|
||||
|
||||
When approved, execute tasks SEQUENTIALLY by phase. For each task:
|
||||
1. BEFORE starting, output: "[TASK_START] T###: Description"
|
||||
2. Implement the task
|
||||
3. AFTER completing, output: "[TASK_COMPLETE] T###: Brief summary"
|
||||
|
||||
After completing all tasks in a phase, output:
|
||||
"[PHASE_COMPLETE] Phase N complete"
|
||||
|
||||
This allows real-time progress tracking during implementation.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_FEATURE_PROMPT_TEMPLATE = `## Feature Implementation Task
|
||||
|
||||
**Feature ID:** {{featureId}}
|
||||
**Title:** {{title}}
|
||||
**Description:** {{description}}
|
||||
|
||||
{{#if spec}}
|
||||
**Specification:**
|
||||
{{spec}}
|
||||
{{/if}}
|
||||
|
||||
{{#if imagePaths}}
|
||||
**Context Images:**
|
||||
{{#each imagePaths}}
|
||||
- {{this}}
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
|
||||
{{#if dependencies}}
|
||||
**Dependencies:**
|
||||
This feature depends on: {{dependencies}}
|
||||
{{/if}}
|
||||
|
||||
{{#if verificationInstructions}}
|
||||
**Verification:**
|
||||
{{verificationInstructions}}
|
||||
{{/if}}
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_FOLLOW_UP_PROMPT_TEMPLATE = `## Follow-up on Feature Implementation
|
||||
|
||||
{{featurePrompt}}
|
||||
|
||||
## Previous Agent Work
|
||||
{{previousContext}}
|
||||
|
||||
## Follow-up Instructions
|
||||
{{followUpInstructions}}
|
||||
|
||||
## Task
|
||||
Address the follow-up instructions above.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_CONTINUATION_PROMPT_TEMPLATE = `## Continuing Feature Implementation
|
||||
|
||||
{{featurePrompt}}
|
||||
|
||||
## Previous Context
|
||||
{{previousContext}}
|
||||
|
||||
## Instructions
|
||||
Review the previous work and continue the implementation.
|
||||
`;
|
||||
|
||||
export const DEFAULT_AUTO_MODE_PIPELINE_STEP_PROMPT_TEMPLATE = `## Pipeline Step: {{stepName}}
|
||||
|
||||
### Feature Context
|
||||
{{featurePrompt}}
|
||||
|
||||
### Previous Work
|
||||
{{previousContext}}
|
||||
|
||||
### Pipeline Step Instructions
|
||||
{{stepInstructions}}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Default Auto Mode prompts (from auto-mode-service.ts)
|
||||
*/
|
||||
export const DEFAULT_AUTO_MODE_PROMPTS: ResolvedAutoModePrompts = {
|
||||
planningLite: DEFAULT_AUTO_MODE_PLANNING_LITE,
|
||||
planningLiteWithApproval: DEFAULT_AUTO_MODE_PLANNING_LITE_WITH_APPROVAL,
|
||||
planningSpec: DEFAULT_AUTO_MODE_PLANNING_SPEC,
|
||||
planningFull: DEFAULT_AUTO_MODE_PLANNING_FULL,
|
||||
featurePromptTemplate: DEFAULT_AUTO_MODE_FEATURE_PROMPT_TEMPLATE,
|
||||
followUpPromptTemplate: DEFAULT_AUTO_MODE_FOLLOW_UP_PROMPT_TEMPLATE,
|
||||
continuationPromptTemplate: DEFAULT_AUTO_MODE_CONTINUATION_PROMPT_TEMPLATE,
|
||||
pipelineStepPromptTemplate: DEFAULT_AUTO_MODE_PIPELINE_STEP_PROMPT_TEMPLATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* ========================================================================
|
||||
* AGENT RUNNER PROMPTS
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
export const DEFAULT_AGENT_SYSTEM_PROMPT = `You are an AI assistant helping users build software. You are part of the Automaker application,
|
||||
which is designed to help developers plan, design, and implement software projects autonomously.
|
||||
|
||||
**Feature Storage:**
|
||||
Features are stored in .automaker/features/{id}/feature.json - each feature has its own folder.
|
||||
Use the UpdateFeatureStatus tool to manage features, not direct file edits.
|
||||
|
||||
Your role is to:
|
||||
- Help users define their project requirements and specifications
|
||||
- Ask clarifying questions to better understand their needs
|
||||
- Suggest technical approaches and architectures
|
||||
- Guide them through the development process
|
||||
- Be conversational and helpful
|
||||
- Write, edit, and modify code files as requested
|
||||
- Execute commands and tests
|
||||
- Search and analyze the codebase
|
||||
|
||||
**Tools Available:**
|
||||
You have access to several tools:
|
||||
- UpdateFeatureStatus: Update feature status (NOT file edits)
|
||||
- Read/Write/Edit: File operations
|
||||
- Bash: Execute commands
|
||||
- Glob/Grep: Search codebase
|
||||
- WebSearch/WebFetch: Research online
|
||||
|
||||
**Important Guidelines:**
|
||||
1. When users want to add or modify features, help them create clear feature definitions
|
||||
2. Use UpdateFeatureStatus tool to manage features in the backlog
|
||||
3. Be proactive in suggesting improvements and best practices
|
||||
4. Ask questions when requirements are unclear
|
||||
5. Guide users toward good software design principles
|
||||
|
||||
Remember: You're a collaborative partner in the development process. Be helpful, clear, and thorough.`;
|
||||
|
||||
/**
|
||||
* Default Agent Runner prompts (from agent-service.ts)
|
||||
*/
|
||||
export const DEFAULT_AGENT_PROMPTS: ResolvedAgentPrompts = {
|
||||
systemPrompt: DEFAULT_AGENT_SYSTEM_PROMPT,
|
||||
};
|
||||
|
||||
/**
|
||||
* ========================================================================
|
||||
* BACKLOG PLAN PROMPTS
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
export const DEFAULT_BACKLOG_PLAN_SYSTEM_PROMPT = `You are an AI assistant helping to modify a software project's feature backlog.
|
||||
You will be given the current list of features and a user request to modify the backlog.
|
||||
|
||||
IMPORTANT CONTEXT (automatically injected):
|
||||
- Remember to update the dependency graph if deleting existing features
|
||||
- Remember to define dependencies on new features hooked into relevant existing ones
|
||||
- Maintain dependency graph integrity (no orphaned dependencies)
|
||||
- When deleting a feature, identify which other features depend on it
|
||||
|
||||
Your task is to analyze the request and produce a structured JSON plan with:
|
||||
1. Features to ADD (include title, description, category, and dependencies)
|
||||
2. Features to UPDATE (specify featureId and the updates)
|
||||
3. Features to DELETE (specify featureId)
|
||||
4. A summary of the changes
|
||||
5. Any dependency updates needed (removed dependencies due to deletions, new dependencies for new features)
|
||||
|
||||
Respond with ONLY a JSON object in this exact format:
|
||||
\`\`\`json
|
||||
{
|
||||
"changes": [
|
||||
{
|
||||
"type": "add",
|
||||
"feature": {
|
||||
"title": "Feature title",
|
||||
"description": "Feature description",
|
||||
"category": "feature" | "bug" | "enhancement" | "refactor",
|
||||
"dependencies": ["existing-feature-id"],
|
||||
"priority": 1
|
||||
},
|
||||
"reason": "Why this feature should be added"
|
||||
},
|
||||
{
|
||||
"type": "update",
|
||||
"featureId": "existing-feature-id",
|
||||
"feature": {
|
||||
"title": "Updated title"
|
||||
},
|
||||
"reason": "Why this feature should be updated"
|
||||
},
|
||||
{
|
||||
"type": "delete",
|
||||
"featureId": "feature-id-to-delete",
|
||||
"reason": "Why this feature should be deleted"
|
||||
}
|
||||
],
|
||||
"summary": "Brief overview of all proposed changes",
|
||||
"dependencyUpdates": [
|
||||
{
|
||||
"featureId": "feature-that-depended-on-deleted",
|
||||
"removedDependencies": ["deleted-feature-id"],
|
||||
"addedDependencies": []
|
||||
}
|
||||
]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
Important rules:
|
||||
- Only include fields that need to change in updates
|
||||
- Ensure dependency references are valid (don't reference deleted features)
|
||||
- Provide clear, actionable descriptions
|
||||
- Maintain category consistency (feature, bug, enhancement, refactor)
|
||||
- When adding dependencies, ensure the referenced features exist or are being added in the same plan
|
||||
`;
|
||||
|
||||
export const DEFAULT_BACKLOG_PLAN_USER_PROMPT_TEMPLATE = `Current Features in Backlog:
|
||||
{{currentFeatures}}
|
||||
|
||||
---
|
||||
|
||||
User Request: {{userRequest}}
|
||||
|
||||
Please analyze the current backlog and the user's request, then provide a JSON plan for the modifications.`;
|
||||
|
||||
/**
|
||||
* Default Backlog Plan prompts (from backlog-plan/generate-plan.ts)
|
||||
*/
|
||||
export const DEFAULT_BACKLOG_PLAN_PROMPTS: ResolvedBacklogPlanPrompts = {
|
||||
systemPrompt: DEFAULT_BACKLOG_PLAN_SYSTEM_PROMPT,
|
||||
userPromptTemplate: DEFAULT_BACKLOG_PLAN_USER_PROMPT_TEMPLATE,
|
||||
};
|
||||
|
||||
/**
|
||||
* ========================================================================
|
||||
* ENHANCEMENT PROMPTS
|
||||
* ========================================================================
|
||||
* Note: Enhancement prompts are already defined in enhancement.ts
|
||||
* We import and re-export them here for consistency
|
||||
*/
|
||||
|
||||
import {
|
||||
IMPROVE_SYSTEM_PROMPT,
|
||||
TECHNICAL_SYSTEM_PROMPT,
|
||||
SIMPLIFY_SYSTEM_PROMPT,
|
||||
ACCEPTANCE_SYSTEM_PROMPT,
|
||||
} from './enhancement.js';
|
||||
|
||||
/**
|
||||
* Default Enhancement prompts (from libs/prompts/src/enhancement.ts)
|
||||
*/
|
||||
export const DEFAULT_ENHANCEMENT_PROMPTS: ResolvedEnhancementPrompts = {
|
||||
improveSystemPrompt: IMPROVE_SYSTEM_PROMPT,
|
||||
technicalSystemPrompt: TECHNICAL_SYSTEM_PROMPT,
|
||||
simplifySystemPrompt: SIMPLIFY_SYSTEM_PROMPT,
|
||||
acceptanceSystemPrompt: ACCEPTANCE_SYSTEM_PROMPT,
|
||||
};
|
||||
|
||||
/**
|
||||
* ========================================================================
|
||||
* COMBINED DEFAULTS
|
||||
* ========================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* All default prompts in one object for easy access
|
||||
*/
|
||||
export const DEFAULT_PROMPTS = {
|
||||
autoMode: DEFAULT_AUTO_MODE_PROMPTS,
|
||||
agent: DEFAULT_AGENT_PROMPTS,
|
||||
backlogPlan: DEFAULT_BACKLOG_PLAN_PROMPTS,
|
||||
enhancement: DEFAULT_ENHANCEMENT_PROMPTS,
|
||||
} as const;
|
||||
@@ -23,3 +23,40 @@ export {
|
||||
|
||||
// Re-export types from @automaker/types
|
||||
export type { EnhancementMode, EnhancementExample } from '@automaker/types';
|
||||
|
||||
// Default prompts
|
||||
export {
|
||||
DEFAULT_AUTO_MODE_PLANNING_LITE,
|
||||
DEFAULT_AUTO_MODE_PLANNING_LITE_WITH_APPROVAL,
|
||||
DEFAULT_AUTO_MODE_PLANNING_SPEC,
|
||||
DEFAULT_AUTO_MODE_PLANNING_FULL,
|
||||
DEFAULT_AUTO_MODE_FEATURE_PROMPT_TEMPLATE,
|
||||
DEFAULT_AUTO_MODE_FOLLOW_UP_PROMPT_TEMPLATE,
|
||||
DEFAULT_AUTO_MODE_CONTINUATION_PROMPT_TEMPLATE,
|
||||
DEFAULT_AUTO_MODE_PIPELINE_STEP_PROMPT_TEMPLATE,
|
||||
DEFAULT_AUTO_MODE_PROMPTS,
|
||||
DEFAULT_AGENT_SYSTEM_PROMPT,
|
||||
DEFAULT_AGENT_PROMPTS,
|
||||
DEFAULT_BACKLOG_PLAN_SYSTEM_PROMPT,
|
||||
DEFAULT_BACKLOG_PLAN_USER_PROMPT_TEMPLATE,
|
||||
DEFAULT_BACKLOG_PLAN_PROMPTS,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS,
|
||||
DEFAULT_PROMPTS,
|
||||
} from './defaults.js';
|
||||
|
||||
// Prompt merging utilities
|
||||
export {
|
||||
mergeAutoModePrompts,
|
||||
mergeAgentPrompts,
|
||||
mergeBacklogPlanPrompts,
|
||||
mergeEnhancementPrompts,
|
||||
mergeAllPrompts,
|
||||
} from './merge.js';
|
||||
|
||||
// Re-export resolved prompt types from @automaker/types
|
||||
export type {
|
||||
ResolvedAutoModePrompts,
|
||||
ResolvedAgentPrompts,
|
||||
ResolvedBacklogPlanPrompts,
|
||||
ResolvedEnhancementPrompts,
|
||||
} from '@automaker/types';
|
||||
|
||||
130
libs/prompts/src/merge.ts
Normal file
130
libs/prompts/src/merge.ts
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Prompt Merging Utilities
|
||||
*
|
||||
* Merges user-customized prompts with built-in defaults.
|
||||
* Used by services to get effective prompts at runtime.
|
||||
*
|
||||
* Custom prompts have an `enabled` flag - when true, the custom value is used.
|
||||
* When false or undefined, the default is used instead.
|
||||
*/
|
||||
|
||||
import type {
|
||||
PromptCustomization,
|
||||
AutoModePrompts,
|
||||
AgentPrompts,
|
||||
BacklogPlanPrompts,
|
||||
EnhancementPrompts,
|
||||
CustomPrompt,
|
||||
ResolvedAutoModePrompts,
|
||||
ResolvedAgentPrompts,
|
||||
ResolvedBacklogPlanPrompts,
|
||||
ResolvedEnhancementPrompts,
|
||||
} from '@automaker/types';
|
||||
import {
|
||||
DEFAULT_AUTO_MODE_PROMPTS,
|
||||
DEFAULT_AGENT_PROMPTS,
|
||||
DEFAULT_BACKLOG_PLAN_PROMPTS,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS,
|
||||
} from './defaults.js';
|
||||
|
||||
/**
|
||||
* Resolve a custom prompt to its effective string value
|
||||
* Returns the custom value if enabled=true, otherwise returns the default
|
||||
*/
|
||||
function resolvePrompt(custom: CustomPrompt | undefined, defaultValue: string): string {
|
||||
return custom?.enabled ? custom.value : defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge custom Auto Mode prompts with defaults
|
||||
* Custom prompts override defaults only when enabled=true
|
||||
*/
|
||||
export function mergeAutoModePrompts(custom?: AutoModePrompts): ResolvedAutoModePrompts {
|
||||
return {
|
||||
planningLite: resolvePrompt(custom?.planningLite, DEFAULT_AUTO_MODE_PROMPTS.planningLite),
|
||||
planningLiteWithApproval: resolvePrompt(
|
||||
custom?.planningLiteWithApproval,
|
||||
DEFAULT_AUTO_MODE_PROMPTS.planningLiteWithApproval
|
||||
),
|
||||
planningSpec: resolvePrompt(custom?.planningSpec, DEFAULT_AUTO_MODE_PROMPTS.planningSpec),
|
||||
planningFull: resolvePrompt(custom?.planningFull, DEFAULT_AUTO_MODE_PROMPTS.planningFull),
|
||||
featurePromptTemplate: resolvePrompt(
|
||||
custom?.featurePromptTemplate,
|
||||
DEFAULT_AUTO_MODE_PROMPTS.featurePromptTemplate
|
||||
),
|
||||
followUpPromptTemplate: resolvePrompt(
|
||||
custom?.followUpPromptTemplate,
|
||||
DEFAULT_AUTO_MODE_PROMPTS.followUpPromptTemplate
|
||||
),
|
||||
continuationPromptTemplate: resolvePrompt(
|
||||
custom?.continuationPromptTemplate,
|
||||
DEFAULT_AUTO_MODE_PROMPTS.continuationPromptTemplate
|
||||
),
|
||||
pipelineStepPromptTemplate: resolvePrompt(
|
||||
custom?.pipelineStepPromptTemplate,
|
||||
DEFAULT_AUTO_MODE_PROMPTS.pipelineStepPromptTemplate
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge custom Agent prompts with defaults
|
||||
* Custom prompts override defaults only when enabled=true
|
||||
*/
|
||||
export function mergeAgentPrompts(custom?: AgentPrompts): ResolvedAgentPrompts {
|
||||
return {
|
||||
systemPrompt: resolvePrompt(custom?.systemPrompt, DEFAULT_AGENT_PROMPTS.systemPrompt),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge custom Backlog Plan prompts with defaults
|
||||
* Custom prompts override defaults only when enabled=true
|
||||
*/
|
||||
export function mergeBacklogPlanPrompts(custom?: BacklogPlanPrompts): ResolvedBacklogPlanPrompts {
|
||||
return {
|
||||
systemPrompt: resolvePrompt(custom?.systemPrompt, DEFAULT_BACKLOG_PLAN_PROMPTS.systemPrompt),
|
||||
userPromptTemplate: resolvePrompt(
|
||||
custom?.userPromptTemplate,
|
||||
DEFAULT_BACKLOG_PLAN_PROMPTS.userPromptTemplate
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge custom Enhancement prompts with defaults
|
||||
* Custom prompts override defaults only when enabled=true
|
||||
*/
|
||||
export function mergeEnhancementPrompts(custom?: EnhancementPrompts): ResolvedEnhancementPrompts {
|
||||
return {
|
||||
improveSystemPrompt: resolvePrompt(
|
||||
custom?.improveSystemPrompt,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS.improveSystemPrompt
|
||||
),
|
||||
technicalSystemPrompt: resolvePrompt(
|
||||
custom?.technicalSystemPrompt,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS.technicalSystemPrompt
|
||||
),
|
||||
simplifySystemPrompt: resolvePrompt(
|
||||
custom?.simplifySystemPrompt,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS.simplifySystemPrompt
|
||||
),
|
||||
acceptanceSystemPrompt: resolvePrompt(
|
||||
custom?.acceptanceSystemPrompt,
|
||||
DEFAULT_ENHANCEMENT_PROMPTS.acceptanceSystemPrompt
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge all custom prompts with defaults
|
||||
* Returns a complete PromptCustomization with all fields populated
|
||||
*/
|
||||
export function mergeAllPrompts(custom?: PromptCustomization) {
|
||||
return {
|
||||
autoMode: mergeAutoModePrompts(custom?.autoMode),
|
||||
agent: mergeAgentPrompts(custom?.agent),
|
||||
backlogPlan: mergeBacklogPlanPrompts(custom?.backlogPlan),
|
||||
enhancement: mergeEnhancementPrompts(custom?.enhancement),
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
/**
|
||||
* Error type classification
|
||||
*/
|
||||
export type ErrorType = 'authentication' | 'cancellation' | 'abort' | 'execution' | 'unknown';
|
||||
export type ErrorType =
|
||||
| 'authentication'
|
||||
| 'cancellation'
|
||||
| 'abort'
|
||||
| 'execution'
|
||||
| 'rate_limit'
|
||||
| 'unknown';
|
||||
|
||||
/**
|
||||
* Classified error information
|
||||
@@ -12,5 +18,7 @@ export interface ErrorInfo {
|
||||
isAbort: boolean;
|
||||
isAuth: boolean;
|
||||
isCancellation: boolean;
|
||||
isRateLimit: boolean;
|
||||
retryAfter?: number; // Seconds to wait before retrying (for rate limit errors)
|
||||
originalError: unknown;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ export type {
|
||||
InstallationStatus,
|
||||
ValidationResult,
|
||||
ModelDefinition,
|
||||
McpServerConfig,
|
||||
McpStdioServerConfig,
|
||||
McpSSEServerConfig,
|
||||
McpHttpServerConfig,
|
||||
} from './provider.js';
|
||||
|
||||
// Feature types
|
||||
@@ -45,6 +49,21 @@ export { specOutputSchema } from './spec.js';
|
||||
// Enhancement types
|
||||
export type { EnhancementMode, EnhancementExample } from './enhancement.js';
|
||||
|
||||
// Prompt customization types
|
||||
export type {
|
||||
CustomPrompt,
|
||||
AutoModePrompts,
|
||||
AgentPrompts,
|
||||
BacklogPlanPrompts,
|
||||
EnhancementPrompts,
|
||||
PromptCustomization,
|
||||
ResolvedAutoModePrompts,
|
||||
ResolvedAgentPrompts,
|
||||
ResolvedBacklogPlanPrompts,
|
||||
ResolvedEnhancementPrompts,
|
||||
} from './prompts.js';
|
||||
export { DEFAULT_PROMPT_CUSTOMIZATION } from './prompts.js';
|
||||
|
||||
// Settings types and constants
|
||||
export type {
|
||||
ThemeMode,
|
||||
@@ -56,6 +75,8 @@ export type {
|
||||
PhaseModelKey,
|
||||
KeyboardShortcuts,
|
||||
AIProfile,
|
||||
MCPToolInfo,
|
||||
MCPServerConfig,
|
||||
ProjectRef,
|
||||
TrashedProjectRef,
|
||||
ChatSessionRef,
|
||||
@@ -92,6 +113,9 @@ export type {
|
||||
IssueValidationVerdict,
|
||||
IssueValidationConfidence,
|
||||
IssueComplexity,
|
||||
PRRecommendation,
|
||||
PRAnalysis,
|
||||
LinkedPRInfo,
|
||||
IssueValidationInput,
|
||||
IssueValidationRequest,
|
||||
IssueValidationResult,
|
||||
@@ -99,6 +123,9 @@ export type {
|
||||
IssueValidationErrorResponse,
|
||||
IssueValidationEvent,
|
||||
StoredValidation,
|
||||
GitHubCommentAuthor,
|
||||
GitHubComment,
|
||||
IssueCommentsResult,
|
||||
} from './issue-validation.js';
|
||||
|
||||
// Backlog plan types
|
||||
@@ -126,3 +153,11 @@ export {
|
||||
getBareModelId,
|
||||
normalizeModelString,
|
||||
} from './provider-utils.js';
|
||||
|
||||
// Pipeline types
|
||||
export type {
|
||||
PipelineStep,
|
||||
PipelineConfig,
|
||||
PipelineStatus,
|
||||
FeatureStatusWithPipeline,
|
||||
} from './pipeline.js';
|
||||
|
||||
@@ -21,6 +21,36 @@ export type IssueValidationConfidence = 'high' | 'medium' | 'low';
|
||||
*/
|
||||
export type IssueComplexity = 'trivial' | 'simple' | 'moderate' | 'complex' | 'very_complex';
|
||||
|
||||
/**
|
||||
* Recommendation for PR-related action
|
||||
*/
|
||||
export type PRRecommendation = 'wait_for_merge' | 'pr_needs_work' | 'no_pr';
|
||||
|
||||
/**
|
||||
* Analysis of a linked pull request
|
||||
*/
|
||||
export interface PRAnalysis {
|
||||
/** Whether there is an open PR linked to this issue */
|
||||
hasOpenPR: boolean;
|
||||
/** Whether the PR appears to fix the issue based on the diff */
|
||||
prFixesIssue?: boolean;
|
||||
/** The PR number that was analyzed */
|
||||
prNumber?: number;
|
||||
/** Brief summary of what the PR changes */
|
||||
prSummary?: string;
|
||||
/** Recommendation: wait for PR to merge, PR needs more work, or no relevant PR */
|
||||
recommendation: PRRecommendation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Linked PR info for validation
|
||||
*/
|
||||
export interface LinkedPRInfo {
|
||||
number: number;
|
||||
title: string;
|
||||
state: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue data for validation (without projectPath)
|
||||
* Used by UI when calling the validation API
|
||||
@@ -30,6 +60,10 @@ export interface IssueValidationInput {
|
||||
issueTitle: string;
|
||||
issueBody: string;
|
||||
issueLabels?: string[];
|
||||
/** Comments to include in validation analysis */
|
||||
comments?: GitHubComment[];
|
||||
/** Linked pull requests for this issue */
|
||||
linkedPRs?: LinkedPRInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,6 +94,8 @@ export interface IssueValidationResult {
|
||||
missingInfo?: string[];
|
||||
/** Estimated effort to address the issue */
|
||||
estimatedComplexity?: IssueComplexity;
|
||||
/** Analysis of linked pull requests (if any) */
|
||||
prAnalysis?: PRAnalysis;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,3 +169,41 @@ export interface StoredValidation {
|
||||
/** ISO timestamp when user viewed this validation (undefined = not yet viewed) */
|
||||
viewedAt?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Author of a GitHub comment
|
||||
*/
|
||||
export interface GitHubCommentAuthor {
|
||||
login: string;
|
||||
avatarUrl?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A comment on a GitHub issue
|
||||
*/
|
||||
export interface GitHubComment {
|
||||
/** Unique comment ID */
|
||||
id: string;
|
||||
/** Author of the comment */
|
||||
author: GitHubCommentAuthor;
|
||||
/** Comment body (markdown) */
|
||||
body: string;
|
||||
/** ISO timestamp when comment was created */
|
||||
createdAt: string;
|
||||
/** ISO timestamp when comment was last updated */
|
||||
updatedAt?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result from fetching issue comments
|
||||
*/
|
||||
export interface IssueCommentsResult {
|
||||
/** List of comments */
|
||||
comments: GitHubComment[];
|
||||
/** Total number of comments on the issue */
|
||||
totalCount: number;
|
||||
/** Whether there are more comments to fetch */
|
||||
hasNextPage: boolean;
|
||||
/** Cursor for pagination (pass to next request) */
|
||||
endCursor?: string;
|
||||
}
|
||||
|
||||
28
libs/types/src/pipeline.ts
Normal file
28
libs/types/src/pipeline.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Pipeline types for AutoMaker custom workflow steps
|
||||
*/
|
||||
|
||||
export interface PipelineStep {
|
||||
id: string;
|
||||
name: string;
|
||||
order: number;
|
||||
instructions: string;
|
||||
colorClass: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface PipelineConfig {
|
||||
version: 1;
|
||||
steps: PipelineStep[];
|
||||
}
|
||||
|
||||
export type PipelineStatus = `pipeline_${string}`;
|
||||
|
||||
export type FeatureStatusWithPipeline =
|
||||
| 'backlog'
|
||||
| 'in_progress'
|
||||
| 'waiting_approval'
|
||||
| 'verified'
|
||||
| 'completed'
|
||||
| PipelineStatus;
|
||||
153
libs/types/src/prompts.ts
Normal file
153
libs/types/src/prompts.ts
Normal file
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* Prompt Customization Types
|
||||
*
|
||||
* Defines the structure for customizable AI prompts used throughout the application.
|
||||
* Allows users to modify prompts for Auto Mode, Agent Runner, and Backlog Planning.
|
||||
*/
|
||||
|
||||
/**
|
||||
* CustomPrompt - A custom prompt with its value and enabled state
|
||||
*
|
||||
* The value is always preserved even when disabled, so users don't lose their work.
|
||||
*/
|
||||
export interface CustomPrompt {
|
||||
/** The custom prompt text */
|
||||
value: string;
|
||||
|
||||
/** Whether this custom prompt should be used (when false, default is used instead) */
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* AutoModePrompts - Customizable prompts for Auto Mode feature implementation
|
||||
*
|
||||
* Controls how the AI plans and implements features in autonomous mode.
|
||||
*/
|
||||
export interface AutoModePrompts {
|
||||
/** Planning mode: Quick outline without approval (lite mode) */
|
||||
planningLite?: CustomPrompt;
|
||||
|
||||
/** Planning mode: Quick outline with approval required (lite with approval) */
|
||||
planningLiteWithApproval?: CustomPrompt;
|
||||
|
||||
/** Planning mode: Detailed specification with task breakdown (spec mode) */
|
||||
planningSpec?: CustomPrompt;
|
||||
|
||||
/** Planning mode: Comprehensive Software Design Document (full SDD mode) */
|
||||
planningFull?: CustomPrompt;
|
||||
|
||||
/** Template for building feature implementation prompts */
|
||||
featurePromptTemplate?: CustomPrompt;
|
||||
|
||||
/** Template for follow-up prompts when resuming work */
|
||||
followUpPromptTemplate?: CustomPrompt;
|
||||
|
||||
/** Template for continuation prompts */
|
||||
continuationPromptTemplate?: CustomPrompt;
|
||||
|
||||
/** Template for pipeline step execution prompts */
|
||||
pipelineStepPromptTemplate?: CustomPrompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* AgentPrompts - Customizable prompts for Agent Runner (chat mode)
|
||||
*
|
||||
* Controls the AI's behavior in interactive chat sessions.
|
||||
*/
|
||||
export interface AgentPrompts {
|
||||
/** System prompt defining the agent's role and behavior in chat */
|
||||
systemPrompt?: CustomPrompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* BacklogPlanPrompts - Customizable prompts for Kanban board planning
|
||||
*
|
||||
* Controls how the AI modifies the feature backlog via the Plan button.
|
||||
*/
|
||||
export interface BacklogPlanPrompts {
|
||||
/** System prompt for backlog plan generation (defines output format and rules) */
|
||||
systemPrompt?: CustomPrompt;
|
||||
|
||||
/** Template for user prompt (includes current features and user request) */
|
||||
userPromptTemplate?: CustomPrompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* EnhancementPrompts - Customizable prompts for feature description enhancement
|
||||
*
|
||||
* Controls how the AI enhances feature titles and descriptions.
|
||||
*/
|
||||
export interface EnhancementPrompts {
|
||||
/** System prompt for "improve" mode (vague → clear) */
|
||||
improveSystemPrompt?: CustomPrompt;
|
||||
|
||||
/** System prompt for "technical" mode (add technical details) */
|
||||
technicalSystemPrompt?: CustomPrompt;
|
||||
|
||||
/** System prompt for "simplify" mode (verbose → concise) */
|
||||
simplifySystemPrompt?: CustomPrompt;
|
||||
|
||||
/** System prompt for "acceptance" mode (add acceptance criteria) */
|
||||
acceptanceSystemPrompt?: CustomPrompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* PromptCustomization - Complete set of customizable prompts
|
||||
*
|
||||
* All fields are optional. Undefined values fall back to built-in defaults.
|
||||
* Stored in GlobalSettings to allow user customization.
|
||||
*/
|
||||
export interface PromptCustomization {
|
||||
/** Auto Mode prompts (feature implementation) */
|
||||
autoMode?: AutoModePrompts;
|
||||
|
||||
/** Agent Runner prompts (interactive chat) */
|
||||
agent?: AgentPrompts;
|
||||
|
||||
/** Backlog planning prompts (Plan button) */
|
||||
backlogPlan?: BacklogPlanPrompts;
|
||||
|
||||
/** Enhancement prompts (feature description improvement) */
|
||||
enhancement?: EnhancementPrompts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default empty prompt customization (all undefined → use built-in defaults)
|
||||
*/
|
||||
export const DEFAULT_PROMPT_CUSTOMIZATION: PromptCustomization = {
|
||||
autoMode: {},
|
||||
agent: {},
|
||||
backlogPlan: {},
|
||||
enhancement: {},
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolved prompt types - all fields are required strings (ready to use)
|
||||
* Used for default prompts and merged prompts after resolving custom values
|
||||
*/
|
||||
export interface ResolvedAutoModePrompts {
|
||||
planningLite: string;
|
||||
planningLiteWithApproval: string;
|
||||
planningSpec: string;
|
||||
planningFull: string;
|
||||
featurePromptTemplate: string;
|
||||
followUpPromptTemplate: string;
|
||||
continuationPromptTemplate: string;
|
||||
pipelineStepPromptTemplate: string;
|
||||
}
|
||||
|
||||
export interface ResolvedAgentPrompts {
|
||||
systemPrompt: string;
|
||||
}
|
||||
|
||||
export interface ResolvedBacklogPlanPrompts {
|
||||
systemPrompt: string;
|
||||
userPromptTemplate: string;
|
||||
}
|
||||
|
||||
export interface ResolvedEnhancementPrompts {
|
||||
improveSystemPrompt: string;
|
||||
technicalSystemPrompt: string;
|
||||
simplifySystemPrompt: string;
|
||||
acceptanceSystemPrompt: string;
|
||||
}
|
||||
@@ -28,6 +28,38 @@ export interface SystemPromptPreset {
|
||||
append?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MCP server configuration types for SDK options
|
||||
* Matches the Claude Agent SDK's McpServerConfig types
|
||||
*/
|
||||
export type McpServerConfig = McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig;
|
||||
|
||||
/**
|
||||
* Stdio-based MCP server (subprocess)
|
||||
* Note: `type` is optional and defaults to 'stdio' to match SDK behavior
|
||||
* and allow simpler configs like { command: "node", args: ["server.js"] }
|
||||
*/
|
||||
export interface McpStdioServerConfig {
|
||||
type?: 'stdio';
|
||||
command: string;
|
||||
args?: string[];
|
||||
env?: Record<string, string>;
|
||||
}
|
||||
|
||||
/** SSE-based MCP server */
|
||||
export interface McpSSEServerConfig {
|
||||
type: 'sse';
|
||||
url: string;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
/** HTTP-based MCP server */
|
||||
export interface McpHttpServerConfig {
|
||||
type: 'http';
|
||||
url: string;
|
||||
headers?: Record<string, string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for executing a query via a provider
|
||||
*/
|
||||
@@ -38,11 +70,20 @@ export interface ExecuteOptions {
|
||||
systemPrompt?: string | SystemPromptPreset;
|
||||
maxTurns?: number;
|
||||
allowedTools?: string[];
|
||||
mcpServers?: Record<string, unknown>;
|
||||
mcpServers?: Record<string, McpServerConfig>;
|
||||
mcpAutoApproveTools?: boolean; // Auto-approve MCP tool calls without permission prompts
|
||||
mcpUnrestrictedTools?: boolean; // Allow unrestricted tools when MCP servers are enabled
|
||||
abortController?: AbortController;
|
||||
conversationHistory?: ConversationMessage[]; // Previous messages for context
|
||||
sdkSessionId?: string; // Claude SDK session ID for resuming conversations
|
||||
settingSources?: Array<'user' | 'project' | 'local'>; // Sources for CLAUDE.md loading
|
||||
sandbox?: { enabled: boolean; autoAllowBashIfSandboxed?: boolean }; // Sandbox configuration
|
||||
/**
|
||||
* If true, the provider should run in read-only mode (no file modifications).
|
||||
* For Cursor CLI, this omits the --force flag, making it suggest-only.
|
||||
* Default: false (allows edits)
|
||||
*/
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import type { ModelAlias } from './model.js';
|
||||
import type { CursorModelId } from './cursor-models.js';
|
||||
import { CURSOR_MODEL_MAP, getAllCursorModelIds } from './cursor-models.js';
|
||||
import type { PromptCustomization } from './prompts.js';
|
||||
|
||||
// Re-export ModelAlias for convenience
|
||||
export type { ModelAlias };
|
||||
@@ -237,6 +238,55 @@ export function getProfileModelString(profile: AIProfile): string {
|
||||
return profile.model || 'sonnet';
|
||||
}
|
||||
|
||||
/**
|
||||
* MCPToolInfo - Information about a tool provided by an MCP server
|
||||
*
|
||||
* Contains the tool's name, description, and whether it's enabled for use.
|
||||
*/
|
||||
export interface MCPToolInfo {
|
||||
/** Tool name as exposed by the MCP server */
|
||||
name: string;
|
||||
/** Description of what the tool does */
|
||||
description?: string;
|
||||
/** JSON Schema for the tool's input parameters */
|
||||
inputSchema?: Record<string, unknown>;
|
||||
/** Whether this tool is enabled for use (defaults to true) */
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* MCPServerConfig - Configuration for an MCP (Model Context Protocol) server
|
||||
*
|
||||
* MCP servers provide additional tools and capabilities to AI agents.
|
||||
* Supports stdio (subprocess), SSE, and HTTP transport types.
|
||||
*/
|
||||
export interface MCPServerConfig {
|
||||
/** Unique identifier for the server config */
|
||||
id: string;
|
||||
/** Display name for the server */
|
||||
name: string;
|
||||
/** User-friendly description of what this server provides */
|
||||
description?: string;
|
||||
/** Transport type: stdio (default), sse, or http */
|
||||
type?: 'stdio' | 'sse' | 'http';
|
||||
/** For stdio: command to execute (e.g., 'node', 'python', 'npx') */
|
||||
command?: string;
|
||||
/** For stdio: arguments to pass to the command */
|
||||
args?: string[];
|
||||
/** For stdio: environment variables to set */
|
||||
env?: Record<string, string>;
|
||||
/** For sse/http: URL endpoint */
|
||||
url?: string;
|
||||
/** For sse/http: headers to include in requests */
|
||||
headers?: Record<string, string>;
|
||||
/** Whether this server is enabled */
|
||||
enabled?: boolean;
|
||||
/** Tools discovered from this server with their enabled states */
|
||||
tools?: MCPToolInfo[];
|
||||
/** Timestamp when tools were last fetched */
|
||||
toolsLastFetched?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* ProjectRef - Minimal reference to a project stored in global settings
|
||||
*
|
||||
@@ -385,6 +435,20 @@ export interface GlobalSettings {
|
||||
// Claude Agent SDK Settings
|
||||
/** Auto-load CLAUDE.md files using SDK's settingSources option */
|
||||
autoLoadClaudeMd?: boolean;
|
||||
/** Enable sandbox mode for bash commands (default: true, disable if issues occur) */
|
||||
enableSandboxMode?: boolean;
|
||||
|
||||
// MCP Server Configuration
|
||||
/** List of configured MCP servers for agent use */
|
||||
mcpServers: MCPServerConfig[];
|
||||
/** Auto-approve MCP tool calls without permission prompts (uses bypassPermissions mode) */
|
||||
mcpAutoApproveTools?: boolean;
|
||||
/** Allow unrestricted tools when MCP servers are enabled (don't filter allowedTools) */
|
||||
mcpUnrestrictedTools?: boolean;
|
||||
|
||||
// Prompt Customization
|
||||
/** Custom prompts for Auto Mode, Agent Runner, Backlog Planning, and Enhancements */
|
||||
promptCustomization?: PromptCustomization;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -563,6 +627,12 @@ export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = {
|
||||
worktreePanelCollapsed: false,
|
||||
lastSelectedSessionByProject: {},
|
||||
autoLoadClaudeMd: false,
|
||||
enableSandboxMode: true,
|
||||
mcpServers: [],
|
||||
// Default to true for autonomous workflow. Security is enforced when adding servers
|
||||
// via the security warning dialog that explains the risks.
|
||||
mcpAutoApproveTools: true,
|
||||
mcpUnrestrictedTools: true,
|
||||
};
|
||||
|
||||
/** Default credentials (empty strings - user must provide API keys) */
|
||||
|
||||
@@ -51,6 +51,41 @@ export function isAuthenticationError(errorMessage: string): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an error is a rate limit error
|
||||
*
|
||||
* @param error - The error to check
|
||||
* @returns True if the error is a rate limit error
|
||||
*/
|
||||
export function isRateLimitError(error: unknown): boolean {
|
||||
const message = error instanceof Error ? error.message : String(error || '');
|
||||
return message.includes('429') || message.includes('rate_limit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract retry-after duration from rate limit error
|
||||
*
|
||||
* @param error - The error to extract retry-after from
|
||||
* @returns Number of seconds to wait, or undefined if not found
|
||||
*/
|
||||
export function extractRetryAfter(error: unknown): number | undefined {
|
||||
const message = error instanceof Error ? error.message : String(error || '');
|
||||
|
||||
// Try to extract from Retry-After header format
|
||||
const retryMatch = message.match(/retry[_-]?after[:\s]+(\d+)/i);
|
||||
if (retryMatch) {
|
||||
return parseInt(retryMatch[1], 10);
|
||||
}
|
||||
|
||||
// Try to extract from error message patterns
|
||||
const waitMatch = message.match(/wait[:\s]+(\d+)\s*(?:second|sec|s)/i);
|
||||
if (waitMatch) {
|
||||
return parseInt(waitMatch[1], 10);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classify an error into a specific type
|
||||
*
|
||||
@@ -62,10 +97,14 @@ export function classifyError(error: unknown): ErrorInfo {
|
||||
const isAbort = isAbortError(error);
|
||||
const isAuth = isAuthenticationError(message);
|
||||
const isCancellation = isCancellationError(message);
|
||||
const isRateLimit = isRateLimitError(error);
|
||||
const retryAfter = isRateLimit ? (extractRetryAfter(error) ?? 60) : undefined;
|
||||
|
||||
let type: ErrorType;
|
||||
if (isAuth) {
|
||||
type = 'authentication';
|
||||
} else if (isRateLimit) {
|
||||
type = 'rate_limit';
|
||||
} else if (isAbort) {
|
||||
type = 'abort';
|
||||
} else if (isCancellation) {
|
||||
@@ -82,6 +121,8 @@ export function classifyError(error: unknown): ErrorInfo {
|
||||
isAbort,
|
||||
isAuth,
|
||||
isCancellation,
|
||||
isRateLimit,
|
||||
retryAfter,
|
||||
originalError: error,
|
||||
};
|
||||
}
|
||||
@@ -103,6 +144,13 @@ export function getUserFriendlyErrorMessage(error: unknown): string {
|
||||
return 'Authentication failed. Please check your API key.';
|
||||
}
|
||||
|
||||
if (info.isRateLimit) {
|
||||
const retryMsg = info.retryAfter
|
||||
? ` Please wait ${info.retryAfter} seconds before retrying.`
|
||||
: ' Please reduce concurrency or wait before retrying.';
|
||||
return `Rate limit exceeded (429).${retryMsg}`;
|
||||
}
|
||||
|
||||
return info.message;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ export {
|
||||
isAbortError,
|
||||
isCancellationError,
|
||||
isAuthenticationError,
|
||||
isRateLimitError,
|
||||
extractRetryAfter,
|
||||
classifyError,
|
||||
getUserFriendlyErrorMessage,
|
||||
getErrorMessage,
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
isAbortError,
|
||||
isCancellationError,
|
||||
isAuthenticationError,
|
||||
isRateLimitError,
|
||||
extractRetryAfter,
|
||||
classifyError,
|
||||
getUserFriendlyErrorMessage,
|
||||
} from '../src/error-handler';
|
||||
@@ -101,6 +103,63 @@ describe('error-handler.ts', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('isRateLimitError', () => {
|
||||
it('should return true for errors with 429 status code', () => {
|
||||
const error = new Error('Error: 429 Too Many Requests');
|
||||
expect(isRateLimitError(error)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for errors with rate_limit in message', () => {
|
||||
const error = new Error('rate_limit_error: Too many requests');
|
||||
expect(isRateLimitError(error)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true for string errors with 429', () => {
|
||||
expect(isRateLimitError('429 - rate limit exceeded')).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false for non-rate-limit errors', () => {
|
||||
const error = new Error('Something went wrong');
|
||||
expect(isRateLimitError(error)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false for null/undefined', () => {
|
||||
expect(isRateLimitError(null)).toBe(false);
|
||||
expect(isRateLimitError(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('extractRetryAfter', () => {
|
||||
it('should extract retry-after from error message', () => {
|
||||
const error = new Error('Rate limit exceeded. retry-after: 60');
|
||||
expect(extractRetryAfter(error)).toBe(60);
|
||||
});
|
||||
|
||||
it('should extract from retry_after format', () => {
|
||||
const error = new Error('retry_after: 120 seconds');
|
||||
expect(extractRetryAfter(error)).toBe(120);
|
||||
});
|
||||
|
||||
it('should extract from wait format', () => {
|
||||
const error = new Error('Please wait: 30 seconds before retrying');
|
||||
expect(extractRetryAfter(error)).toBe(30);
|
||||
});
|
||||
|
||||
it('should return undefined for rate limit errors without explicit retry-after', () => {
|
||||
const error = new Error('429 rate_limit_error');
|
||||
expect(extractRetryAfter(error)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return undefined for non-rate-limit errors', () => {
|
||||
const error = new Error('Something went wrong');
|
||||
expect(extractRetryAfter(error)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle string errors', () => {
|
||||
expect(extractRetryAfter('retry-after: 45')).toBe(45);
|
||||
});
|
||||
});
|
||||
|
||||
describe('classifyError', () => {
|
||||
it('should classify authentication errors', () => {
|
||||
const error = new Error('Authentication failed');
|
||||
@@ -110,10 +169,30 @@ describe('error-handler.ts', () => {
|
||||
expect(result.isAuth).toBe(true);
|
||||
expect(result.isAbort).toBe(false);
|
||||
expect(result.isCancellation).toBe(false);
|
||||
expect(result.isRateLimit).toBe(false);
|
||||
expect(result.message).toBe('Authentication failed');
|
||||
expect(result.originalError).toBe(error);
|
||||
});
|
||||
|
||||
it('should classify rate limit errors', () => {
|
||||
const error = new Error('Error: 429 rate_limit_error');
|
||||
const result = classifyError(error);
|
||||
|
||||
expect(result.type).toBe('rate_limit');
|
||||
expect(result.isRateLimit).toBe(true);
|
||||
expect(result.isAuth).toBe(false);
|
||||
expect(result.retryAfter).toBe(60); // Default
|
||||
});
|
||||
|
||||
it('should extract retryAfter from rate limit errors', () => {
|
||||
const error = new Error('429 - retry-after: 120');
|
||||
const result = classifyError(error);
|
||||
|
||||
expect(result.type).toBe('rate_limit');
|
||||
expect(result.isRateLimit).toBe(true);
|
||||
expect(result.retryAfter).toBe(120);
|
||||
});
|
||||
|
||||
it('should classify abort errors', () => {
|
||||
const error = new Error('aborted');
|
||||
const result = classifyError(error);
|
||||
@@ -169,6 +248,24 @@ describe('error-handler.ts', () => {
|
||||
expect(result2.message).toBe('Unknown error');
|
||||
});
|
||||
|
||||
it('should prioritize authentication over rate limit', () => {
|
||||
const error = new Error('Authentication failed - 429');
|
||||
const result = classifyError(error);
|
||||
|
||||
expect(result.type).toBe('authentication');
|
||||
expect(result.isAuth).toBe(true);
|
||||
expect(result.isRateLimit).toBe(true); // Both flags can be true
|
||||
});
|
||||
|
||||
it('should prioritize rate limit over abort', () => {
|
||||
const error = new Error('429 rate_limit - aborted');
|
||||
const result = classifyError(error);
|
||||
|
||||
expect(result.type).toBe('rate_limit');
|
||||
expect(result.isRateLimit).toBe(true);
|
||||
expect(result.isAbort).toBe(true);
|
||||
});
|
||||
|
||||
it('should prioritize authentication over abort', () => {
|
||||
const error = new Error('Authentication failed - aborted');
|
||||
const result = classifyError(error);
|
||||
@@ -223,6 +320,22 @@ describe('error-handler.ts', () => {
|
||||
expect(message).toBe('Authentication failed. Please check your API key.');
|
||||
});
|
||||
|
||||
it('should return friendly message for rate limit errors', () => {
|
||||
const error = new Error('429 rate_limit_error');
|
||||
const message = getUserFriendlyErrorMessage(error);
|
||||
|
||||
expect(message).toContain('Rate limit exceeded');
|
||||
expect(message).toContain('60 seconds');
|
||||
});
|
||||
|
||||
it('should include custom retry-after in rate limit message', () => {
|
||||
const error = new Error('429 - retry-after: 120');
|
||||
const message = getUserFriendlyErrorMessage(error);
|
||||
|
||||
expect(message).toContain('Rate limit exceeded');
|
||||
expect(message).toContain('120 seconds');
|
||||
});
|
||||
|
||||
it('should prioritize abort message over auth', () => {
|
||||
const error = new Error('Authentication failed - abort');
|
||||
const message = getUserFriendlyErrorMessage(error);
|
||||
|
||||
Reference in New Issue
Block a user