@polka-codes/cli 0.9.85 → 0.9.86
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -15
- package/dist/index.js +324 -1499
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -39615,8 +39615,18 @@ var init_dynamic_types = __esm(() => {
|
|
|
39615
39615
|
// ../core/src/workflow/dynamic.ts
|
|
39616
39616
|
function convertJsonSchemaToZod(schema) {
|
|
39617
39617
|
if (schema.enum) {
|
|
39618
|
-
const enumValues = schema.enum
|
|
39619
|
-
|
|
39618
|
+
const enumValues = schema.enum;
|
|
39619
|
+
if (enumValues.length === 0) {
|
|
39620
|
+
return exports_external.never();
|
|
39621
|
+
}
|
|
39622
|
+
if (enumValues.every((v) => typeof v === "string")) {
|
|
39623
|
+
return exports_external.enum(enumValues);
|
|
39624
|
+
}
|
|
39625
|
+
const literals = enumValues.map((v) => exports_external.literal(v));
|
|
39626
|
+
if (literals.length === 1) {
|
|
39627
|
+
return literals[0];
|
|
39628
|
+
}
|
|
39629
|
+
return exports_external.union([literals[0], literals[1], ...literals.slice(2)]);
|
|
39620
39630
|
}
|
|
39621
39631
|
if (Array.isArray(schema.type)) {
|
|
39622
39632
|
const types3 = schema.type;
|
|
@@ -39786,8 +39796,11 @@ ${errors4.map((e) => ` - ${e}`).join(`
|
|
|
39786
39796
|
}
|
|
39787
39797
|
return validatedInput;
|
|
39788
39798
|
}
|
|
39789
|
-
function evaluateCondition(condition, input, state, allowUnsafeCodeExecution = false) {
|
|
39799
|
+
function evaluateCondition(condition, input, state, allowUnsafeCodeExecution = false, logger) {
|
|
39790
39800
|
if (allowUnsafeCodeExecution) {
|
|
39801
|
+
if (logger) {
|
|
39802
|
+
logger.warn(`[SECURITY] Executing unsafe code evaluation for condition: ${condition}. This allows arbitrary JavaScript execution and should only be used for trusted workflows.`);
|
|
39803
|
+
}
|
|
39791
39804
|
const functionBody = `
|
|
39792
39805
|
try {
|
|
39793
39806
|
return ${condition};
|
|
@@ -73990,344 +74003,6 @@ ${createJsonResponseInstruction({
|
|
|
73990
74003
|
`;
|
|
73991
74004
|
});
|
|
73992
74005
|
|
|
73993
|
-
// src/workflows/prompts/epic.ts
|
|
73994
|
-
var EPIC_PLANNER_SYSTEM_PROMPT, BRANCH_NAME_PATTERN, EpicPlanSchema, EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT;
|
|
73995
|
-
var init_epic = __esm(() => {
|
|
73996
|
-
init_zod();
|
|
73997
|
-
EPIC_PLANNER_SYSTEM_PROMPT = `Role: Expert software architect and epic planner.
|
|
73998
|
-
Goal: Analyze a large and complex user request (an "epic") and create a detailed implementation plan with task breakdowns.
|
|
73999
|
-
|
|
74000
|
-
${MEMORY_USAGE_SECTION}
|
|
74001
|
-
|
|
74002
|
-
${TOOL_USAGE_INSTRUCTION}
|
|
74003
|
-
|
|
74004
|
-
## Your Role
|
|
74005
|
-
|
|
74006
|
-
As an epic planner, your expertise lies in:
|
|
74007
|
-
- Decomposing large, complex features into structured task breakdowns
|
|
74008
|
-
- Creating epic-scale plans with implementation-ready task specifications
|
|
74009
|
-
- Organizing work into logical phases with clear dependencies
|
|
74010
|
-
- Providing complete technical details for each task to enable autonomous implementation
|
|
74011
|
-
|
|
74012
|
-
## Epic Planning Principles
|
|
74013
|
-
|
|
74014
|
-
**1. Explore Before Planning**
|
|
74015
|
-
- Use available tools to understand the existing codebase
|
|
74016
|
-
- Identify similar implementations, patterns, and conventions
|
|
74017
|
-
- Understand project structure, naming conventions, and architectural patterns
|
|
74018
|
-
- The best plans are informed by actual codebase state, not assumptions
|
|
74019
|
-
|
|
74020
|
-
**2. Epic Planning Structure**
|
|
74021
|
-
- **Phases**: Organize work into logical phases (e.g., "Phase 1: Backend API", "Phase 2: Frontend UI")
|
|
74022
|
-
- **Tasks**: Break each phase into specific, actionable tasks
|
|
74023
|
-
- **Dependencies**: Make task dependencies and ordering clear
|
|
74024
|
-
|
|
74025
|
-
**3. Task Detail Requirements**
|
|
74026
|
-
Each task must be **implementation-ready** with complete specifications:
|
|
74027
|
-
- **Exact file paths** for new files or modifications (e.g., \`src/api/auth.ts\`)
|
|
74028
|
-
- **Function/class signatures** to implement (e.g., \`async function authenticateUser(email: string, password: string)\`)
|
|
74029
|
-
- **Implementation patterns** from the codebase (e.g., "Follow the middleware pattern in \`src/middleware/logger.ts\`")
|
|
74030
|
-
- **Dependencies and imports** (e.g., "Import \`bcrypt\` for password hashing")
|
|
74031
|
-
- **Error handling approach** (e.g., "Use \`ApiError\` class from \`src/errors.ts\`")
|
|
74032
|
-
- **Integration points** with existing code (e.g., "Register in \`src/app.ts\` before route handlers")
|
|
74033
|
-
- **Testing requirements** (e.g., "Add tests in \`src/api/__tests__/auth.test.ts\`")
|
|
74034
|
-
|
|
74035
|
-
**Examples of appropriate task detail:**
|
|
74036
|
-
- ❌ **Too vague**: "Add authentication"
|
|
74037
|
-
- ❌ **Too granular**: "Add a 20px margin to the button on line 45"
|
|
74038
|
-
- ✅ **Implementation-ready**: "Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\` that validates credentials using bcrypt and returns JWT tokens with 24h expiration"
|
|
74039
|
-
|
|
74040
|
-
**4. Enable Autonomous Implementation**
|
|
74041
|
-
- Plans must provide enough detail that task creation doesn't require codebase exploration
|
|
74042
|
-
- Each task should be concrete and implementable by an AI agent
|
|
74043
|
-
- Include all technical information needed for autonomous execution
|
|
74044
|
-
|
|
74045
|
-
## Your Approach
|
|
74046
|
-
|
|
74047
|
-
When planning an epic:
|
|
74048
|
-
|
|
74049
|
-
1. **Understand the Goal**: Analyze the request to grasp objectives and constraints
|
|
74050
|
-
2. **Gather Context**: Explore the codebase to understand patterns and structure
|
|
74051
|
-
3. **Organize into Phases**: Break work into logical phases with clear progression
|
|
74052
|
-
4. **Define Tasks**: Create specific, implementation-ready tasks for each phase
|
|
74053
|
-
5. **Specify Details**: Provide complete technical specifications for each task
|
|
74054
|
-
6. **Seek Clarity**: Ask questions if requirements are ambiguous or information is missing
|
|
74055
|
-
|
|
74056
|
-
## Plan Format Guidelines
|
|
74057
|
-
|
|
74058
|
-
Your plan must have two parts: task description and implementation plan.
|
|
74059
|
-
|
|
74060
|
-
### 1. Task Description
|
|
74061
|
-
Start by providing a detailed description of the task and its expected outcome. This description should be a comprehensive summary based on the user's request, setting the stage for the detailed implementation plan that follows. It should clearly articulate the "what" and "why" of the epic before breaking it down into "how".
|
|
74062
|
-
|
|
74063
|
-
### 2. Implementation Plan
|
|
74064
|
-
|
|
74065
|
-
For epic-scale work, **use markdown checkboxes** to track progress through multiple sequential tasks:
|
|
74066
|
-
|
|
74067
|
-
**Required Checkbox Format**:
|
|
74068
|
-
- Use markdown checkboxes (\`- [ ] item\`) for all tasks
|
|
74069
|
-
- Organize checkboxes under numbered phases (Phase 1, Phase 2, etc.)
|
|
74070
|
-
- Create nested sub-tasks using indentation (max 3 levels: Phase > Task > Sub-task)
|
|
74071
|
-
- Each checkbox represents a distinct, trackable piece of work
|
|
74072
|
-
- Workflow automatically marks completed items with \`- [x]\`
|
|
74073
|
-
|
|
74074
|
-
**Nesting Rules**:
|
|
74075
|
-
- **Level 1 (Phase)**: High-level grouping (e.g., "Phase 1: Backend API Development")
|
|
74076
|
-
- **Level 2 (Task)**: Specific implementation work (e.g., "Design and implement authentication endpoints")
|
|
74077
|
-
- **Level 3 (Sub-task)**: Detailed breakdown when task is complex (e.g., "Create POST /api/auth/login endpoint")
|
|
74078
|
-
- **Maximum depth**: 3 levels to maintain clarity
|
|
74079
|
-
|
|
74080
|
-
**Each Task Must Include Implementation-Ready Details**:
|
|
74081
|
-
- **Exact file paths** for new files or modifications (e.g., \`src/api/auth.ts\`)
|
|
74082
|
-
- **Function/class signatures** to implement (e.g., \`async function authenticateUser(email: string, password: string)\`)
|
|
74083
|
-
- **Implementation patterns** to follow (e.g., "Follow the middleware pattern in \`src/middleware/logger.ts\`")
|
|
74084
|
-
- **Dependencies and imports** (e.g., "Import \`bcrypt\` for password hashing, use \`jsonwebtoken\` for JWT generation")
|
|
74085
|
-
- **Error handling** (e.g., "Use \`ApiError\` class from \`src/errors.ts\`")
|
|
74086
|
-
- **Integration points** (e.g., "Register middleware in \`src/app.ts\` before route handlers")
|
|
74087
|
-
- **Testing requirements** (e.g., "Add unit tests in \`src/api/__tests__/auth.test.ts\`")
|
|
74088
|
-
|
|
74089
|
-
\`\`\`
|
|
74090
|
-
### 1. Task Description
|
|
74091
|
-
|
|
74092
|
-
This epic is to implement a complete user authentication system using JSON Web Tokens (JWT). The primary goal is to allow users to register for a new account and log in to receive a token that can be used to access protected resources. The system should handle password hashing for security and provide a way to manage user sessions on the frontend.
|
|
74093
|
-
|
|
74094
|
-
**Expected Outcome:**
|
|
74095
|
-
- A backend with registration and login endpoints.
|
|
74096
|
-
- Secure password storage using bcrypt.
|
|
74097
|
-
- JWT generation upon successful login.
|
|
74098
|
-
- Middleware to protect specific routes.
|
|
74099
|
-
- A frontend with a login form, registration form, and context for managing authentication state.
|
|
74100
|
-
|
|
74101
|
-
### 2. Implementation Plan
|
|
74102
|
-
|
|
74103
|
-
1. Phase 1: Backend API
|
|
74104
|
-
- [ ] Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\` (validates credentials using bcrypt, returns JWT with 24h expiration using \`jsonwebtoken\` library) and \`POST /api/auth/register\` (validates with zod, hashes password with bcrypt 10 rounds, stores via Prisma)
|
|
74105
|
-
- [ ] Create authentication middleware in \`src/middleware/auth.ts\` that verifies JWT tokens from Authorization header and attaches user to \`req.user\`, following pattern in \`src/middleware/logger.ts\`
|
|
74106
|
-
- [ ] Define User model in \`prisma/schema.prisma\` with id (UUID), email (unique), passwordHash, createdAt, updatedAt; generate migration with \`npx prisma migrate dev --name add-user-auth\`
|
|
74107
|
-
|
|
74108
|
-
2. Phase 2: Frontend Integration
|
|
74109
|
-
- [ ] Create \`LoginForm.tsx\` in \`src/components/auth/\` with email/password fields using React Hook Form, submit calls \`/api/auth/login\` endpoint
|
|
74110
|
-
- [ ] Create \`AuthContext.tsx\` using React Context API to manage auth state (user object, isAuthenticated boolean, login/logout functions that interact with localStorage JWT storage)
|
|
74111
|
-
- [ ] Add error handling using \`ErrorMessage\` component from \`src/components/ui/ErrorMessage.tsx\` and loading states with \`LoadingSpinner\` from \`src/components/ui/LoadingSpinner.tsx\`
|
|
74112
|
-
\`\`\`
|
|
74113
|
-
|
|
74114
|
-
**Good Task Detail (Implementation-Ready)**:
|
|
74115
|
-
\`\`\`
|
|
74116
|
-
- [ ] Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\` (validates credentials using bcrypt, returns JWT with 24h expiration using \`jsonwebtoken\` library) and \`POST /api/auth/register\` (validates with zod, hashes password with bcrypt 10 rounds, stores via Prisma)
|
|
74117
|
-
\`\`\`
|
|
74118
|
-
|
|
74119
|
-
**Poor Task Detail (Too Vague)**:
|
|
74120
|
-
\`\`\`
|
|
74121
|
-
- [ ] Add authentication to the backend API
|
|
74122
|
-
\`\`\`
|
|
74123
|
-
|
|
74124
|
-
**What to Include**:
|
|
74125
|
-
- Implementation steps with complete technical specifications
|
|
74126
|
-
- Exact file paths, function names, and implementation patterns
|
|
74127
|
-
- Dependencies, imports, and integration points
|
|
74128
|
-
- Technical constraints and requirements
|
|
74129
|
-
|
|
74130
|
-
**What NOT to Include**:
|
|
74131
|
-
- Future enhancements beyond current scope
|
|
74132
|
-
- Manual test plans or validation checklists
|
|
74133
|
-
- Meta-information about priorities
|
|
74134
|
-
|
|
74135
|
-
|
|
74136
|
-
|
|
74137
|
-
## Branch Naming Conventions
|
|
74138
|
-
|
|
74139
|
-
Branch names should:
|
|
74140
|
-
- Use kebab-case (lowercase with hyphens)
|
|
74141
|
-
- Start with a prefix: feat/, fix/, refactor/, docs/, test/, chore/
|
|
74142
|
-
- Be descriptive but concise (2-4 words typically)
|
|
74143
|
-
- Describe what is being changed, not who or why
|
|
74144
|
-
|
|
74145
|
-
## Decision Logic
|
|
74146
|
-
|
|
74147
|
-
1. **Analyze the request**: Review the task and any existing plan
|
|
74148
|
-
2. **If requirements are clear**:
|
|
74149
|
-
- Explore the codebase to understand patterns and conventions
|
|
74150
|
-
- Create an epic-scale plan with checkbox format and implementation-ready task details
|
|
74151
|
-
- Ensure each task includes specific file paths, function names, patterns, and technical details
|
|
74152
|
-
- Propose a suitable git branch name (see conventions below)
|
|
74153
|
-
3. **If requirements are unclear**:
|
|
74154
|
-
- Ask a clarifying question with optional default answer
|
|
74155
|
-
4. **If no action is needed**:
|
|
74156
|
-
- Provide reason (e.g., already implemented, not applicable)
|
|
74157
|
-
|
|
74158
|
-
## Response Format
|
|
74159
|
-
|
|
74160
|
-
${createJsonResponseInstruction({
|
|
74161
|
-
type: "'plan-generated' | 'question' | 'error'",
|
|
74162
|
-
plan: "The epic plan with checkbox format (required when type='plan-generated')",
|
|
74163
|
-
branchName: "Git branch name with valid prefix (required when type='plan-generated')",
|
|
74164
|
-
question: {
|
|
74165
|
-
question: "The clarifying question to ask",
|
|
74166
|
-
defaultAnswer: "Optional default answer"
|
|
74167
|
-
},
|
|
74168
|
-
reason: "Why no plan is needed (required when type='error')"
|
|
74169
|
-
})}
|
|
74170
|
-
|
|
74171
|
-
**Response Type Details:**
|
|
74172
|
-
|
|
74173
|
-
1. **plan-generated**: When you create or update an epic plan
|
|
74174
|
-
- Include complete plan with checkbox format
|
|
74175
|
-
- Provide branch name with valid prefix (feat/, fix/, refactor/, docs/, test/, chore/)
|
|
74176
|
-
|
|
74177
|
-
2. **question**: When you need clarification
|
|
74178
|
-
- Ask specific, unambiguous question
|
|
74179
|
-
- Optionally provide default answer
|
|
74180
|
-
|
|
74181
|
-
3. **error**: When no action is needed
|
|
74182
|
-
- Explain why (e.g., already implemented, not applicable)
|
|
74183
|
-
`;
|
|
74184
|
-
BRANCH_NAME_PATTERN = /^[a-zA-Z0-9/_-]+$/;
|
|
74185
|
-
EpicPlanSchema = exports_external.object({
|
|
74186
|
-
type: exports_external.enum(["plan-generated", "question", "error"]),
|
|
74187
|
-
plan: exports_external.string().nullish(),
|
|
74188
|
-
branchName: exports_external.string().min(3, "Branch name is too short (min 3 characters)").max(255, "Branch name is too long (max 255 characters)").refine((name17) => BRANCH_NAME_PATTERN.test(name17), {
|
|
74189
|
-
message: "Invalid branch name format. Branch names should contain only letters, numbers, hyphens, underscores, and forward slashes."
|
|
74190
|
-
}).nullish(),
|
|
74191
|
-
question: exports_external.object({
|
|
74192
|
-
question: exports_external.string(),
|
|
74193
|
-
defaultAnswer: exports_external.string().nullish()
|
|
74194
|
-
}).nullish(),
|
|
74195
|
-
reason: exports_external.string().nullish()
|
|
74196
|
-
}).superRefine((data, ctx) => {
|
|
74197
|
-
switch (data.type) {
|
|
74198
|
-
case "plan-generated": {
|
|
74199
|
-
if (!data.plan || data.plan.trim() === "") {
|
|
74200
|
-
ctx.addIssue({
|
|
74201
|
-
code: "custom",
|
|
74202
|
-
message: 'Plan is required when type is "plan-generated".',
|
|
74203
|
-
path: ["plan"]
|
|
74204
|
-
});
|
|
74205
|
-
}
|
|
74206
|
-
if (!data.branchName || data.branchName.trim() === "") {
|
|
74207
|
-
ctx.addIssue({
|
|
74208
|
-
code: "custom",
|
|
74209
|
-
message: 'Branch name is required when type is "plan-generated".',
|
|
74210
|
-
path: ["branchName"]
|
|
74211
|
-
});
|
|
74212
|
-
}
|
|
74213
|
-
break;
|
|
74214
|
-
}
|
|
74215
|
-
case "question": {
|
|
74216
|
-
if (!data.question) {
|
|
74217
|
-
ctx.addIssue({
|
|
74218
|
-
code: "custom",
|
|
74219
|
-
message: 'Question is required when type is "question".',
|
|
74220
|
-
path: ["question"]
|
|
74221
|
-
});
|
|
74222
|
-
}
|
|
74223
|
-
break;
|
|
74224
|
-
}
|
|
74225
|
-
case "error": {
|
|
74226
|
-
if (!data.reason || data.reason.trim() === "") {
|
|
74227
|
-
ctx.addIssue({
|
|
74228
|
-
code: "custom",
|
|
74229
|
-
message: 'Reason is required when type is "error".',
|
|
74230
|
-
path: ["reason"]
|
|
74231
|
-
});
|
|
74232
|
-
}
|
|
74233
|
-
break;
|
|
74234
|
-
}
|
|
74235
|
-
}
|
|
74236
|
-
});
|
|
74237
|
-
EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT = `Role: Task extraction agent
|
|
74238
|
-
Goal: Parse an epic plan and create structured todo items from task breakdowns.
|
|
74239
|
-
|
|
74240
|
-
${TOOL_USAGE_INSTRUCTION}
|
|
74241
|
-
|
|
74242
|
-
You are responsible for extracting tasks from a detailed epic plan and creating todo items that can be executed autonomously by an AI coding agent.
|
|
74243
|
-
|
|
74244
|
-
## Expected Plan Format
|
|
74245
|
-
|
|
74246
|
-
The plan you receive follows a specific structure:
|
|
74247
|
-
- **Markdown checkboxes** (\`- [ ] item\`) indicate tasks
|
|
74248
|
-
- **Nesting** (indentation) indicates hierarchy: Phase > Task > Sub-task
|
|
74249
|
-
- **Implementation details** are included in each checkbox item
|
|
74250
|
-
- **Max 3 levels** of nesting
|
|
74251
|
-
|
|
74252
|
-
**Example plan structure:**
|
|
74253
|
-
\`\`\`
|
|
74254
|
-
1. Phase 1: Backend API
|
|
74255
|
-
- [ ] Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\`...
|
|
74256
|
-
- [ ] Create \`POST /api/auth/login\` endpoint that validates credentials...
|
|
74257
|
-
- [ ] Create \`POST /api/auth/register\` endpoint that validates input...
|
|
74258
|
-
- [ ] Create authentication middleware in \`src/middleware/auth.ts\`...
|
|
74259
|
-
\`\`\`
|
|
74260
|
-
|
|
74261
|
-
**Parsing rules:**
|
|
74262
|
-
- Lines with \`- [ ]\` are tasks to extract
|
|
74263
|
-
- Indentation level indicates parent-child relationships
|
|
74264
|
-
- Text after checkbox is the task title
|
|
74265
|
-
- Nested content provides additional context
|
|
74266
|
-
|
|
74267
|
-
## Your Role: Extract and Structure Tasks
|
|
74268
|
-
|
|
74269
|
-
Your job is to **extract and structure** tasks from the plan, not to explore or research:
|
|
74270
|
-
- Parse the checkbox structure to identify tasks
|
|
74271
|
-
- Extract implementation details already in the plan
|
|
74272
|
-
- Create todo items that preserve the plan's hierarchy
|
|
74273
|
-
- Do NOT explore the codebase - all information is in the plan
|
|
74274
|
-
|
|
74275
|
-
## Todo Item Creation Rules
|
|
74276
|
-
|
|
74277
|
-
For each checkbox in the plan, create a todo item using \`updateTodoItem\`:
|
|
74278
|
-
|
|
74279
|
-
### 1. **title** (required)
|
|
74280
|
-
Extract the checkbox text as the task title (max 60 characters, concise and action-oriented).
|
|
74281
|
-
|
|
74282
|
-
**Examples:**
|
|
74283
|
-
- Plan: \`- [ ] Implement authentication endpoints in \`src/api/auth.ts\`...\`
|
|
74284
|
-
- Title: "Implement authentication endpoints in src/api/auth.ts"
|
|
74285
|
-
|
|
74286
|
-
### 2. **description** (required)
|
|
74287
|
-
Extract and organize implementation details from the plan:
|
|
74288
|
-
|
|
74289
|
-
**Extract from the plan:**
|
|
74290
|
-
- **File paths**: All backtick-wrapped paths (e.g., \`src/api/auth.ts\`)
|
|
74291
|
-
- **Function/class names**: Code-formatted identifiers with parentheses (e.g., \`authenticateUser()\`)
|
|
74292
|
-
- **Dependencies**: "import X", "use Y library" mentions
|
|
74293
|
-
- **Patterns**: "Follow pattern in...", "Similar to..." references
|
|
74294
|
-
- **Technical specs**: All implementation guidance from the checkbox and nested content
|
|
74295
|
-
|
|
74296
|
-
**Example extraction:**
|
|
74297
|
-
|
|
74298
|
-
Plan:
|
|
74299
|
-
\`\`\`
|
|
74300
|
-
- [ ] Implement authentication endpoints in \`src/api/auth.ts\` with \`POST /api/auth/login\` that validates credentials using bcrypt and returns JWT tokens
|
|
74301
|
-
- [ ] Create \`POST /api/auth/login\` endpoint that accepts email/password in request body
|
|
74302
|
-
\`\`\`
|
|
74303
|
-
|
|
74304
|
-
Title: "Implement authentication endpoints in src/api/auth.ts"
|
|
74305
|
-
|
|
74306
|
-
Description:
|
|
74307
|
-
\`\`\`
|
|
74308
|
-
Create authentication endpoints in \`src/api/auth.ts\`:
|
|
74309
|
-
|
|
74310
|
-
**Main endpoint:**
|
|
74311
|
-
- \`POST /api/auth/login\` that validates credentials using bcrypt and returns JWT tokens
|
|
74312
|
-
|
|
74313
|
-
**Sub-tasks:**
|
|
74314
|
-
- Create \`POST /api/auth/login\` endpoint that accepts email/password in request body
|
|
74315
|
-
\`\`\`
|
|
74316
|
-
|
|
74317
|
-
|
|
74318
|
-
## Process
|
|
74319
|
-
|
|
74320
|
-
1. Parse the plan to identify all checkbox items
|
|
74321
|
-
2. For each checkbox:
|
|
74322
|
-
a. Extract title from checkbox text (keep concise)
|
|
74323
|
-
b. Extract description from checkbox content and nested items
|
|
74324
|
-
c. Identify parent-child relationships from indentation
|
|
74325
|
-
d. Extract file paths, functions, dependencies, patterns
|
|
74326
|
-
|
|
74327
|
-
**Remember:** Your role is extraction and organization, not exploration or planning.
|
|
74328
|
-
`;
|
|
74329
|
-
});
|
|
74330
|
-
|
|
74331
74006
|
// src/workflows/prompts/fix.ts
|
|
74332
74007
|
function getFixUserPrompt(command, exitCode, stdout, stderr, task, prompt) {
|
|
74333
74008
|
const taskSection = task ? `
|
|
@@ -74438,14 +74113,13 @@ ${createJsonResponseInstruction({
|
|
|
74438
74113
|
var META_SYSTEM_PROMPT;
|
|
74439
74114
|
var init_meta = __esm(() => {
|
|
74440
74115
|
META_SYSTEM_PROMPT = `Role: Meta-agent.
|
|
74441
|
-
Goal: Decide which workflow ('code'
|
|
74116
|
+
Goal: Decide which workflow ('code' or 'task') to use for a given task.
|
|
74442
74117
|
|
|
74443
74118
|
You are a meta-agent that decides which workflow to use for a given task.
|
|
74444
|
-
Based on the user's task, decide whether to use the 'code'
|
|
74119
|
+
Based on the user's task, decide whether to use the 'code' or 'task' workflow.
|
|
74445
74120
|
|
|
74446
74121
|
- Use the 'code' workflow for tasks that are well-defined and can be implemented directly without a separate planning phase.
|
|
74447
74122
|
- Use the 'task' workflow for simple, single-action tasks like answering a question or running a command.
|
|
74448
|
-
- Use the 'epic' workflow for large, complex features that require breaking down into multiple sequential tasks, creating a feature branch, and executing multiple implementation-commit-review cycles.
|
|
74449
74123
|
|
|
74450
74124
|
The user's task is provided in the <task> tag.
|
|
74451
74125
|
|
|
@@ -74697,6 +74371,9 @@ ${value}
|
|
|
74697
74371
|
</${tag}>`;
|
|
74698
74372
|
}
|
|
74699
74373
|
function getReviewInstructions(params) {
|
|
74374
|
+
if (params.targetCommit) {
|
|
74375
|
+
return `Review the changes in commit '${params.targetCommit}'. The gitDiff tool is NOT available for past commits. Use readFile to inspect the file contents and identify issues in the modified files listed in <file_status>.`;
|
|
74376
|
+
}
|
|
74700
74377
|
if (params.commitRange) {
|
|
74701
74378
|
return `Review the pull request. Use the gitDiff tool with commit range '${params.commitRange}' to inspect the actual code changes.`;
|
|
74702
74379
|
}
|
|
@@ -74720,6 +74397,7 @@ function formatReviewToolInput(params) {
|
|
|
74720
74397
|
formatContext("pr_title", params.pullRequestTitle),
|
|
74721
74398
|
formatContext("pr_description", params.pullRequestDescription),
|
|
74722
74399
|
formatContext("commit_messages", params.commitMessages),
|
|
74400
|
+
formatContext("target_commit", params.targetCommit),
|
|
74723
74401
|
formatContext("user_context", params.context),
|
|
74724
74402
|
formatContext("file_status", fileList),
|
|
74725
74403
|
formatContext("review_instructions", getReviewInstructions(params))
|
|
@@ -74740,17 +74418,19 @@ ${TOOL_USAGE_INSTRUCTION}
|
|
|
74740
74418
|
2. **Select Files for Diff**: From the modified files, select only the reviewable source and configuration files.
|
|
74741
74419
|
- **Include**: Source code, config files, and template files.
|
|
74742
74420
|
- **Exclude**: Lockfiles, build artifacts, test snapshots, binary/media files, data and fixtures and other generated files.
|
|
74743
|
-
3. **Inspect Changes**:
|
|
74744
|
-
|
|
74421
|
+
3. **Inspect Changes**:
|
|
74422
|
+
- When the \`gitDiff\` tool is available: Use it on one file at a time to see the exact changes. When reviewing pull requests, use the \`commitRange\` parameter provided in the review instructions.
|
|
74423
|
+
- When the \`gitDiff\` tool is NOT available (reviewing past commits): Use \`readFile\` to inspect the file contents. You will not have access to the exact diff, so focus on reviewing the code for issues in the modified files listed in \`<file_status>\`.
|
|
74424
|
+
4. **Analyze and Review**: Analyze the code for issues. When using \`gitDiff\`, focus only on the modified lines (additions/deletions). Provide specific, actionable feedback with accurate line numbers.
|
|
74745
74425
|
|
|
74746
74426
|
## Critical Rules
|
|
74747
74427
|
|
|
74748
|
-
- **Focus on Changes**: ONLY review the actual changes shown in the diff. Do not comment on existing, unmodified code.
|
|
74428
|
+
- **Focus on Changes**: When using \`gitDiff\`, ONLY review the actual changes shown in the diff. Do not comment on existing, unmodified code. When \`gitDiff\` is not available, focus on the modified files listed in \`<file_status>\`.
|
|
74749
74429
|
- **Focus Scope**: Do not comment on overall project structure or architecture unless directly impacted by the changes in the diff.
|
|
74750
74430
|
- **No Feature Requests**: Do not comment on missing features or functionality that are not part of this diff.
|
|
74751
|
-
- **One File at a Time**: Review files individually using \`gitDiff\` with the specific file path.
|
|
74752
|
-
- **No Empty Diffs**: MUST NOT call \`gitDiff\` with an empty or omitted file parameter.
|
|
74753
|
-
- **Accurate Line Numbers**:
|
|
74431
|
+
- **One File at a Time**: Review files individually using \`gitDiff\` (when available) with the specific file path, or \`readFile\` when reviewing past commits.
|
|
74432
|
+
- **No Empty Diffs**: MUST NOT call \`gitDiff\` with an empty or omitted file parameter when the tool is available.
|
|
74433
|
+
- **Accurate Line Numbers**: When using \`gitDiff\`, use the line numbers from the diff annotations (\`[Line N]\` for additions, \`[Line N removed]\` for deletions). When \`gitDiff\` is not available, use line numbers from \`readFile\` output.
|
|
74754
74434
|
- **No Praise**: Provide only reviews for actual issues found. Do not include praise or positive feedback.
|
|
74755
74435
|
- **Clear Reasoning**: For each issue, provide clear reasoning explaining why it's a problem and what the impact could be.
|
|
74756
74436
|
- **Specific Advice**: Avoid generic advice. Provide concrete, actionable suggestions specific to the code being reviewed.
|
|
@@ -74762,6 +74442,7 @@ You may receive the following context:
|
|
|
74762
74442
|
- \`<user_context>\`: Specific review focus from the user
|
|
74763
74443
|
- \`<file_status>\`: List of modified files with their status
|
|
74764
74444
|
- \`<review_instructions>\`: Specific instructions for this review
|
|
74445
|
+
- \`<target_commit>\`: The specific commit being reviewed (when reviewing past commits)
|
|
74765
74446
|
|
|
74766
74447
|
## Output Format
|
|
74767
74448
|
|
|
@@ -74824,7 +74505,6 @@ ${createJsonResponseInstruction({
|
|
|
74824
74505
|
var init_prompts2 = __esm(() => {
|
|
74825
74506
|
init_coder();
|
|
74826
74507
|
init_commit();
|
|
74827
|
-
init_epic();
|
|
74828
74508
|
init_fix();
|
|
74829
74509
|
init_init();
|
|
74830
74510
|
init_meta();
|
|
@@ -88283,20 +87963,6 @@ ${item.review}
|
|
|
88283
87963
|
}
|
|
88284
87964
|
return formatted;
|
|
88285
87965
|
}
|
|
88286
|
-
function formatElapsedTime(ms) {
|
|
88287
|
-
const seconds = ms / 1000;
|
|
88288
|
-
if (seconds < 60) {
|
|
88289
|
-
return `${seconds.toFixed(1)}s`;
|
|
88290
|
-
}
|
|
88291
|
-
const minutes = Math.floor(seconds / 60);
|
|
88292
|
-
const remainingSeconds = Math.floor(seconds % 60);
|
|
88293
|
-
if (minutes < 60) {
|
|
88294
|
-
return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
|
|
88295
|
-
}
|
|
88296
|
-
const hours = Math.floor(minutes / 60);
|
|
88297
|
-
const remainingMinutes = minutes % 60;
|
|
88298
|
-
return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
|
|
88299
|
-
}
|
|
88300
87966
|
async function getDefaultContext(commandName) {
|
|
88301
87967
|
const config4 = await loadConfig2();
|
|
88302
87968
|
const cwd = process.cwd();
|
|
@@ -89493,6 +89159,219 @@ var init_tools3 = __esm(() => {
|
|
|
89493
89159
|
init_updateTodoItem();
|
|
89494
89160
|
});
|
|
89495
89161
|
|
|
89162
|
+
// src/utils/shell.ts
|
|
89163
|
+
function isWindows() {
|
|
89164
|
+
return process.platform === "win32";
|
|
89165
|
+
}
|
|
89166
|
+
function quoteForShell(str) {
|
|
89167
|
+
if (isWindows()) {
|
|
89168
|
+
const escaped = str.replace(/"/g, '""');
|
|
89169
|
+
return `"${escaped}"`;
|
|
89170
|
+
} else {
|
|
89171
|
+
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
89172
|
+
}
|
|
89173
|
+
}
|
|
89174
|
+
|
|
89175
|
+
// src/workflows/git-file-tools.ts
|
|
89176
|
+
function extractTargetCommit(range, pr2) {
|
|
89177
|
+
if (pr2) {
|
|
89178
|
+
return null;
|
|
89179
|
+
}
|
|
89180
|
+
if (!range) {
|
|
89181
|
+
return null;
|
|
89182
|
+
}
|
|
89183
|
+
const parts = range.split(/\.\.\.?/);
|
|
89184
|
+
if (parts.length > 1) {
|
|
89185
|
+
return parts[1].trim() || null;
|
|
89186
|
+
}
|
|
89187
|
+
return range.trim() || null;
|
|
89188
|
+
}
|
|
89189
|
+
function createGitReadFile(commit2) {
|
|
89190
|
+
const toolInfo20 = {
|
|
89191
|
+
name: "readFile",
|
|
89192
|
+
description: `Read file contents from git commit ${commit2}. Use this to examine files at the specific commit being reviewed.`,
|
|
89193
|
+
parameters: exports_external.object({
|
|
89194
|
+
path: exports_external.preprocess((val) => {
|
|
89195
|
+
if (!val)
|
|
89196
|
+
return [];
|
|
89197
|
+
const values = Array.isArray(val) ? val : [val];
|
|
89198
|
+
return values.flatMap((i2) => typeof i2 === "string" ? i2.split(",") : []).filter((s2) => s2.length > 0);
|
|
89199
|
+
}, exports_external.array(exports_external.string())).describe("The path of the file to read (relative to git root)").meta({ usageValue: "Comma separated paths here" })
|
|
89200
|
+
}).meta({
|
|
89201
|
+
examples: [
|
|
89202
|
+
{
|
|
89203
|
+
description: "Read the contents of a file at the commit",
|
|
89204
|
+
input: {
|
|
89205
|
+
path: "src/main.ts"
|
|
89206
|
+
}
|
|
89207
|
+
}
|
|
89208
|
+
]
|
|
89209
|
+
})
|
|
89210
|
+
};
|
|
89211
|
+
const handler20 = async (provider3, args) => {
|
|
89212
|
+
if (!provider3.executeCommand) {
|
|
89213
|
+
return {
|
|
89214
|
+
success: false,
|
|
89215
|
+
message: {
|
|
89216
|
+
type: "error-text",
|
|
89217
|
+
value: "Not possible to execute command."
|
|
89218
|
+
}
|
|
89219
|
+
};
|
|
89220
|
+
}
|
|
89221
|
+
const { path: paths } = toolInfo20.parameters.parse(args);
|
|
89222
|
+
const results = [];
|
|
89223
|
+
for (const filePath of paths) {
|
|
89224
|
+
const quotedCommit = quoteForShell(commit2);
|
|
89225
|
+
const quotedPath = quoteForShell(filePath);
|
|
89226
|
+
const result = await provider3.executeCommand(`git show ${quotedCommit}:${quotedPath}`, false);
|
|
89227
|
+
if (result.exitCode === 0) {
|
|
89228
|
+
results.push(`<read_file_file_content path="${filePath}">${result.stdout}</read_file_file_content>`);
|
|
89229
|
+
} else {
|
|
89230
|
+
results.push(`<read_file_file_content path="${filePath}" file_not_found="true"></read_file_file_content>`);
|
|
89231
|
+
}
|
|
89232
|
+
}
|
|
89233
|
+
return {
|
|
89234
|
+
success: true,
|
|
89235
|
+
message: {
|
|
89236
|
+
type: "text",
|
|
89237
|
+
value: results.join(`
|
|
89238
|
+
`)
|
|
89239
|
+
}
|
|
89240
|
+
};
|
|
89241
|
+
};
|
|
89242
|
+
return {
|
|
89243
|
+
...toolInfo20,
|
|
89244
|
+
handler: handler20
|
|
89245
|
+
};
|
|
89246
|
+
}
|
|
89247
|
+
function createGitListFiles(commit2) {
|
|
89248
|
+
const toolInfo20 = {
|
|
89249
|
+
name: "listFiles",
|
|
89250
|
+
description: `List files and directories at git commit ${commit2}. Shows the file tree as it existed at that commit.`,
|
|
89251
|
+
parameters: exports_external.object({
|
|
89252
|
+
path: exports_external.string().optional().describe("The path of the directory to list (relative to git root). Default is root.").meta({ usageValue: "Directory path here (optional)" }),
|
|
89253
|
+
maxCount: exports_external.coerce.number().optional().default(2000).describe("The maximum number of files to list. Default to 2000").meta({ usageValue: "Maximum number of files to list (optional)" })
|
|
89254
|
+
})
|
|
89255
|
+
};
|
|
89256
|
+
const handler20 = async (provider3, args) => {
|
|
89257
|
+
if (!provider3.executeCommand) {
|
|
89258
|
+
return {
|
|
89259
|
+
success: false,
|
|
89260
|
+
message: {
|
|
89261
|
+
type: "error-text",
|
|
89262
|
+
value: "Not possible to execute command."
|
|
89263
|
+
}
|
|
89264
|
+
};
|
|
89265
|
+
}
|
|
89266
|
+
const parsed = toolInfo20.parameters.parse(args);
|
|
89267
|
+
const path2 = parsed.path || ".";
|
|
89268
|
+
const quotedCommit = quoteForShell(commit2);
|
|
89269
|
+
const quotedPath = quoteForShell(path2);
|
|
89270
|
+
const result = await provider3.executeCommand(`git ls-tree -r --name-only ${quotedCommit} ${quotedPath}`, false);
|
|
89271
|
+
if (result.exitCode !== 0) {
|
|
89272
|
+
return {
|
|
89273
|
+
success: false,
|
|
89274
|
+
message: {
|
|
89275
|
+
type: "error-text",
|
|
89276
|
+
value: `Failed to list files at commit ${commit2}: ${result.stderr}`
|
|
89277
|
+
}
|
|
89278
|
+
};
|
|
89279
|
+
}
|
|
89280
|
+
const files = result.stdout.trim().split(`
|
|
89281
|
+
`).filter((f3) => f3.length > 0);
|
|
89282
|
+
const truncated = files.length > parsed.maxCount;
|
|
89283
|
+
const displayFiles = truncated ? files.slice(0, parsed.maxCount) : files;
|
|
89284
|
+
return {
|
|
89285
|
+
success: true,
|
|
89286
|
+
message: {
|
|
89287
|
+
type: "text",
|
|
89288
|
+
value: `<list_files_path>${path2}</list_files_path>
|
|
89289
|
+
<list_files_files>
|
|
89290
|
+
${displayFiles.join(`
|
|
89291
|
+
`)}
|
|
89292
|
+
</list_files_files>
|
|
89293
|
+
<list_files_truncated>${truncated}</list_files_truncated>`
|
|
89294
|
+
}
|
|
89295
|
+
};
|
|
89296
|
+
};
|
|
89297
|
+
return {
|
|
89298
|
+
...toolInfo20,
|
|
89299
|
+
handler: handler20
|
|
89300
|
+
};
|
|
89301
|
+
}
|
|
89302
|
+
function createGitReadBinaryFile(commit2) {
|
|
89303
|
+
const toolInfo20 = {
|
|
89304
|
+
name: "readBinaryFile",
|
|
89305
|
+
description: `Read binary file contents from git commit ${commit2} and return as base64 encoded data. Use for images, fonts, and other binary files.`,
|
|
89306
|
+
parameters: exports_external.object({
|
|
89307
|
+
url: exports_external.string().describe("The URL or path of the binary file to read (relative to git root)")
|
|
89308
|
+
})
|
|
89309
|
+
};
|
|
89310
|
+
const handler20 = async (provider3, args) => {
|
|
89311
|
+
if (!provider3.executeCommand) {
|
|
89312
|
+
return {
|
|
89313
|
+
success: false,
|
|
89314
|
+
message: {
|
|
89315
|
+
type: "error-text",
|
|
89316
|
+
value: "Not possible to execute command."
|
|
89317
|
+
}
|
|
89318
|
+
};
|
|
89319
|
+
}
|
|
89320
|
+
const { url: url2 } = toolInfo20.parameters.parse(args);
|
|
89321
|
+
const quotedCommit = quoteForShell(commit2);
|
|
89322
|
+
const quotedUrl = quoteForShell(url2);
|
|
89323
|
+
const checkResult = await provider3.executeCommand(`git cat-file -e ${quotedCommit}:${quotedUrl}`, false);
|
|
89324
|
+
if (checkResult.exitCode !== 0) {
|
|
89325
|
+
return {
|
|
89326
|
+
success: true,
|
|
89327
|
+
message: {
|
|
89328
|
+
type: "text",
|
|
89329
|
+
value: `<read_binary_file_file_content url="${url2}" file_not_found="true"></read_binary_file_file_content>`
|
|
89330
|
+
}
|
|
89331
|
+
};
|
|
89332
|
+
}
|
|
89333
|
+
const result = await provider3.executeCommand(`git show ${quotedCommit}:${quotedUrl} | base64`, false);
|
|
89334
|
+
if (result.exitCode === 0) {
|
|
89335
|
+
const base64Data = result.stdout.replace(/\n/g, "");
|
|
89336
|
+
return {
|
|
89337
|
+
success: true,
|
|
89338
|
+
message: {
|
|
89339
|
+
type: "content",
|
|
89340
|
+
value: [
|
|
89341
|
+
{
|
|
89342
|
+
type: "media",
|
|
89343
|
+
url: url2,
|
|
89344
|
+
data: base64Data
|
|
89345
|
+
}
|
|
89346
|
+
]
|
|
89347
|
+
}
|
|
89348
|
+
};
|
|
89349
|
+
} else {
|
|
89350
|
+
return {
|
|
89351
|
+
success: false,
|
|
89352
|
+
message: {
|
|
89353
|
+
type: "error-text",
|
|
89354
|
+
value: `Failed to read binary file: ${result.stderr}`
|
|
89355
|
+
}
|
|
89356
|
+
};
|
|
89357
|
+
}
|
|
89358
|
+
};
|
|
89359
|
+
return {
|
|
89360
|
+
...toolInfo20,
|
|
89361
|
+
handler: handler20
|
|
89362
|
+
};
|
|
89363
|
+
}
|
|
89364
|
+
function createGitAwareTools(commit2) {
|
|
89365
|
+
return {
|
|
89366
|
+
readFile: createGitReadFile(commit2),
|
|
89367
|
+
listFiles: createGitListFiles(commit2),
|
|
89368
|
+
readBinaryFile: createGitReadBinaryFile(commit2)
|
|
89369
|
+
};
|
|
89370
|
+
}
|
|
89371
|
+
var init_git_file_tools = __esm(() => {
|
|
89372
|
+
init_zod();
|
|
89373
|
+
});
|
|
89374
|
+
|
|
89496
89375
|
// src/workflows/review.workflow.ts
|
|
89497
89376
|
var exports_review_workflow = {};
|
|
89498
89377
|
__export(exports_review_workflow, {
|
|
@@ -89749,7 +89628,11 @@ var reviewWorkflow = async (input, context) => {
|
|
|
89749
89628
|
if (!changeInfo) {
|
|
89750
89629
|
return { overview: "No changes to review.", specificReviews: [] };
|
|
89751
89630
|
}
|
|
89752
|
-
const
|
|
89631
|
+
const targetCommit = extractTargetCommit(range, pr2);
|
|
89632
|
+
const isReviewingCommit = targetCommit !== null;
|
|
89633
|
+
const finalChangeInfo = targetCommit ? { ...changeInfo, targetCommit } : changeInfo;
|
|
89634
|
+
const fileTools = isReviewingCommit && targetCommit ? createGitAwareTools(targetCommit) : { readFile: readFile_default, listFiles: listFiles_default, readBinaryFile: readBinaryFile_default };
|
|
89635
|
+
const reviewTools = isReviewingCommit ? [fileTools.readFile, fileTools.readBinaryFile, fileTools.listFiles] : [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default];
|
|
89753
89636
|
const result = await step("review", async () => {
|
|
89754
89637
|
const defaultContext = await getDefaultContext("review");
|
|
89755
89638
|
const memoryContext = await tools3.getMemoryContext();
|
|
@@ -89766,7 +89649,7 @@ ${memoryContext}`;
|
|
|
89766
89649
|
content: fullContent
|
|
89767
89650
|
}
|
|
89768
89651
|
],
|
|
89769
|
-
tools:
|
|
89652
|
+
tools: reviewTools,
|
|
89770
89653
|
outputSchema: reviewOutputSchema
|
|
89771
89654
|
}, context);
|
|
89772
89655
|
});
|
|
@@ -89782,6 +89665,7 @@ ${memoryContext}`;
|
|
|
89782
89665
|
var init_review_workflow = __esm(() => {
|
|
89783
89666
|
init_src();
|
|
89784
89667
|
init_tools3();
|
|
89668
|
+
init_git_file_tools();
|
|
89785
89669
|
init_prompts2();
|
|
89786
89670
|
init_workflow_utils();
|
|
89787
89671
|
});
|
|
@@ -89796,10 +89680,24 @@ var commitWorkflow = async (input, context) => {
|
|
|
89796
89680
|
const { stagedFiles, unstagedFiles } = await tools3.printChangeFile();
|
|
89797
89681
|
let hasStaged = stagedFiles.length > 0;
|
|
89798
89682
|
const hasUnstaged = unstagedFiles.length > 0;
|
|
89799
|
-
if (
|
|
89683
|
+
if (input.files && input.files.length > 0) {
|
|
89684
|
+
await step("stage-files", async () => {
|
|
89685
|
+
const result2 = await tools3.executeCommand({
|
|
89686
|
+
command: "git",
|
|
89687
|
+
args: ["add", ...input.files]
|
|
89688
|
+
});
|
|
89689
|
+
if (result2.exitCode !== 0) {
|
|
89690
|
+
throw new Error(`Failed to stage files: ${result2.stderr}`);
|
|
89691
|
+
}
|
|
89692
|
+
});
|
|
89693
|
+
hasStaged = true;
|
|
89694
|
+
} else if (!hasStaged) {
|
|
89800
89695
|
if (input.all) {
|
|
89801
89696
|
await step("stage-all", async () => {
|
|
89802
|
-
await tools3.executeCommand({ command: "git", args: ["add", "."] });
|
|
89697
|
+
const result2 = await tools3.executeCommand({ command: "git", args: ["add", "."] });
|
|
89698
|
+
if (result2.exitCode !== 0) {
|
|
89699
|
+
throw new Error(`Failed to stage files: ${result2.stderr}`);
|
|
89700
|
+
}
|
|
89803
89701
|
});
|
|
89804
89702
|
hasStaged = true;
|
|
89805
89703
|
} else if (hasUnstaged) {
|
|
@@ -89812,10 +89710,13 @@ var commitWorkflow = async (input, context) => {
|
|
|
89812
89710
|
}
|
|
89813
89711
|
if (confirmed) {
|
|
89814
89712
|
await step("stage-all", async () => {
|
|
89815
|
-
await tools3.executeCommand({
|
|
89713
|
+
const result2 = await tools3.executeCommand({
|
|
89816
89714
|
command: "git",
|
|
89817
89715
|
args: ["add", "."]
|
|
89818
89716
|
});
|
|
89717
|
+
if (result2.exitCode !== 0) {
|
|
89718
|
+
throw new Error(`Failed to stage files: ${result2.stderr}`);
|
|
89719
|
+
}
|
|
89819
89720
|
});
|
|
89820
89721
|
hasStaged = true;
|
|
89821
89722
|
} else if (input.interactive !== false) {
|
|
@@ -89891,663 +89792,6 @@ var init_commit_workflow = __esm(() => {
|
|
|
89891
89792
|
init_workflow_utils();
|
|
89892
89793
|
});
|
|
89893
89794
|
|
|
89894
|
-
// src/workflows/epic.workflow.ts
|
|
89895
|
-
var exports_epic_workflow = {};
|
|
89896
|
-
__export(exports_epic_workflow, {
|
|
89897
|
-
epicWorkflow: () => epicWorkflow
|
|
89898
|
-
});
|
|
89899
|
-
async function createPlan2(input, context) {
|
|
89900
|
-
const { task, plan: plan2, files, feedback, messages, additionalTools } = input;
|
|
89901
|
-
const { tools: tools3 } = context;
|
|
89902
|
-
const agentTools = [
|
|
89903
|
-
askFollowupQuestion_default,
|
|
89904
|
-
fetchUrl_default,
|
|
89905
|
-
listFiles_default,
|
|
89906
|
-
readFile_default,
|
|
89907
|
-
readBinaryFile_default,
|
|
89908
|
-
searchFiles_default,
|
|
89909
|
-
readMemory_default,
|
|
89910
|
-
updateMemory_default,
|
|
89911
|
-
listMemoryTopics_default
|
|
89912
|
-
];
|
|
89913
|
-
if (additionalTools.search) {
|
|
89914
|
-
agentTools.push(additionalTools.search);
|
|
89915
|
-
}
|
|
89916
|
-
if (messages) {
|
|
89917
|
-
const userMessage2 = feedback ? [{ role: "user", content: feedback }] : [];
|
|
89918
|
-
return await agentWorkflow({
|
|
89919
|
-
messages,
|
|
89920
|
-
userMessage: userMessage2,
|
|
89921
|
-
tools: agentTools,
|
|
89922
|
-
outputSchema: EpicPlanSchema
|
|
89923
|
-
}, context);
|
|
89924
|
-
}
|
|
89925
|
-
const defaultContext = await getDefaultContext("epic");
|
|
89926
|
-
const memoryContext = await tools3.getMemoryContext();
|
|
89927
|
-
const prompt = `${memoryContext}
|
|
89928
|
-
${getPlanPrompt(task, plan2)}
|
|
89929
|
-
|
|
89930
|
-
${defaultContext}`;
|
|
89931
|
-
const content = [{ type: "text", text: prompt }];
|
|
89932
|
-
if (files) {
|
|
89933
|
-
for (const file2 of files) {
|
|
89934
|
-
if (file2.type === "file") {
|
|
89935
|
-
content.push({
|
|
89936
|
-
type: "file",
|
|
89937
|
-
mediaType: file2.mediaType,
|
|
89938
|
-
filename: file2.filename,
|
|
89939
|
-
data: { type: "base64", value: file2.data }
|
|
89940
|
-
});
|
|
89941
|
-
} else if (file2.type === "image") {
|
|
89942
|
-
content.push({
|
|
89943
|
-
type: "image",
|
|
89944
|
-
mediaType: file2.mediaType,
|
|
89945
|
-
image: { type: "base64", value: file2.image }
|
|
89946
|
-
});
|
|
89947
|
-
}
|
|
89948
|
-
}
|
|
89949
|
-
}
|
|
89950
|
-
const userMessage = [{ role: "user", content }];
|
|
89951
|
-
return await agentWorkflow({
|
|
89952
|
-
systemPrompt: EPIC_PLANNER_SYSTEM_PROMPT,
|
|
89953
|
-
userMessage,
|
|
89954
|
-
tools: agentTools,
|
|
89955
|
-
outputSchema: EpicPlanSchema
|
|
89956
|
-
}, context);
|
|
89957
|
-
}
|
|
89958
|
-
async function createAndApprovePlan(task, context, saveUsageSnapshot, interactive = true, additionalTools) {
|
|
89959
|
-
const { logger, step, tools: tools3 } = context;
|
|
89960
|
-
logger.info(`Phase 2: Creating high-level plan...
|
|
89961
|
-
`);
|
|
89962
|
-
let feedback;
|
|
89963
|
-
let planAttempt = 1;
|
|
89964
|
-
let messages;
|
|
89965
|
-
try {
|
|
89966
|
-
while (true) {
|
|
89967
|
-
const planAgentResult = await step(`plan-${planAttempt}`, () => createPlan2({ task, feedback, messages, additionalTools }, context));
|
|
89968
|
-
messages = planAgentResult.messages;
|
|
89969
|
-
planAttempt++;
|
|
89970
|
-
if (planAgentResult.type !== "Exit") {
|
|
89971
|
-
logger.error(`Plan creation failed. Agent exited with status: ${planAgentResult.type}`);
|
|
89972
|
-
return null;
|
|
89973
|
-
}
|
|
89974
|
-
const result = planAgentResult.object;
|
|
89975
|
-
switch (result.type) {
|
|
89976
|
-
case "plan-generated": {
|
|
89977
|
-
if (!result.plan || !result.branchName) {
|
|
89978
|
-
logger.error("Invalid plan-generated response. Missing plan or branchName.");
|
|
89979
|
-
return null;
|
|
89980
|
-
}
|
|
89981
|
-
logger.info(`Plan:
|
|
89982
|
-
${result.plan}`);
|
|
89983
|
-
logger.info(`Suggested branch name: ${result.branchName}`);
|
|
89984
|
-
if (!interactive) {
|
|
89985
|
-
logger.info("Non-interactive mode: Auto-approving plan.");
|
|
89986
|
-
await saveUsageSnapshot();
|
|
89987
|
-
return { plan: result.plan, branchName: result.branchName };
|
|
89988
|
-
}
|
|
89989
|
-
feedback = await tools3.input({ message: "Press Enter to approve the plan, or provide feedback to refine it." });
|
|
89990
|
-
if (feedback.trim() === "") {
|
|
89991
|
-
logger.info(`High-level plan approved.
|
|
89992
|
-
`);
|
|
89993
|
-
await saveUsageSnapshot();
|
|
89994
|
-
return { plan: result.plan, branchName: result.branchName };
|
|
89995
|
-
}
|
|
89996
|
-
break;
|
|
89997
|
-
}
|
|
89998
|
-
case "question": {
|
|
89999
|
-
if (!result.question) {
|
|
90000
|
-
logger.error("Invalid question response. Missing question object.");
|
|
90001
|
-
return null;
|
|
90002
|
-
}
|
|
90003
|
-
const answer = await tools3.input({
|
|
90004
|
-
message: result.question.question,
|
|
90005
|
-
default: result.question.defaultAnswer || undefined
|
|
90006
|
-
});
|
|
90007
|
-
feedback = `The user answered the question "${result.question.question}" with: "${answer}"`;
|
|
90008
|
-
break;
|
|
90009
|
-
}
|
|
90010
|
-
case "error": {
|
|
90011
|
-
logger.info(`Plan creation failed. Reason: ${result.reason || "Unknown error"}`);
|
|
90012
|
-
return null;
|
|
90013
|
-
}
|
|
90014
|
-
default: {
|
|
90015
|
-
logger.error(`Unknown response type from planner`);
|
|
90016
|
-
return null;
|
|
90017
|
-
}
|
|
90018
|
-
}
|
|
90019
|
-
}
|
|
90020
|
-
} catch (e2) {
|
|
90021
|
-
if (e2 instanceof UserCancelledError) {
|
|
90022
|
-
logger.info("Plan creation cancelled by user.");
|
|
90023
|
-
return null;
|
|
90024
|
-
}
|
|
90025
|
-
throw e2;
|
|
90026
|
-
}
|
|
90027
|
-
}
|
|
90028
|
-
async function createFeatureBranch(branchName, baseBranch, context) {
|
|
90029
|
-
const { logger, step, tools: tools3 } = context;
|
|
90030
|
-
const MAX_ATTEMPTS = 10;
|
|
90031
|
-
let currentBranchName = branchName;
|
|
90032
|
-
logger.info(`Phase 3: Creating/switching to feature branch...
|
|
90033
|
-
`);
|
|
90034
|
-
for (let attempt = 0;attempt < MAX_ATTEMPTS; attempt++) {
|
|
90035
|
-
if (attempt > 0) {
|
|
90036
|
-
currentBranchName = `${branchName}-${attempt}`;
|
|
90037
|
-
}
|
|
90038
|
-
logger.info(`Attempting to use branch name: '${currentBranchName}' (Attempt ${attempt + 1}/${MAX_ATTEMPTS})`);
|
|
90039
|
-
const currentBranchResult = await step(`getCurrentBranch-${attempt}`, async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] }));
|
|
90040
|
-
const onBranch = currentBranchResult.stdout.trim();
|
|
90041
|
-
if (onBranch === currentBranchName) {
|
|
90042
|
-
logger.info(`Already on branch '${currentBranchName}'.`);
|
|
90043
|
-
logger.info(`Successfully on branch '${currentBranchName}'.
|
|
90044
|
-
`);
|
|
90045
|
-
return { success: true, branchName: currentBranchName };
|
|
90046
|
-
}
|
|
90047
|
-
const branchExistsResult = await step(`checkBranchExists-${attempt}`, async () => await tools3.executeCommand({ command: "git", args: ["rev-parse", "--verify", currentBranchName] }));
|
|
90048
|
-
if (branchExistsResult.exitCode === 0) {
|
|
90049
|
-
logger.info(`Branch '${currentBranchName}' already exists. Switching to it...`);
|
|
90050
|
-
const checkoutResult = await step(`checkoutBranch-${attempt}`, async () => await tools3.executeCommand({ command: "git", args: ["checkout", currentBranchName] }));
|
|
90051
|
-
if (checkoutResult.exitCode === 0) {
|
|
90052
|
-
logger.info(`Successfully switched to branch '${currentBranchName}'.
|
|
90053
|
-
`);
|
|
90054
|
-
return { success: true, branchName: currentBranchName };
|
|
90055
|
-
}
|
|
90056
|
-
logger.warn(`Warning: Failed to switch to existing branch '${currentBranchName}'. Git command failed.`);
|
|
90057
|
-
} else {
|
|
90058
|
-
logger.info(`Creating new branch '${currentBranchName}'...`);
|
|
90059
|
-
const createBranchResult = await step(`createBranch-${attempt}`, async () => await tools3.executeCommand({
|
|
90060
|
-
command: "git",
|
|
90061
|
-
args: baseBranch ? ["checkout", "-b", currentBranchName, baseBranch] : ["checkout", "-b", currentBranchName]
|
|
90062
|
-
}));
|
|
90063
|
-
if (createBranchResult.exitCode === 0) {
|
|
90064
|
-
logger.info(`Successfully created and switched to branch '${currentBranchName}'.
|
|
90065
|
-
`);
|
|
90066
|
-
return { success: true, branchName: currentBranchName };
|
|
90067
|
-
}
|
|
90068
|
-
logger.warn(`Warning: Failed to create branch '${currentBranchName}'. Git command failed.`);
|
|
90069
|
-
}
|
|
90070
|
-
}
|
|
90071
|
-
logger.error(`Error: Failed to create or switch to a feature branch after ${MAX_ATTEMPTS} attempts.`);
|
|
90072
|
-
return { success: false, branchName: null };
|
|
90073
|
-
}
|
|
90074
|
-
async function addTodoItemsFromPlan(plan2, context) {
|
|
90075
|
-
const { logger, step, tools: tools3 } = context;
|
|
90076
|
-
logger.info(`Phase 4: Creating todo items from plan...
|
|
90077
|
-
`);
|
|
90078
|
-
await step("add-todo-items", async () => {
|
|
90079
|
-
await agentWorkflow({
|
|
90080
|
-
systemPrompt: EPIC_ADD_TODO_ITEMS_SYSTEM_PROMPT,
|
|
90081
|
-
userMessage: [{ role: "user", content: `Please create the todo items based on the plan
|
|
90082
|
-
<plan>
|
|
90083
|
-
${plan2}</plan>` }],
|
|
90084
|
-
tools: [readFile_default, searchFiles_default, listFiles_default, readMemory_default, getTodoItem_default, listTodoItems_default, updateTodoItem_default, updateMemory_default, listMemoryTopics_default]
|
|
90085
|
-
}, context);
|
|
90086
|
-
});
|
|
90087
|
-
const todos = await tools3.listTodoItems({});
|
|
90088
|
-
logger.info(`Created ${todos.length} todo items.
|
|
90089
|
-
`);
|
|
90090
|
-
}
|
|
90091
|
-
async function runPreflightChecks(epicContext, context) {
|
|
90092
|
-
const { logger, step, tools: tools3 } = context;
|
|
90093
|
-
logger.info(`Phase 1: Running pre-flight checks...
|
|
90094
|
-
`);
|
|
90095
|
-
const gitCheckResult = await step("gitCheck", async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--git-dir"] }));
|
|
90096
|
-
if (gitCheckResult.exitCode !== 0) {
|
|
90097
|
-
logger.error("Error: Git is not initialized in this directory. Please run `git init` first.");
|
|
90098
|
-
logger.info("Suggestion: Run `git init` to initialize a git repository.\n");
|
|
90099
|
-
return false;
|
|
90100
|
-
}
|
|
90101
|
-
if (epicContext.plan) {
|
|
90102
|
-
logger.info("Found an existing `.epic.yml` file.");
|
|
90103
|
-
if (!epicContext.branchName) {
|
|
90104
|
-
throw new Error("Invalid epic context loaded from .epic.yml: branchName is required.");
|
|
90105
|
-
}
|
|
90106
|
-
const currentBranchResult = await step("getCurrentBranch", async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] }));
|
|
90107
|
-
const currentBranch = currentBranchResult.stdout.trim();
|
|
90108
|
-
if (currentBranch !== epicContext.branchName) {
|
|
90109
|
-
throw new Error(`You are on branch '${currentBranch}' but the epic was started on branch '${epicContext.branchName}'. Please switch to the correct branch to resume.`);
|
|
90110
|
-
}
|
|
90111
|
-
logger.info("Resuming previous epic session.");
|
|
90112
|
-
return true;
|
|
90113
|
-
}
|
|
90114
|
-
const gitStatusResult = await step("gitStatus", async () => tools3.executeCommand({ command: "git status --porcelain", shell: true }));
|
|
90115
|
-
if (gitStatusResult.stdout.trim() !== "") {
|
|
90116
|
-
logger.error("Error: Your working directory is not clean. Please stash or commit your changes before running the epic workflow.");
|
|
90117
|
-
logger.info("Suggestion: Run `git add .` and `git commit` to clean your working directory, or `git stash` to temporarily save changes.\n");
|
|
90118
|
-
return false;
|
|
90119
|
-
}
|
|
90120
|
-
const baseBranchResult = await step("getBaseBranch", async () => tools3.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] }));
|
|
90121
|
-
if (baseBranchResult.exitCode === 0 && baseBranchResult.stdout.trim()) {
|
|
90122
|
-
epicContext.baseBranch = baseBranchResult.stdout.trim();
|
|
90123
|
-
logger.info(`Using current branch '${epicContext.baseBranch}' as the base for this epic.`);
|
|
90124
|
-
}
|
|
90125
|
-
logger.info(`Pre-flight checks passed.
|
|
90126
|
-
`);
|
|
90127
|
-
return true;
|
|
90128
|
-
}
|
|
90129
|
-
async function performReviewAndFixCycle(iterationCount, taskItem, highLevelPlan, context, additionalTools) {
|
|
90130
|
-
const { logger, step, tools: tools3 } = context;
|
|
90131
|
-
const commitMessages = [];
|
|
90132
|
-
for (let i2 = 0;i2 < MAX_REVIEW_RETRIES; i2++) {
|
|
90133
|
-
const diffResult = await tools3.executeCommand({ command: "git", args: ["diff", "--name-status", "HEAD~1", "HEAD"] });
|
|
90134
|
-
const changedFiles = parseGitDiffNameStatus(diffResult.stdout).filter(({ path: path3 }) => path3 !== ".epic.yml");
|
|
90135
|
-
if (changedFiles.length === 0) {
|
|
90136
|
-
logger.info(`No files were changed. Skipping review.
|
|
90137
|
-
`);
|
|
90138
|
-
return { passed: true, commitMessages: [] };
|
|
90139
|
-
}
|
|
90140
|
-
logger.info(`
|
|
90141
|
-
Review iteration ${i2 + 1}/${MAX_REVIEW_RETRIES}`);
|
|
90142
|
-
logger.info(` Changed files: ${changedFiles.length}`);
|
|
90143
|
-
const changeInfo = {
|
|
90144
|
-
commitRange: "HEAD~1...HEAD",
|
|
90145
|
-
changedFiles
|
|
90146
|
-
};
|
|
90147
|
-
const reviewAgentResult = await step(`review-${iterationCount}-${i2}`, { retry: 1 }, async () => {
|
|
90148
|
-
const defaultContext = await getDefaultContext("review");
|
|
90149
|
-
const memoryContext = await tools3.getMemoryContext();
|
|
90150
|
-
const userMessage = `${defaultContext}
|
|
90151
|
-
${memoryContext}
|
|
90152
|
-
|
|
90153
|
-
${formatReviewToolInput(changeInfo)}`;
|
|
90154
|
-
return await agentWorkflow({
|
|
90155
|
-
systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
|
|
90156
|
-
userMessage: [{ role: "user", content: userMessage }],
|
|
90157
|
-
tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
|
|
90158
|
-
outputSchema: reviewOutputSchema
|
|
90159
|
-
}, context);
|
|
90160
|
-
});
|
|
90161
|
-
if (reviewAgentResult.type !== "Exit") {
|
|
90162
|
-
logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
|
|
90163
|
-
break;
|
|
90164
|
-
}
|
|
90165
|
-
const reviewResult = reviewAgentResult.object;
|
|
90166
|
-
if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
|
|
90167
|
-
logger.info(`Review passed. No issues found.
|
|
90168
|
-
`);
|
|
90169
|
-
return { passed: true, commitMessages };
|
|
90170
|
-
}
|
|
90171
|
-
logger.warn(`Warning: Review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
|
|
90172
|
-
`);
|
|
90173
|
-
for (const [idx, review2] of reviewResult.specificReviews.entries()) {
|
|
90174
|
-
logger.warn(` ${idx + 1}. ${review2.file}:${review2.lines}`);
|
|
90175
|
-
}
|
|
90176
|
-
logger.warn("");
|
|
90177
|
-
const reviewSummary = reviewResult.specificReviews.map((r2) => `File: ${r2.file} (lines: ${r2.lines})
|
|
90178
|
-
Review: ${r2.review}`).join(`
|
|
90179
|
-
|
|
90180
|
-
`);
|
|
90181
|
-
const fixTask = `You are working on an epic. The original task was: "${taskItem}".
|
|
90182
|
-
|
|
90183
|
-
Here is the full plan for context:
|
|
90184
|
-
<plan>
|
|
90185
|
-
${highLevelPlan}
|
|
90186
|
-
</plan>
|
|
90187
|
-
|
|
90188
|
-
After an initial implementation, a review found the following issues. Please fix them:
|
|
90189
|
-
|
|
90190
|
-
${reviewSummary}`;
|
|
90191
|
-
await step(`fix-${iterationCount}-${i2}`, { retry: 1 }, async () => {
|
|
90192
|
-
await codeWorkflow({
|
|
90193
|
-
task: fixTask,
|
|
90194
|
-
mode: "noninteractive",
|
|
90195
|
-
additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
|
|
90196
|
-
customTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
|
|
90197
|
-
interactive: false,
|
|
90198
|
-
additionalTools
|
|
90199
|
-
}, context);
|
|
90200
|
-
});
|
|
90201
|
-
await step(`commit-fix-${iterationCount}-${i2}`, async () => {
|
|
90202
|
-
const commitMessage = await commitWorkflow({
|
|
90203
|
-
all: true,
|
|
90204
|
-
context: reviewSummary,
|
|
90205
|
-
interactive: false,
|
|
90206
|
-
additionalTools
|
|
90207
|
-
}, context);
|
|
90208
|
-
if (commitMessage) {
|
|
90209
|
-
commitMessages.push(commitMessage);
|
|
90210
|
-
}
|
|
90211
|
-
});
|
|
90212
|
-
if (i2 === MAX_REVIEW_RETRIES - 1) {
|
|
90213
|
-
logger.error(`
|
|
90214
|
-
Max retries (${MAX_REVIEW_RETRIES}) reached. Moving to the next task, but issues might remain.
|
|
90215
|
-
`);
|
|
90216
|
-
return { passed: false, commitMessages };
|
|
90217
|
-
}
|
|
90218
|
-
}
|
|
90219
|
-
return { passed: false, commitMessages };
|
|
90220
|
-
}
|
|
90221
|
-
async function findNextTask(tools3) {
|
|
90222
|
-
const openRootTasks = await tools3.listTodoItems({ status: "open" });
|
|
90223
|
-
if (openRootTasks.length === 0) {
|
|
90224
|
-
return null;
|
|
90225
|
-
}
|
|
90226
|
-
let currentTask = openRootTasks[0];
|
|
90227
|
-
while (true) {
|
|
90228
|
-
const subTasks = await tools3.listTodoItems({ status: "open", id: currentTask.id });
|
|
90229
|
-
if (subTasks.length === 0) {
|
|
90230
|
-
return currentTask;
|
|
90231
|
-
}
|
|
90232
|
-
currentTask = subTasks[0];
|
|
90233
|
-
}
|
|
90234
|
-
}
|
|
90235
|
-
async function runImplementationLoop(context, highLevelPlan, saveUsageSnapshot, additionalTools, noReview) {
|
|
90236
|
-
const { logger, step, tools: tools3 } = context;
|
|
90237
|
-
const commitMessages = [];
|
|
90238
|
-
logger.info(`Phase 5: Iterative Implementation Loop...
|
|
90239
|
-
`);
|
|
90240
|
-
logger.info(`${"=".repeat(80)}
|
|
90241
|
-
`);
|
|
90242
|
-
let iterationCount = 0;
|
|
90243
|
-
let nextTaskItem = await step("get-initial-task", () => findNextTask(tools3));
|
|
90244
|
-
while (nextTaskItem) {
|
|
90245
|
-
iterationCount++;
|
|
90246
|
-
const taskStartTime = Date.now();
|
|
90247
|
-
const { title: nextTask, id: nextTaskId } = nextTaskItem;
|
|
90248
|
-
logger.info(`
|
|
90249
|
-
${"-".repeat(80)}`);
|
|
90250
|
-
logger.info(`Iteration ${iterationCount}`);
|
|
90251
|
-
logger.info(`${"-".repeat(80)}`);
|
|
90252
|
-
logger.info(`${nextTask}
|
|
90253
|
-
`);
|
|
90254
|
-
await step(`task-${iterationCount}`, { retry: 1 }, async () => {
|
|
90255
|
-
const taskWithContext = `You are working on an epic. Here is the full plan:
|
|
90256
|
-
|
|
90257
|
-
<plan>
|
|
90258
|
-
${highLevelPlan}
|
|
90259
|
-
</plan>
|
|
90260
|
-
|
|
90261
|
-
Your current task is to implement this specific item:
|
|
90262
|
-
${nextTask}
|
|
90263
|
-
|
|
90264
|
-
Focus only on this item, but use the plan for context.`;
|
|
90265
|
-
return await codeWorkflow({
|
|
90266
|
-
task: taskWithContext,
|
|
90267
|
-
mode: "noninteractive",
|
|
90268
|
-
additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
|
|
90269
|
-
customTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
|
|
90270
|
-
interactive: false,
|
|
90271
|
-
additionalTools
|
|
90272
|
-
}, context);
|
|
90273
|
-
});
|
|
90274
|
-
const commitMessage = `feat: ${nextTask}`;
|
|
90275
|
-
await step(`commit-initial-${iterationCount}`, async () => {
|
|
90276
|
-
await tools3.executeCommand({ command: "git", args: ["add", "."] });
|
|
90277
|
-
await tools3.executeCommand({ command: "git", args: ["commit", "-m", commitMessage] });
|
|
90278
|
-
});
|
|
90279
|
-
commitMessages.push(commitMessage);
|
|
90280
|
-
if (!noReview) {
|
|
90281
|
-
const { passed: reviewPassed, commitMessages: fixCommitMessages } = await performReviewAndFixCycle(iterationCount, nextTask, highLevelPlan, context, additionalTools);
|
|
90282
|
-
commitMessages.push(...fixCommitMessages);
|
|
90283
|
-
const taskElapsed = Date.now() - taskStartTime;
|
|
90284
|
-
const taskElapsedTime = formatElapsedTime(taskElapsed);
|
|
90285
|
-
if (reviewPassed) {
|
|
90286
|
-
logger.info(`Iteration ${iterationCount} completed successfully (${taskElapsedTime})`);
|
|
90287
|
-
} else {
|
|
90288
|
-
logger.warn(`Warning: Iteration ${iterationCount} completed with potential issues (${taskElapsedTime})`);
|
|
90289
|
-
}
|
|
90290
|
-
} else {
|
|
90291
|
-
const taskElapsed = Date.now() - taskStartTime;
|
|
90292
|
-
const taskElapsedTime = formatElapsedTime(taskElapsed);
|
|
90293
|
-
logger.info(`Iteration ${iterationCount} completed (${taskElapsedTime})`);
|
|
90294
|
-
}
|
|
90295
|
-
await step(`update-task-status-${iterationCount}`, async () => {
|
|
90296
|
-
await tools3.updateTodoItem({ operation: "update", id: nextTaskId, status: "completed" });
|
|
90297
|
-
});
|
|
90298
|
-
nextTaskItem = await step(`get-next-task-${iterationCount}`, () => findNextTask(tools3));
|
|
90299
|
-
const allTodos = await tools3.listTodoItems({});
|
|
90300
|
-
const completedTodos = allTodos.filter((t2) => t2.status === "completed").length;
|
|
90301
|
-
const totalTodos = allTodos.length;
|
|
90302
|
-
let progressMessage = "";
|
|
90303
|
-
if (totalTodos > 0) {
|
|
90304
|
-
progressMessage = `${completedTodos}/${totalTodos} items completed`;
|
|
90305
|
-
} else {
|
|
90306
|
-
progressMessage = `Iteration ${iterationCount} completed`;
|
|
90307
|
-
}
|
|
90308
|
-
logger.info(`
|
|
90309
|
-
Progress: ${progressMessage}`);
|
|
90310
|
-
await saveUsageSnapshot();
|
|
90311
|
-
if (!nextTaskItem) {
|
|
90312
|
-
logger.info(`All tasks complete!
|
|
90313
|
-
`);
|
|
90314
|
-
break;
|
|
90315
|
-
}
|
|
90316
|
-
if (nextTaskItem) {
|
|
90317
|
-
logger.info(`Next task: ${nextTaskItem.title}
|
|
90318
|
-
`);
|
|
90319
|
-
}
|
|
90320
|
-
logger.info(`${"-".repeat(80)}
|
|
90321
|
-
`);
|
|
90322
|
-
}
|
|
90323
|
-
return commitMessages;
|
|
90324
|
-
}
|
|
90325
|
-
async function performFinalReviewAndFix(context, highLevelPlan, baseBranch, additionalTools) {
|
|
90326
|
-
const { logger, step, tools: tools3 } = context;
|
|
90327
|
-
logger.info(`
|
|
90328
|
-
Phase 6: Final Review and Fixup...
|
|
90329
|
-
`);
|
|
90330
|
-
if (!baseBranch) {
|
|
90331
|
-
logger.warn("Warning: Base branch is not defined. Skipping final review step.");
|
|
90332
|
-
return { passed: true };
|
|
90333
|
-
}
|
|
90334
|
-
const currentBranchResult = await tools3.executeCommand({ command: "git", args: ["rev-parse", "--abbrev-ref", "HEAD"] });
|
|
90335
|
-
const currentBranch = currentBranchResult.stdout.trim();
|
|
90336
|
-
if (currentBranch === baseBranch) {
|
|
90337
|
-
logger.info(`You are on the base branch ('${baseBranch}'). No final review needed.`);
|
|
90338
|
-
return { passed: true };
|
|
90339
|
-
}
|
|
90340
|
-
const commitRange = `${baseBranch}...${currentBranch}`;
|
|
90341
|
-
for (let i2 = 0;i2 < MAX_REVIEW_RETRIES; i2++) {
|
|
90342
|
-
const diffResult = await tools3.executeCommand({ command: "git", args: ["diff", "--name-status", commitRange] });
|
|
90343
|
-
const changedFiles = parseGitDiffNameStatus(diffResult.stdout).filter(({ path: path3 }) => path3 !== ".epic.yml");
|
|
90344
|
-
if (changedFiles.length === 0) {
|
|
90345
|
-
logger.info(`No files have been changed in this branch. Skipping final review.
|
|
90346
|
-
`);
|
|
90347
|
-
return { passed: true };
|
|
90348
|
-
}
|
|
90349
|
-
logger.info(`
|
|
90350
|
-
Final review iteration ${i2 + 1}/${MAX_REVIEW_RETRIES}`);
|
|
90351
|
-
logger.info(` Changed files: ${changedFiles.length}`);
|
|
90352
|
-
const changeInfo = {
|
|
90353
|
-
commitRange,
|
|
90354
|
-
changedFiles
|
|
90355
|
-
};
|
|
90356
|
-
const reviewAgentResult = await step(`final-review-${i2}`, async () => {
|
|
90357
|
-
const defaultContext = await getDefaultContext("review");
|
|
90358
|
-
const memoryContext = await tools3.getMemoryContext();
|
|
90359
|
-
const userMessage = `${defaultContext}
|
|
90360
|
-
${memoryContext}
|
|
90361
|
-
|
|
90362
|
-
${formatReviewToolInput(changeInfo)}`;
|
|
90363
|
-
return await agentWorkflow({
|
|
90364
|
-
systemPrompt: CODE_REVIEW_SYSTEM_PROMPT,
|
|
90365
|
-
userMessage: [{ role: "user", content: userMessage }],
|
|
90366
|
-
tools: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
|
|
90367
|
-
outputSchema: reviewOutputSchema
|
|
90368
|
-
}, context);
|
|
90369
|
-
});
|
|
90370
|
-
if (reviewAgentResult.type !== "Exit") {
|
|
90371
|
-
logger.error(`Review agent failed with status: ${reviewAgentResult.type}.`);
|
|
90372
|
-
break;
|
|
90373
|
-
}
|
|
90374
|
-
const reviewResult = reviewAgentResult.object;
|
|
90375
|
-
if (!reviewResult || !reviewResult.specificReviews || reviewResult.specificReviews.length === 0) {
|
|
90376
|
-
logger.info(`Final review passed. No issues found.
|
|
90377
|
-
`);
|
|
90378
|
-
return { passed: true };
|
|
90379
|
-
}
|
|
90380
|
-
logger.warn(`Warning: Final review found ${reviewResult.specificReviews.length} issue(s). Attempting to fix...
|
|
90381
|
-
`);
|
|
90382
|
-
for (const [idx, review2] of reviewResult.specificReviews.entries()) {
|
|
90383
|
-
logger.warn(` ${idx + 1}. ${review2.file}:${review2.lines}`);
|
|
90384
|
-
}
|
|
90385
|
-
logger.warn("");
|
|
90386
|
-
const reviewSummary = reviewResult.specificReviews.map((r2) => `File: ${r2.file} (lines: ${r2.lines})
|
|
90387
|
-
Review: ${r2.review}`).join(`
|
|
90388
|
-
|
|
90389
|
-
`);
|
|
90390
|
-
const fixTask = `You are working on an epic. The original task was to implement a feature based on this plan:
|
|
90391
|
-
|
|
90392
|
-
<plan>
|
|
90393
|
-
${highLevelPlan}
|
|
90394
|
-
</plan>
|
|
90395
|
-
|
|
90396
|
-
A final review of all the changes in the branch found the following issues. Please fix them:
|
|
90397
|
-
|
|
90398
|
-
${reviewSummary}`;
|
|
90399
|
-
await step(`final-fix-${i2}`, async () => {
|
|
90400
|
-
await codeWorkflow({
|
|
90401
|
-
task: fixTask,
|
|
90402
|
-
mode: "noninteractive",
|
|
90403
|
-
additionalInstructions: TODO_HANDLING_INSTRUCTIONS,
|
|
90404
|
-
customTools: [getTodoItem_default, listTodoItems_default, updateTodoItem_default, readMemory_default, updateMemory_default, listMemoryTopics_default],
|
|
90405
|
-
interactive: false,
|
|
90406
|
-
additionalTools
|
|
90407
|
-
}, context);
|
|
90408
|
-
});
|
|
90409
|
-
await step(`commit-final-fix-${i2}`, async () => {
|
|
90410
|
-
await tools3.executeCommand({ command: "git", args: ["add", "."] });
|
|
90411
|
-
await tools3.executeCommand({ command: "git", args: ["commit", "-m", "chore: apply automated review feedback"] });
|
|
90412
|
-
});
|
|
90413
|
-
if (i2 === MAX_REVIEW_RETRIES - 1) {
|
|
90414
|
-
logger.error(`
|
|
90415
|
-
Max retries (${MAX_REVIEW_RETRIES}) reached for final review. Issues might remain.
|
|
90416
|
-
`);
|
|
90417
|
-
return { passed: false };
|
|
90418
|
-
}
|
|
90419
|
-
}
|
|
90420
|
-
return { passed: false };
|
|
90421
|
-
}
|
|
90422
|
-
var MAX_REVIEW_RETRIES = 5, TODO_HANDLING_INSTRUCTIONS = `If you discover that a task is larger than you thought, or that a new task is required, you can add a // TODO comment in the code and create a todo item for it. This will allow you to continue with the current task and address the larger issue later.`, epicWorkflow = async (input, context) => {
|
|
90423
|
-
const { logger, tools: tools3 } = context;
|
|
90424
|
-
const { task, saveEpicContext, saveUsageSnapshot, additionalTools, noReview } = input;
|
|
90425
|
-
const workflowStartTime = Date.now();
|
|
90426
|
-
if (!task || task.trim() === "") {
|
|
90427
|
-
logger.error("Error: Task cannot be empty. Please provide a valid task description.");
|
|
90428
|
-
return;
|
|
90429
|
-
}
|
|
90430
|
-
if (!input.task) {
|
|
90431
|
-
input.task = task;
|
|
90432
|
-
}
|
|
90433
|
-
try {
|
|
90434
|
-
const preflightResult = await runPreflightChecks(input, context);
|
|
90435
|
-
if (!preflightResult) {
|
|
90436
|
-
return;
|
|
90437
|
-
}
|
|
90438
|
-
if (!input.plan) {
|
|
90439
|
-
if (!input.task) {
|
|
90440
|
-
logger.error("Error: Task is missing in epic context. Exiting.");
|
|
90441
|
-
return;
|
|
90442
|
-
}
|
|
90443
|
-
const planResult = await createAndApprovePlan(input.task, context, saveUsageSnapshot, input.interactive, additionalTools);
|
|
90444
|
-
if (!planResult)
|
|
90445
|
-
return;
|
|
90446
|
-
input.plan = planResult.plan;
|
|
90447
|
-
input.branchName = planResult.branchName;
|
|
90448
|
-
await saveEpicContext(input);
|
|
90449
|
-
}
|
|
90450
|
-
if (!input.plan) {
|
|
90451
|
-
logger.error("Error: Plan is missing after planning phase. Exiting.");
|
|
90452
|
-
return;
|
|
90453
|
-
}
|
|
90454
|
-
if (!input.branchName) {
|
|
90455
|
-
logger.error("Error: Branch name is missing after planning phase. Exiting.");
|
|
90456
|
-
return;
|
|
90457
|
-
}
|
|
90458
|
-
const branchResult = await createFeatureBranch(input.branchName, input.baseBranch ?? undefined, context);
|
|
90459
|
-
if (!branchResult.success || !branchResult.branchName)
|
|
90460
|
-
return;
|
|
90461
|
-
if (input.branchName !== branchResult.branchName) {
|
|
90462
|
-
input.branchName = branchResult.branchName;
|
|
90463
|
-
await saveEpicContext(input);
|
|
90464
|
-
}
|
|
90465
|
-
const todos = await tools3.listTodoItems({});
|
|
90466
|
-
if (todos.length === 0) {
|
|
90467
|
-
await addTodoItemsFromPlan(input.plan, context);
|
|
90468
|
-
}
|
|
90469
|
-
const commitMessages = await runImplementationLoop(context, input.plan, saveUsageSnapshot, additionalTools, noReview);
|
|
90470
|
-
if (!noReview) {
|
|
90471
|
-
await performFinalReviewAndFix(context, input.plan, input.baseBranch ?? undefined, additionalTools);
|
|
90472
|
-
}
|
|
90473
|
-
await saveUsageSnapshot();
|
|
90474
|
-
await tools3.executeCommand({ command: "git", args: ["rm", "-f", ".epic.yml"] });
|
|
90475
|
-
const statusResult = await tools3.executeCommand({
|
|
90476
|
-
command: "git",
|
|
90477
|
-
args: ["status", "--porcelain", "--", ".epic.yml"]
|
|
90478
|
-
});
|
|
90479
|
-
if (statusResult.stdout.trim() !== "") {
|
|
90480
|
-
await tools3.executeCommand({ command: "git", args: ["commit", "-m", "chore: remove .epic.yml", "--", ".epic.yml"] });
|
|
90481
|
-
logger.info("Cleaned up .epic.yml file.");
|
|
90482
|
-
}
|
|
90483
|
-
const totalElapsed = Date.now() - workflowStartTime;
|
|
90484
|
-
const totalElapsedTime = formatElapsedTime(totalElapsed);
|
|
90485
|
-
logger.info(`
|
|
90486
|
-
${"=".repeat(80)}`);
|
|
90487
|
-
logger.info("Epic Workflow Complete!");
|
|
90488
|
-
logger.info(`${"=".repeat(80)}`);
|
|
90489
|
-
logger.info(`
|
|
90490
|
-
Summary:`);
|
|
90491
|
-
logger.info(` Branch: ${input.branchName}`);
|
|
90492
|
-
logger.info(` Total time: ${totalElapsedTime}`);
|
|
90493
|
-
logger.info(` Total commits: ${commitMessages.length}`);
|
|
90494
|
-
logger.info("Commits created:");
|
|
90495
|
-
for (const [idx, msg] of commitMessages.entries()) {
|
|
90496
|
-
logger.info(` ${idx + 1}. ${msg}`);
|
|
90497
|
-
}
|
|
90498
|
-
if (input.usages && input.usages.length > 0) {
|
|
90499
|
-
const sortedUsages = [...input.usages].sort((a, b) => a.timestamp - b.timestamp);
|
|
90500
|
-
let lastUsage = {
|
|
90501
|
-
input: 0,
|
|
90502
|
-
output: 0,
|
|
90503
|
-
cachedRead: 0,
|
|
90504
|
-
cost: 0,
|
|
90505
|
-
messageCount: 0
|
|
90506
|
-
};
|
|
90507
|
-
logger.info(`
|
|
90508
|
-
Usage Breakdown:`);
|
|
90509
|
-
sortedUsages.forEach((usage, index) => {
|
|
90510
|
-
const delta = {
|
|
90511
|
-
input: usage.input - lastUsage.input,
|
|
90512
|
-
output: usage.output - lastUsage.output,
|
|
90513
|
-
cachedRead: usage.cachedRead - lastUsage.cachedRead,
|
|
90514
|
-
cost: usage.cost - lastUsage.cost,
|
|
90515
|
-
messageCount: usage.messageCount - lastUsage.messageCount
|
|
90516
|
-
};
|
|
90517
|
-
const tempMeter = new UsageMeter;
|
|
90518
|
-
tempMeter.setUsage(delta);
|
|
90519
|
-
logger.info(` Step ${index + 1}: ${tempMeter.getUsageText()}`);
|
|
90520
|
-
lastUsage = usage;
|
|
90521
|
-
});
|
|
90522
|
-
const last = sortedUsages.at(-1);
|
|
90523
|
-
if (last) {
|
|
90524
|
-
const totalMeter = new UsageMeter;
|
|
90525
|
-
totalMeter.setUsage(last);
|
|
90526
|
-
logger.info(` Total: ${totalMeter.getUsageText()}`);
|
|
90527
|
-
}
|
|
90528
|
-
}
|
|
90529
|
-
} catch (error48) {
|
|
90530
|
-
logger.error(`
|
|
90531
|
-
Epic workflow failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
90532
|
-
if (input?.branchName) {
|
|
90533
|
-
logger.info(`
|
|
90534
|
-
Branch '${input.branchName}' was created but work is incomplete.`);
|
|
90535
|
-
logger.info(`To cleanup: git checkout <previous-branch> && git branch -D ${input.branchName}
|
|
90536
|
-
`);
|
|
90537
|
-
}
|
|
90538
|
-
throw error48;
|
|
90539
|
-
}
|
|
90540
|
-
};
|
|
90541
|
-
var init_epic_workflow = __esm(() => {
|
|
90542
|
-
init_src();
|
|
90543
|
-
init_errors5();
|
|
90544
|
-
init_tools3();
|
|
90545
|
-
init_code_workflow();
|
|
90546
|
-
init_commit_workflow();
|
|
90547
|
-
init_prompts2();
|
|
90548
|
-
init_workflow_utils();
|
|
90549
|
-
});
|
|
90550
|
-
|
|
90551
89795
|
// src/mcp/errors.ts
|
|
90552
89796
|
var McpError, McpConnectionError, McpToolError, McpServerError;
|
|
90553
89797
|
var init_errors6 = __esm(() => {
|
|
@@ -108161,94 +107405,6 @@ var init_sdk_client = __esm(() => {
|
|
|
108161
107405
|
init_errors6();
|
|
108162
107406
|
});
|
|
108163
107407
|
|
|
108164
|
-
// src/workflows/epic-context.ts
|
|
108165
|
-
var exports_epic_context = {};
|
|
108166
|
-
__export(exports_epic_context, {
|
|
108167
|
-
saveEpicContext: () => saveEpicContext,
|
|
108168
|
-
loadEpicContext: () => loadEpicContext,
|
|
108169
|
-
EpicUsageSchema: () => EpicUsageSchema,
|
|
108170
|
-
EpicTodoItemStore: () => EpicTodoItemStore,
|
|
108171
|
-
EpicMemoryStore: () => EpicMemoryStore,
|
|
108172
|
-
EpicContextSchema: () => EpicContextSchema,
|
|
108173
|
-
EPIC_CONTEXT_FILE: () => EPIC_CONTEXT_FILE
|
|
108174
|
-
});
|
|
108175
|
-
import { promises as fs14 } from "node:fs";
|
|
108176
|
-
|
|
108177
|
-
class EpicMemoryStore {
|
|
108178
|
-
#context;
|
|
108179
|
-
constructor(context) {
|
|
108180
|
-
this.#context = context;
|
|
108181
|
-
}
|
|
108182
|
-
async read() {
|
|
108183
|
-
return this.#context.memory ?? {};
|
|
108184
|
-
}
|
|
108185
|
-
async write(data) {
|
|
108186
|
-
this.#context.memory = data;
|
|
108187
|
-
await saveEpicContext(this.#context);
|
|
108188
|
-
}
|
|
108189
|
-
}
|
|
108190
|
-
|
|
108191
|
-
class EpicTodoItemStore {
|
|
108192
|
-
#context;
|
|
108193
|
-
constructor(context) {
|
|
108194
|
-
this.#context = context;
|
|
108195
|
-
}
|
|
108196
|
-
async read() {
|
|
108197
|
-
return this.#context.todos ?? [];
|
|
108198
|
-
}
|
|
108199
|
-
async write(data) {
|
|
108200
|
-
this.#context.todos = data;
|
|
108201
|
-
await saveEpicContext(this.#context);
|
|
108202
|
-
}
|
|
108203
|
-
}
|
|
108204
|
-
var import_yaml5, EPIC_CONTEXT_FILE = ".epic.yml", EpicUsageSchema, EpicContextSchema, saveEpicContext = async (context) => {
|
|
108205
|
-
const yamlString = import_yaml5.stringify({
|
|
108206
|
-
task: context.task,
|
|
108207
|
-
plan: context.plan,
|
|
108208
|
-
branchName: context.branchName,
|
|
108209
|
-
baseBranch: context.baseBranch,
|
|
108210
|
-
todos: context.todos,
|
|
108211
|
-
memory: context.memory,
|
|
108212
|
-
usages: context.usages
|
|
108213
|
-
});
|
|
108214
|
-
await fs14.writeFile(EPIC_CONTEXT_FILE, yamlString, "utf-8");
|
|
108215
|
-
}, loadEpicContext = async () => {
|
|
108216
|
-
let fileContent;
|
|
108217
|
-
try {
|
|
108218
|
-
fileContent = await fs14.readFile(EPIC_CONTEXT_FILE, "utf-8");
|
|
108219
|
-
} catch {
|
|
108220
|
-
return {};
|
|
108221
|
-
}
|
|
108222
|
-
try {
|
|
108223
|
-
const loaded = import_yaml5.parse(fileContent);
|
|
108224
|
-
return EpicContextSchema.parse(loaded);
|
|
108225
|
-
} catch (_error) {
|
|
108226
|
-
return {};
|
|
108227
|
-
}
|
|
108228
|
-
};
|
|
108229
|
-
var init_epic_context = __esm(() => {
|
|
108230
|
-
init_src();
|
|
108231
|
-
init_zod();
|
|
108232
|
-
import_yaml5 = __toESM(require_dist(), 1);
|
|
108233
|
-
EpicUsageSchema = exports_external.object({
|
|
108234
|
-
timestamp: exports_external.number(),
|
|
108235
|
-
input: exports_external.number(),
|
|
108236
|
-
output: exports_external.number(),
|
|
108237
|
-
cachedRead: exports_external.number(),
|
|
108238
|
-
cost: exports_external.number(),
|
|
108239
|
-
messageCount: exports_external.number()
|
|
108240
|
-
});
|
|
108241
|
-
EpicContextSchema = exports_external.object({
|
|
108242
|
-
task: exports_external.string().nullish(),
|
|
108243
|
-
plan: exports_external.string().nullish(),
|
|
108244
|
-
branchName: exports_external.string().nullish(),
|
|
108245
|
-
baseBranch: exports_external.string().nullish(),
|
|
108246
|
-
todos: exports_external.array(TodoItemSchema).nullish(),
|
|
108247
|
-
memory: exports_external.record(exports_external.string(), exports_external.string()).nullish(),
|
|
108248
|
-
usages: exports_external.array(EpicUsageSchema).nullish()
|
|
108249
|
-
});
|
|
108250
|
-
});
|
|
108251
|
-
|
|
108252
107408
|
// src/index.ts
|
|
108253
107409
|
var import_config2 = __toESM(require_config(), 1);
|
|
108254
107410
|
|
|
@@ -108268,7 +107424,7 @@ var {
|
|
|
108268
107424
|
Help
|
|
108269
107425
|
} = import__.default;
|
|
108270
107426
|
// package.json
|
|
108271
|
-
var version = "0.9.
|
|
107427
|
+
var version = "0.9.86";
|
|
108272
107428
|
|
|
108273
107429
|
// src/commands/agent.ts
|
|
108274
107430
|
import { exec as exec3 } from "node:child_process";
|
|
@@ -108929,19 +108085,6 @@ async function adaptCommitWorkflow(input, context) {
|
|
|
108929
108085
|
throw new WorkflowInvocationError("commit", error48 instanceof Error ? error48.message : String(error48), error48 instanceof Error ? error48 : undefined);
|
|
108930
108086
|
}
|
|
108931
108087
|
}
|
|
108932
|
-
async function adaptEpicWorkflow(input, context) {
|
|
108933
|
-
try {
|
|
108934
|
-
const { epicWorkflow: epicWorkflow2 } = await Promise.resolve().then(() => (init_epic_workflow(), exports_epic_workflow));
|
|
108935
|
-
const _result = await epicWorkflow2(input, context);
|
|
108936
|
-
return {
|
|
108937
|
-
success: true,
|
|
108938
|
-
data: null,
|
|
108939
|
-
output: "Epic workflow completed"
|
|
108940
|
-
};
|
|
108941
|
-
} catch (error48) {
|
|
108942
|
-
throw new WorkflowInvocationError("epic", "Epic workflow not available", error48 instanceof Error ? error48 : undefined);
|
|
108943
|
-
}
|
|
108944
|
-
}
|
|
108945
108088
|
async function invokeWorkflow(workflowName, input, context, signal) {
|
|
108946
108089
|
if (signal?.aborted) {
|
|
108947
108090
|
const abortReason = signal.reason ? String(signal.reason) : "Workflow was cancelled before execution";
|
|
@@ -108969,8 +108112,6 @@ async function invokeWorkflow(workflowName, input, context, signal) {
|
|
|
108969
108112
|
return adaptReviewWorkflow(workflowInput, cliContext);
|
|
108970
108113
|
case "commit":
|
|
108971
108114
|
return adaptCommitWorkflow(workflowInput, cliContext);
|
|
108972
|
-
case "epic":
|
|
108973
|
-
return adaptEpicWorkflow(workflowInput, cliContext);
|
|
108974
108115
|
default:
|
|
108975
108116
|
throw new WorkflowInvocationError(workflowName, `Unknown workflow: ${workflowName}`);
|
|
108976
108117
|
}
|
|
@@ -112417,19 +111558,6 @@ var createLogger = (options) => {
|
|
|
112417
111558
|
};
|
|
112418
111559
|
};
|
|
112419
111560
|
|
|
112420
|
-
// src/utils/shell.ts
|
|
112421
|
-
function isWindows() {
|
|
112422
|
-
return process.platform === "win32";
|
|
112423
|
-
}
|
|
112424
|
-
function quoteForShell(str) {
|
|
112425
|
-
if (isWindows()) {
|
|
112426
|
-
const escaped = str.replace(/"/g, '""');
|
|
112427
|
-
return `"${escaped}"`;
|
|
112428
|
-
} else {
|
|
112429
|
-
return `'${str.replace(/'/g, "'\\''")}'`;
|
|
112430
|
-
}
|
|
112431
|
-
}
|
|
112432
|
-
|
|
112433
111561
|
// src/commands/agent.ts
|
|
112434
111562
|
async function runAgent(goal, options, _command) {
|
|
112435
111563
|
console.log("\uD83E\uDD16 Polka Agent");
|
|
@@ -112464,6 +111592,13 @@ async function runAgent(goal, options, _command) {
|
|
|
112464
111592
|
});
|
|
112465
111593
|
return { exitCode: 0, stdout, stderr };
|
|
112466
111594
|
} catch (error48) {
|
|
111595
|
+
if (error48.errno === "ENOBUFS" || error48.code === "ENOBUFS") {
|
|
111596
|
+
return {
|
|
111597
|
+
exitCode: 1,
|
|
111598
|
+
stdout: error48.stdout || "",
|
|
111599
|
+
stderr: `Command output exceeded buffer limit (10MB). The command produced too much output. Try using different arguments or redirecting output to a file. Original error: ${error48.message}`
|
|
111600
|
+
};
|
|
111601
|
+
}
|
|
112467
111602
|
return {
|
|
112468
111603
|
exitCode: error48.code || 1,
|
|
112469
111604
|
stdout: error48.stdout || "",
|
|
@@ -112548,9 +111683,6 @@ var agentCommand = new Command("agent").description("Run autonomous agent (exper
|
|
|
112548
111683
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
112549
111684
|
init_mime_types();
|
|
112550
111685
|
|
|
112551
|
-
// src/api.ts
|
|
112552
|
-
init_src3();
|
|
112553
|
-
|
|
112554
111686
|
// src/runWorkflow.ts
|
|
112555
111687
|
init_src3();
|
|
112556
111688
|
init_src();
|
|
@@ -112671,7 +111803,7 @@ function getProviderOptions(options) {
|
|
|
112671
111803
|
init_errors6();
|
|
112672
111804
|
|
|
112673
111805
|
// src/mcp/manager.ts
|
|
112674
|
-
|
|
111806
|
+
init_src();
|
|
112675
111807
|
|
|
112676
111808
|
// src/mcp/client.ts
|
|
112677
111809
|
async function createMcpClient(serverName, config4) {
|
|
@@ -112810,7 +111942,7 @@ class McpManager {
|
|
|
112810
111942
|
for (const [fullToolName, { tool: tool3 }] of this.tools.entries()) {
|
|
112811
111943
|
let zodSchema2;
|
|
112812
111944
|
try {
|
|
112813
|
-
zodSchema2 =
|
|
111945
|
+
zodSchema2 = convertJsonSchemaToZod(tool3.inputSchema);
|
|
112814
111946
|
} catch (error48) {
|
|
112815
111947
|
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
112816
111948
|
if (this.logger) {
|
|
@@ -112850,68 +111982,6 @@ class McpManager {
|
|
|
112850
111982
|
}
|
|
112851
111983
|
return toolInfos;
|
|
112852
111984
|
}
|
|
112853
|
-
jsonSchemaToZod(schema) {
|
|
112854
|
-
const properties = {};
|
|
112855
|
-
const required2 = [];
|
|
112856
|
-
if (schema.properties && typeof schema.properties === "object") {
|
|
112857
|
-
for (const [propName, propSchema] of Object.entries(schema.properties)) {
|
|
112858
|
-
const propDef = propSchema;
|
|
112859
|
-
properties[propName] = this.convertProperty(propDef);
|
|
112860
|
-
}
|
|
112861
|
-
}
|
|
112862
|
-
if (Array.isArray(schema.required)) {
|
|
112863
|
-
required2.push(...schema.required);
|
|
112864
|
-
}
|
|
112865
|
-
const finalSchema = {};
|
|
112866
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
112867
|
-
if (required2.includes(key)) {
|
|
112868
|
-
finalSchema[key] = value;
|
|
112869
|
-
} else {
|
|
112870
|
-
finalSchema[key] = value.optional();
|
|
112871
|
-
}
|
|
112872
|
-
}
|
|
112873
|
-
return exports_external.object(finalSchema);
|
|
112874
|
-
}
|
|
112875
|
-
convertProperty(propDef) {
|
|
112876
|
-
const type = propDef.type;
|
|
112877
|
-
if (propDef.enum && Array.isArray(propDef.enum)) {
|
|
112878
|
-
const enumValues = propDef.enum;
|
|
112879
|
-
if (enumValues.length > 0 && enumValues.every((v) => typeof v === "string")) {
|
|
112880
|
-
return exports_external.enum(enumValues);
|
|
112881
|
-
}
|
|
112882
|
-
}
|
|
112883
|
-
if (propDef.const !== undefined) {
|
|
112884
|
-
const constValue = propDef.const;
|
|
112885
|
-
if (typeof constValue === "string" || typeof constValue === "number" || typeof constValue === "boolean" || constValue === null) {
|
|
112886
|
-
return exports_external.literal(constValue);
|
|
112887
|
-
}
|
|
112888
|
-
}
|
|
112889
|
-
switch (type) {
|
|
112890
|
-
case "string":
|
|
112891
|
-
return exports_external.string();
|
|
112892
|
-
case "number":
|
|
112893
|
-
case "integer":
|
|
112894
|
-
return exports_external.number();
|
|
112895
|
-
case "boolean":
|
|
112896
|
-
return exports_external.boolean();
|
|
112897
|
-
case "array":
|
|
112898
|
-
if (propDef.items && typeof propDef.items === "object") {
|
|
112899
|
-
const itemsSchema = this.convertProperty(propDef.items);
|
|
112900
|
-
return exports_external.array(itemsSchema);
|
|
112901
|
-
}
|
|
112902
|
-
return exports_external.array(exports_external.any());
|
|
112903
|
-
case "object":
|
|
112904
|
-
if (propDef.properties && typeof propDef.properties === "object") {
|
|
112905
|
-
return this.jsonSchemaToZod(propDef);
|
|
112906
|
-
}
|
|
112907
|
-
return exports_external.record(exports_external.string(), exports_external.any());
|
|
112908
|
-
default:
|
|
112909
|
-
if (this.logger) {
|
|
112910
|
-
this.logger.warn(`Unsupported JSON Schema type: ${type}, falling back to z.any(). Tools should validate their inputs.`);
|
|
112911
|
-
}
|
|
112912
|
-
return exports_external.any();
|
|
112913
|
-
}
|
|
112914
|
-
}
|
|
112915
111985
|
}
|
|
112916
111986
|
|
|
112917
111987
|
// src/options.ts
|
|
@@ -113601,7 +112671,7 @@ async function runWorkflow(workflow2, workflowInput, options) {
|
|
|
113601
112671
|
throw new Error(`No provider configured for command: ${commandName}`);
|
|
113602
112672
|
}
|
|
113603
112673
|
const model = getModel(commandConfig);
|
|
113604
|
-
const excludeFiles = [
|
|
112674
|
+
const excludeFiles = [...config4.excludeFiles ?? []];
|
|
113605
112675
|
const toolProvider = (options.getProvider ?? getProvider)({
|
|
113606
112676
|
excludeFiles,
|
|
113607
112677
|
yes: context.yes,
|
|
@@ -113810,7 +112880,6 @@ var initWorkflow = async (input2, context) => {
|
|
|
113810
112880
|
init_src();
|
|
113811
112881
|
init_zod();
|
|
113812
112882
|
init_code_workflow();
|
|
113813
|
-
init_epic_workflow();
|
|
113814
112883
|
init_prompts2();
|
|
113815
112884
|
|
|
113816
112885
|
// src/workflows/task.workflow.ts
|
|
@@ -113862,7 +112931,7 @@ Agent finished!
|
|
|
113862
112931
|
|
|
113863
112932
|
// src/workflows/meta.workflow.ts
|
|
113864
112933
|
var DecisionSchema = exports_external.object({
|
|
113865
|
-
workflow: exports_external.enum(["code", "task"
|
|
112934
|
+
workflow: exports_external.enum(["code", "task"])
|
|
113866
112935
|
});
|
|
113867
112936
|
var metaWorkflow = async (input2, context) => {
|
|
113868
112937
|
const { task } = input2;
|
|
@@ -113905,9 +112974,6 @@ Decision: Using '${decision.workflow}' workflow.`);
|
|
|
113905
112974
|
additionalTools: input2.additionalTools
|
|
113906
112975
|
}, context);
|
|
113907
112976
|
break;
|
|
113908
|
-
case "epic":
|
|
113909
|
-
await epicWorkflow(input2, context);
|
|
113910
|
-
break;
|
|
113911
112977
|
default:
|
|
113912
112978
|
throw new Error(`Unknown workflow: ${decision.workflow}`);
|
|
113913
112979
|
}
|
|
@@ -113976,14 +113042,13 @@ init_review_workflow();
|
|
|
113976
113042
|
init_workflow_utils();
|
|
113977
113043
|
|
|
113978
113044
|
// src/api.ts
|
|
113979
|
-
init_epic_workflow();
|
|
113980
|
-
init_epic_context();
|
|
113981
113045
|
async function commit3(options = {}) {
|
|
113982
|
-
const { all, context: messageContext, interactive, onUsage, ...context } = options;
|
|
113046
|
+
const { all, files, context: messageContext, interactive, onUsage, ...context } = options;
|
|
113983
113047
|
const verbose = context.silent ? -1 : context.verbose ?? 0;
|
|
113984
113048
|
const logger = createLogger({ verbose });
|
|
113985
113049
|
const workflowInput = {
|
|
113986
113050
|
...all && { all: true },
|
|
113051
|
+
...files && { files },
|
|
113987
113052
|
...messageContext && { context: messageContext },
|
|
113988
113053
|
interactive: interactive !== false
|
|
113989
113054
|
};
|
|
@@ -114083,46 +113148,6 @@ async function plan3(options = {}) {
|
|
|
114083
113148
|
onUsageMeterCreated: onUsage
|
|
114084
113149
|
});
|
|
114085
113150
|
}
|
|
114086
|
-
async function epic2(options = {}) {
|
|
114087
|
-
const { task: task2, noReview, interactive, onUsage, getProvider: getProvider2, _workflowInput, _saveEpicContext, _saveUsageSnapshot, ...context } = options;
|
|
114088
|
-
const verbose = context.silent ? -1 : context.verbose ?? 0;
|
|
114089
|
-
const logger = createLogger({ verbose });
|
|
114090
|
-
let epicContext = _workflowInput;
|
|
114091
|
-
if (!epicContext) {
|
|
114092
|
-
const { loadEpicContext: loadEpicContext2 } = await Promise.resolve().then(() => (init_epic_context(), exports_epic_context));
|
|
114093
|
-
epicContext = await loadEpicContext2();
|
|
114094
|
-
}
|
|
114095
|
-
if (task2 && epicContext.task) {
|
|
114096
|
-
throw new Error("Existing epic context found, but task was provided. Exiting.");
|
|
114097
|
-
}
|
|
114098
|
-
if (task2) {
|
|
114099
|
-
epicContext.task = task2;
|
|
114100
|
-
}
|
|
114101
|
-
const providerGetter = getProvider2 || ((opt) => getProvider({
|
|
114102
|
-
...opt,
|
|
114103
|
-
todoItemStore: new EpicTodoItemStore(epicContext),
|
|
114104
|
-
memoryStore: new EpicMemoryStore(epicContext)
|
|
114105
|
-
}));
|
|
114106
|
-
const workflowInput = {
|
|
114107
|
-
...epicContext,
|
|
114108
|
-
interactive: interactive !== false,
|
|
114109
|
-
noReview: noReview ?? false,
|
|
114110
|
-
saveEpicContext: _saveEpicContext || (async (ctx) => {
|
|
114111
|
-
Object.assign(epicContext, ctx);
|
|
114112
|
-
const { saveEpicContext: saveEpicContext2 } = await Promise.resolve().then(() => (init_epic_context(), exports_epic_context));
|
|
114113
|
-
await saveEpicContext2(epicContext);
|
|
114114
|
-
}),
|
|
114115
|
-
saveUsageSnapshot: _saveUsageSnapshot || (async () => {})
|
|
114116
|
-
};
|
|
114117
|
-
await runWorkflow(epicWorkflow, workflowInput, {
|
|
114118
|
-
commandName: "epic",
|
|
114119
|
-
context,
|
|
114120
|
-
logger,
|
|
114121
|
-
onUsageMeterCreated: onUsage,
|
|
114122
|
-
getProvider: providerGetter,
|
|
114123
|
-
interactive: interactive !== false
|
|
114124
|
-
});
|
|
114125
|
-
}
|
|
114126
113151
|
|
|
114127
113152
|
// src/commands/code.ts
|
|
114128
113153
|
var readStdin = async (timeoutMs = 1000) => {
|
|
@@ -114218,87 +113243,11 @@ var commitCommand = new Command("commit").description("Create a commit with AI-g
|
|
|
114218
113243
|
await commit3({
|
|
114219
113244
|
all: localOptions.all,
|
|
114220
113245
|
context: message,
|
|
114221
|
-
|
|
114222
|
-
|
|
113246
|
+
files: globalOpts.file,
|
|
113247
|
+
interactive: !globalOpts.yes
|
|
114223
113248
|
});
|
|
114224
113249
|
});
|
|
114225
113250
|
|
|
114226
|
-
// src/commands/epic.ts
|
|
114227
|
-
init_src3();
|
|
114228
|
-
init_epic_context();
|
|
114229
|
-
async function runEpic(task2, options, command) {
|
|
114230
|
-
const globalOpts = (command.parent ?? command).opts();
|
|
114231
|
-
const { verbose } = globalOpts;
|
|
114232
|
-
const { review: review3 } = options;
|
|
114233
|
-
const logger = createLogger({
|
|
114234
|
-
verbose
|
|
114235
|
-
});
|
|
114236
|
-
let taskInput = task2;
|
|
114237
|
-
const epicContext = await loadEpicContext();
|
|
114238
|
-
if (epicContext.task) {
|
|
114239
|
-
if (taskInput) {
|
|
114240
|
-
logger.error("Error: Existing epic context found, but task was provided via CLI args. Exiting.");
|
|
114241
|
-
return;
|
|
114242
|
-
}
|
|
114243
|
-
logger.info("Resuming existing epic session. Task:");
|
|
114244
|
-
logger.info(` ${epicContext.task}`);
|
|
114245
|
-
} else {
|
|
114246
|
-
if (!taskInput) {
|
|
114247
|
-
taskInput = await getUserInput("What feature do you want to implement?");
|
|
114248
|
-
if (!taskInput) {
|
|
114249
|
-
logger.info("No task provided. Exiting.");
|
|
114250
|
-
return;
|
|
114251
|
-
}
|
|
114252
|
-
}
|
|
114253
|
-
}
|
|
114254
|
-
let usageMeter;
|
|
114255
|
-
try {
|
|
114256
|
-
await epic2({
|
|
114257
|
-
task: taskInput,
|
|
114258
|
-
noReview: review3 === false,
|
|
114259
|
-
interactive: !globalOpts.yes,
|
|
114260
|
-
onUsage: (meter) => {
|
|
114261
|
-
usageMeter = meter;
|
|
114262
|
-
},
|
|
114263
|
-
...globalOpts,
|
|
114264
|
-
getProvider: (opt) => getProvider({
|
|
114265
|
-
...opt,
|
|
114266
|
-
todoItemStore: new EpicTodoItemStore(epicContext),
|
|
114267
|
-
memoryStore: new EpicMemoryStore(epicContext)
|
|
114268
|
-
}),
|
|
114269
|
-
_workflowInput: epicContext,
|
|
114270
|
-
_saveEpicContext: async (context) => {
|
|
114271
|
-
if (context.task)
|
|
114272
|
-
epicContext.task = context.task;
|
|
114273
|
-
if (context.plan)
|
|
114274
|
-
epicContext.plan = context.plan;
|
|
114275
|
-
if (context.branchName)
|
|
114276
|
-
epicContext.branchName = context.branchName;
|
|
114277
|
-
if (context.baseBranch)
|
|
114278
|
-
epicContext.baseBranch = context.baseBranch;
|
|
114279
|
-
await saveEpicContext(epicContext);
|
|
114280
|
-
},
|
|
114281
|
-
_saveUsageSnapshot: async () => {
|
|
114282
|
-
if (usageMeter) {
|
|
114283
|
-
const currentUsage = usageMeter.usage;
|
|
114284
|
-
if (!epicContext.usages) {
|
|
114285
|
-
epicContext.usages = [];
|
|
114286
|
-
}
|
|
114287
|
-
epicContext.usages.push({ ...currentUsage, timestamp: Date.now() });
|
|
114288
|
-
await saveEpicContext(epicContext);
|
|
114289
|
-
}
|
|
114290
|
-
}
|
|
114291
|
-
});
|
|
114292
|
-
} catch (error48) {
|
|
114293
|
-
if (error48 instanceof Error && error48.message.includes("Existing epic context found")) {
|
|
114294
|
-
logger.error(`Error: ${error48.message}`);
|
|
114295
|
-
return;
|
|
114296
|
-
}
|
|
114297
|
-
throw error48;
|
|
114298
|
-
}
|
|
114299
|
-
}
|
|
114300
|
-
var epicCommand = new Command("epic").description("Orchestrates a large feature or epic, breaking it down into smaller tasks.").argument("[task]", "The epic to plan and implement.").option("--no-review", "Disable the review step").action(runEpic);
|
|
114301
|
-
|
|
114302
113251
|
// src/commands/fix.ts
|
|
114303
113252
|
var fixCommand = new Command("fix").description("Fix issues by running a command and letting an agent fix it.").argument("[command]", "The command to run").option("-p, --prompt <prompt>", "Additional prompt for the agent.").action(async (commandArg, options, cmd) => {
|
|
114304
113253
|
const globalOpts = (cmd.parent ?? cmd).opts();
|
|
@@ -114316,7 +113265,7 @@ init_src3();
|
|
|
114316
113265
|
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
114317
113266
|
import { join as join13 } from "node:path";
|
|
114318
113267
|
init_lodash();
|
|
114319
|
-
var
|
|
113268
|
+
var import_yaml5 = __toESM(require_dist(), 1);
|
|
114320
113269
|
|
|
114321
113270
|
// src/builtin-commands.ts
|
|
114322
113271
|
var BUILT_IN_COMMANDS = ["code", "commit", "pr", "review", "fix", "plan", "workflow", "run", "init", "meta", "skills"];
|
|
@@ -114701,7 +113650,7 @@ var initCommand = new Command("init").description("Initialize polkacodes configu
|
|
|
114701
113650
|
case "global": {
|
|
114702
113651
|
const globalConfig2 = loadConfigAtPath(globalConfigPath) ?? {};
|
|
114703
113652
|
set_default(globalConfig2, ["providers", provider3, "apiKey"], apiKey);
|
|
114704
|
-
writeFileSync(globalConfigPath,
|
|
113653
|
+
writeFileSync(globalConfigPath, import_yaml5.stringify(globalConfig2));
|
|
114705
113654
|
logger.info(`API key saved to global config file: ${globalConfigPath}`);
|
|
114706
113655
|
providerConfig.apiKey = undefined;
|
|
114707
113656
|
break;
|
|
@@ -114736,7 +113685,7 @@ var initCommand = new Command("init").description("Initialize polkacodes configu
|
|
|
114736
113685
|
if (providerConfig.apiKey) {
|
|
114737
113686
|
set_default(finalConfig, ["providers", provider3, "apiKey"], providerConfig.apiKey);
|
|
114738
113687
|
}
|
|
114739
|
-
writeFileSync(configPath,
|
|
113688
|
+
writeFileSync(configPath, import_yaml5.stringify(finalConfig));
|
|
114740
113689
|
logger.info(`Configuration saved to ${configPath}`);
|
|
114741
113690
|
let shouldAnalyze = false;
|
|
114742
113691
|
if (!isGlobal && interactive) {
|
|
@@ -116078,7 +115027,12 @@ function createExecutionContext(_logger) {
|
|
|
116078
115027
|
async function executeWorkflow(workflow3, input2, commandName, logger) {
|
|
116079
115028
|
try {
|
|
116080
115029
|
const context = createExecutionContext(logger);
|
|
116081
|
-
const
|
|
115030
|
+
const workflowInput = {
|
|
115031
|
+
...input2,
|
|
115032
|
+
interactive: false,
|
|
115033
|
+
additionalTools: {}
|
|
115034
|
+
};
|
|
115035
|
+
const result = await runWorkflow(workflow3, workflowInput, {
|
|
116082
115036
|
commandName,
|
|
116083
115037
|
context,
|
|
116084
115038
|
logger,
|
|
@@ -116086,7 +115040,7 @@ async function executeWorkflow(workflow3, input2, commandName, logger) {
|
|
|
116086
115040
|
interactive: false
|
|
116087
115041
|
});
|
|
116088
115042
|
if (!result) {
|
|
116089
|
-
return "Workflow
|
|
115043
|
+
return "Error: Workflow returned no result (possible internal error or workflow produced no output)";
|
|
116090
115044
|
}
|
|
116091
115045
|
if (typeof result === "string") {
|
|
116092
115046
|
return result;
|
|
@@ -116127,16 +115081,14 @@ The workflow will:
|
|
|
116127
115081
|
Best used for implementing new features, refactoring existing code, fixing bugs across multiple files, adding tests, or code modernization.
|
|
116128
115082
|
|
|
116129
115083
|
Parameters:
|
|
116130
|
-
- task (required): Detailed description of what needs to be implemented or changed
|
|
116131
|
-
- files (optional): Specific file paths to focus on. When provided, the AI will primarily analyze and modify these files`,
|
|
115084
|
+
- task (required): Detailed description of what needs to be implemented or changed`,
|
|
116132
115085
|
inputSchema: exports_external.object({
|
|
116133
|
-
task: exports_external.string().describe("The coding task to execute - be specific about what needs to be done")
|
|
116134
|
-
files: exports_external.array(exports_external.string()).optional().describe("Specific files to focus on (optional)")
|
|
115086
|
+
task: exports_external.string().describe("The coding task to execute - be specific about what needs to be done")
|
|
116135
115087
|
}),
|
|
116136
115088
|
handler: async (args) => {
|
|
116137
|
-
const { task: task2
|
|
116138
|
-
logger.info(`MCP: Executing code workflow - task: "${task2}"
|
|
116139
|
-
return await executeWorkflow(codeWorkflow, { task: task2
|
|
115089
|
+
const { task: task2 } = args;
|
|
115090
|
+
logger.info(`MCP: Executing code workflow - task: "${task2}"`);
|
|
115091
|
+
return await executeWorkflow(codeWorkflow, { task: task2 }, "code", logger);
|
|
116140
115092
|
}
|
|
116141
115093
|
},
|
|
116142
115094
|
{
|
|
@@ -116291,57 +115243,12 @@ Parameters:
|
|
|
116291
115243
|
return await executeWorkflow(fixWorkflow, { task: task2 }, "fix", logger);
|
|
116292
115244
|
}
|
|
116293
115245
|
},
|
|
116294
|
-
{
|
|
116295
|
-
name: "epic",
|
|
116296
|
-
description: `Break down large features into manageable tasks and implement them systematically.
|
|
116297
|
-
|
|
116298
|
-
The workflow will:
|
|
116299
|
-
- Take a high-level feature or goal description
|
|
116300
|
-
- Decompose it into smaller, concrete tasks
|
|
116301
|
-
- Create an ordered todo list with clear definitions
|
|
116302
|
-
- Implement tasks sequentially, handling dependencies
|
|
116303
|
-
- Track progress and provide summaries after each task
|
|
116304
|
-
- Continue until the entire epic is complete
|
|
116305
|
-
|
|
116306
|
-
Process:
|
|
116307
|
-
1. Understand epic requirements and constraints
|
|
116308
|
-
2. Break down into specific, actionable tasks
|
|
116309
|
-
3. Create and prioritize the todo list
|
|
116310
|
-
4. For each task:
|
|
116311
|
-
- Analyze what needs to be done
|
|
116312
|
-
- Make necessary code changes
|
|
116313
|
-
- Test and verify the implementation
|
|
116314
|
-
- Mark task complete and move to next
|
|
116315
|
-
5. Provide final completion summary
|
|
116316
|
-
|
|
116317
|
-
Best used for large features, multi-component implementations, or complex refactoring projects that span multiple files or modules.
|
|
116318
|
-
|
|
116319
|
-
Parameters:
|
|
116320
|
-
- epic (required): High-level description of the epic/feature to implement`,
|
|
116321
|
-
inputSchema: exports_external.object({
|
|
116322
|
-
epic: exports_external.string().describe("Description of the epic to implement - describe the overall feature or goal, not specific implementation steps")
|
|
116323
|
-
}),
|
|
116324
|
-
handler: async (args) => {
|
|
116325
|
-
const { epic: epicTask } = args;
|
|
116326
|
-
logger.info(`MCP: Executing epic workflow - epic: "${epicTask}"`);
|
|
116327
|
-
try {
|
|
116328
|
-
await epic2({
|
|
116329
|
-
...createExecutionContext(logger),
|
|
116330
|
-
task: epicTask,
|
|
116331
|
-
interactive: false
|
|
116332
|
-
});
|
|
116333
|
-
return "Epic workflow completed successfully";
|
|
116334
|
-
} catch (error48) {
|
|
116335
|
-
return `Error: ${error48 instanceof Error ? error48.message : String(error48)}`;
|
|
116336
|
-
}
|
|
116337
|
-
}
|
|
116338
|
-
},
|
|
116339
115246
|
{
|
|
116340
115247
|
name: "commit",
|
|
116341
115248
|
description: `Create a git commit with an AI-generated, well-formatted commit message.
|
|
116342
115249
|
|
|
116343
115250
|
The workflow will:
|
|
116344
|
-
- Stage
|
|
115251
|
+
- Stage specified files (all files or specific files)
|
|
116345
115252
|
- Analyze the diff to understand what changed
|
|
116346
115253
|
- Generate a clear, descriptive commit message following best practices
|
|
116347
115254
|
- Create the commit with the generated message
|
|
@@ -116359,17 +115266,21 @@ Best practices followed:
|
|
|
116359
115266
|
- Wrap body lines at 72 characters
|
|
116360
115267
|
|
|
116361
115268
|
Parameters:
|
|
116362
|
-
- message (optional): Custom commit message. If not provided, AI analyzes changes and generates an appropriate message following best practices
|
|
115269
|
+
- message (optional): Custom commit message. If not provided, AI analyzes changes and generates an appropriate message following best practices
|
|
115270
|
+
- stageFiles (optional): Files to stage before committing. Use "all" to stage all files, or provide an array of specific file paths to stage`,
|
|
116363
115271
|
inputSchema: exports_external.object({
|
|
116364
|
-
message: exports_external.string().optional().describe("Optional commit message - if not provided, AI will analyze changes and generate an appropriate message")
|
|
115272
|
+
message: exports_external.string().optional().describe("Optional commit message - if not provided, AI will analyze changes and generate an appropriate message"),
|
|
115273
|
+
stageFiles: exports_external.union([exports_external.literal("all"), exports_external.array(exports_external.string())]).optional().describe('Files to stage: "all" for all files, or array of specific file paths')
|
|
116365
115274
|
}),
|
|
116366
115275
|
handler: async (args) => {
|
|
116367
|
-
const { message } = args;
|
|
116368
|
-
logger.info(`MCP: Executing commit workflow${message ? ` - message: "${message}"` : ""}`);
|
|
115276
|
+
const { message, stageFiles } = args;
|
|
115277
|
+
logger.info(`MCP: Executing commit workflow${message ? ` - message: "${message}"` : ""}${stageFiles ? ` - stageFiles: "${JSON.stringify(stageFiles)}"` : ""}`);
|
|
116369
115278
|
try {
|
|
116370
115279
|
await commit3({
|
|
116371
115280
|
...createExecutionContext(logger),
|
|
116372
115281
|
context: message,
|
|
115282
|
+
all: stageFiles === "all",
|
|
115283
|
+
files: Array.isArray(stageFiles) ? stageFiles : undefined,
|
|
116373
115284
|
interactive: false
|
|
116374
115285
|
});
|
|
116375
115286
|
return "Commit created successfully";
|
|
@@ -116498,9 +115409,9 @@ function validateScriptPermissions(script, logger) {
|
|
|
116498
115409
|
}
|
|
116499
115410
|
if ("script" in script && script.permissions) {
|
|
116500
115411
|
logger?.warn("Script permissions are currently advisory only. Scripts run with full process permissions.");
|
|
116501
|
-
const { fs:
|
|
116502
|
-
if (
|
|
116503
|
-
throw new ScriptValidationError(`Invalid fs permission: ${
|
|
115412
|
+
const { fs: fs14, network, subprocess } = script.permissions;
|
|
115413
|
+
if (fs14 && !["read", "write", "none"].includes(fs14)) {
|
|
115414
|
+
throw new ScriptValidationError(`Invalid fs permission: ${fs14}. Must be 'read', 'write', or 'none'`);
|
|
116504
115415
|
}
|
|
116505
115416
|
if (typeof network !== "boolean" && network !== undefined) {
|
|
116506
115417
|
throw new ScriptValidationError(`Invalid network permission: must be true or false`);
|
|
@@ -116665,56 +115576,12 @@ async function executeScript(script, name18, logger, args = []) {
|
|
|
116665
115576
|
}
|
|
116666
115577
|
|
|
116667
115578
|
// src/commands/meta.ts
|
|
116668
|
-
init_epic_context();
|
|
116669
115579
|
async function runMeta(task2, command) {
|
|
116670
115580
|
const globalOpts = (command.parent ?? command).opts();
|
|
116671
115581
|
const { verbose } = globalOpts;
|
|
116672
115582
|
const logger = createLogger({
|
|
116673
115583
|
verbose
|
|
116674
115584
|
});
|
|
116675
|
-
const epicContext = await loadEpicContext();
|
|
116676
|
-
if (epicContext.task) {
|
|
116677
|
-
if (task2) {
|
|
116678
|
-
logger.error("Error: Existing epic context found.");
|
|
116679
|
-
logger.info(`Current task: ${epicContext.task}`);
|
|
116680
|
-
logger.info('Use "polka epic --clear" to start a new task.');
|
|
116681
|
-
return;
|
|
116682
|
-
}
|
|
116683
|
-
logger.info("Resuming existing epic session. Task:");
|
|
116684
|
-
logger.info(` ${epicContext.task}`);
|
|
116685
|
-
let usageMeter2;
|
|
116686
|
-
const saveUsageSnapshot2 = async () => {
|
|
116687
|
-
if (usageMeter2) {
|
|
116688
|
-
const currentUsage = usageMeter2.usage;
|
|
116689
|
-
if (!epicContext.usages) {
|
|
116690
|
-
epicContext.usages = [];
|
|
116691
|
-
}
|
|
116692
|
-
epicContext.usages.push({ ...currentUsage, timestamp: Date.now() });
|
|
116693
|
-
}
|
|
116694
|
-
};
|
|
116695
|
-
const workflowInput2 = {
|
|
116696
|
-
...epicContext,
|
|
116697
|
-
async saveEpicContext(context) {
|
|
116698
|
-
await saveEpicContext(context);
|
|
116699
|
-
},
|
|
116700
|
-
saveUsageSnapshot: saveUsageSnapshot2,
|
|
116701
|
-
interactive: !globalOpts.yes
|
|
116702
|
-
};
|
|
116703
|
-
await runWorkflow(metaWorkflow, workflowInput2, {
|
|
116704
|
-
commandName: "meta",
|
|
116705
|
-
context: globalOpts,
|
|
116706
|
-
logger,
|
|
116707
|
-
onUsageMeterCreated: (meter) => {
|
|
116708
|
-
usageMeter2 = meter;
|
|
116709
|
-
},
|
|
116710
|
-
getProvider: (opt) => getProvider({
|
|
116711
|
-
...opt,
|
|
116712
|
-
todoItemStore: new EpicTodoItemStore(workflowInput2),
|
|
116713
|
-
memoryStore: new EpicMemoryStore(workflowInput2)
|
|
116714
|
-
})
|
|
116715
|
-
});
|
|
116716
|
-
return;
|
|
116717
|
-
}
|
|
116718
115585
|
if (task2) {
|
|
116719
115586
|
const trimmedTask = task2.trim();
|
|
116720
115587
|
const words2 = trimmedTask.split(/\s+/);
|
|
@@ -116744,37 +115611,17 @@ async function runMeta(task2, command) {
|
|
|
116744
115611
|
logger.info(' For tasks: polka "detailed task description"');
|
|
116745
115612
|
return;
|
|
116746
115613
|
}
|
|
116747
|
-
epicContext.task = task2;
|
|
116748
|
-
let usageMeter2;
|
|
116749
|
-
const saveUsageSnapshot2 = async () => {
|
|
116750
|
-
if (usageMeter2) {
|
|
116751
|
-
const currentUsage = usageMeter2.usage;
|
|
116752
|
-
if (!epicContext.usages) {
|
|
116753
|
-
epicContext.usages = [];
|
|
116754
|
-
}
|
|
116755
|
-
epicContext.usages.push({ ...currentUsage, timestamp: Date.now() });
|
|
116756
|
-
}
|
|
116757
|
-
};
|
|
116758
115614
|
const workflowInput2 = {
|
|
116759
|
-
|
|
116760
|
-
|
|
116761
|
-
|
|
116762
|
-
},
|
|
116763
|
-
saveUsageSnapshot: saveUsageSnapshot2,
|
|
116764
|
-
interactive: !globalOpts.yes
|
|
115615
|
+
task: task2,
|
|
115616
|
+
interactive: !globalOpts.yes,
|
|
115617
|
+
additionalTools: {}
|
|
116765
115618
|
};
|
|
116766
115619
|
await runWorkflow(metaWorkflow, workflowInput2, {
|
|
116767
115620
|
commandName: "meta",
|
|
116768
115621
|
context: globalOpts,
|
|
116769
115622
|
logger,
|
|
116770
|
-
|
|
116771
|
-
|
|
116772
|
-
},
|
|
116773
|
-
getProvider: (opt) => getProvider({
|
|
116774
|
-
...opt,
|
|
116775
|
-
todoItemStore: new EpicTodoItemStore(workflowInput2),
|
|
116776
|
-
memoryStore: new EpicMemoryStore(workflowInput2)
|
|
116777
|
-
})
|
|
115623
|
+
requiresProvider: true,
|
|
115624
|
+
interactive: !globalOpts.yes
|
|
116778
115625
|
});
|
|
116779
115626
|
return;
|
|
116780
115627
|
}
|
|
@@ -116801,37 +115648,17 @@ async function runMeta(task2, command) {
|
|
|
116801
115648
|
logger.info(' For tasks: polka "detailed task description"');
|
|
116802
115649
|
return;
|
|
116803
115650
|
}
|
|
116804
|
-
epicContext.task = input2;
|
|
116805
|
-
let usageMeter;
|
|
116806
|
-
const saveUsageSnapshot = async () => {
|
|
116807
|
-
if (usageMeter) {
|
|
116808
|
-
const currentUsage = usageMeter.usage;
|
|
116809
|
-
if (!epicContext.usages) {
|
|
116810
|
-
epicContext.usages = [];
|
|
116811
|
-
}
|
|
116812
|
-
epicContext.usages.push({ ...currentUsage, timestamp: Date.now() });
|
|
116813
|
-
}
|
|
116814
|
-
};
|
|
116815
115651
|
const workflowInput = {
|
|
116816
|
-
|
|
116817
|
-
|
|
116818
|
-
|
|
116819
|
-
},
|
|
116820
|
-
saveUsageSnapshot,
|
|
116821
|
-
interactive: !globalOpts.yes
|
|
115652
|
+
task: input2,
|
|
115653
|
+
interactive: !globalOpts.yes,
|
|
115654
|
+
additionalTools: {}
|
|
116822
115655
|
};
|
|
116823
115656
|
await runWorkflow(metaWorkflow, workflowInput, {
|
|
116824
115657
|
commandName: "meta",
|
|
116825
115658
|
context: globalOpts,
|
|
116826
115659
|
logger,
|
|
116827
|
-
|
|
116828
|
-
|
|
116829
|
-
},
|
|
116830
|
-
getProvider: (opt) => getProvider({
|
|
116831
|
-
...opt,
|
|
116832
|
-
todoItemStore: new EpicTodoItemStore(workflowInput),
|
|
116833
|
-
memoryStore: new EpicMemoryStore(workflowInput)
|
|
116834
|
-
})
|
|
115660
|
+
requiresProvider: true,
|
|
115661
|
+
interactive: !globalOpts.yes
|
|
116835
115662
|
});
|
|
116836
115663
|
}
|
|
116837
115664
|
async function tryExecuteCommand(commandName, logger) {
|
|
@@ -117340,7 +116167,6 @@ program2.addCommand(prCommand);
|
|
|
117340
116167
|
program2.addCommand(reviewCommand);
|
|
117341
116168
|
program2.addCommand(planCommand);
|
|
117342
116169
|
program2.addCommand(codeCommand);
|
|
117343
|
-
program2.addCommand(epicCommand);
|
|
117344
116170
|
program2.addCommand(fixCommand);
|
|
117345
116171
|
program2.addCommand(runCommand);
|
|
117346
116172
|
program2.addCommand(skillsCommand);
|
|
@@ -117362,7 +116188,6 @@ export {
|
|
|
117362
116188
|
reviewCode,
|
|
117363
116189
|
plan3 as plan,
|
|
117364
116190
|
fix3 as fix,
|
|
117365
|
-
epic2 as epic,
|
|
117366
116191
|
createPr,
|
|
117367
116192
|
commit3 as commit,
|
|
117368
116193
|
code2 as code
|