@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.
Files changed (3) hide show
  1. package/README.md +0 -15
  2. package/dist/index.js +324 -1499
  3. 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.map((v) => String(v));
39619
- return exports_external.enum(enumValues);
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', 'task', or 'epic') to use for a given task.
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', 'task', or 'epic' workflow.
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**: Use the \`gitDiff\` tool on one file at a time to see the exact changes. When reviewing pull requests, use the \`commitRange\` parameter provided in the review instructions.
74744
- 4. **Analyze and Review**: Analyze only the modified lines (additions/deletions) for issues. Provide specific, actionable feedback with accurate line numbers.
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**: Use the line numbers from the diff annotations (\`[Line N]\` for additions, \`[Line N removed]\` for deletions).
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 finalChangeInfo = changeInfo;
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: [readFile_default, readBinaryFile_default, searchFiles_default, listFiles_default, gitDiff_default],
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 (!hasStaged) {
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.85";
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
- init_zod();
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 = this.jsonSchemaToZod(tool3.inputSchema);
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 = [".epic.yml", ...config4.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", "epic"])
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
- interactive: !globalOpts.yes,
114222
- ...globalOpts
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 import_yaml6 = __toESM(require_dist(), 1);
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, import_yaml6.stringify(globalConfig2));
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, import_yaml6.stringify(finalConfig));
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 result = await runWorkflow(workflow3, input2, {
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 completed with no output";
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, files } = args;
116138
- logger.info(`MCP: Executing code workflow - task: "${task2}"${files ? `, files: ${files.join(", ")}` : ""}`);
116139
- return await executeWorkflow(codeWorkflow, { task: task2, files }, "code", logger);
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 all changes (git add .)
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: fs15, network, subprocess } = script.permissions;
116502
- if (fs15 && !["read", "write", "none"].includes(fs15)) {
116503
- throw new ScriptValidationError(`Invalid fs permission: ${fs15}. Must be 'read', 'write', or 'none'`);
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
- ...epicContext,
116760
- async saveEpicContext(context) {
116761
- await saveEpicContext(context);
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
- onUsageMeterCreated: (meter) => {
116771
- usageMeter2 = meter;
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
- ...epicContext,
116817
- async saveEpicContext(context) {
116818
- await saveEpicContext(context);
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
- onUsageMeterCreated: (meter) => {
116828
- usageMeter = meter;
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