Terminal-based AI coding agent with interactive TUI for autonomous code generation.
Features: - Interactive TUI with React/Ink - Autonomous agent with tool calls (bash, read, write, edit, glob, grep) - Permission system with pattern-based rules - Session management with auto-compaction - Dual providers: GitHub Copilot and Ollama - MCP server integration - Todo panel and theme system - Streaming responses - GitHub-compatible project context
This commit is contained in:
148
src/services/plan-service.ts
Normal file
148
src/services/plan-service.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* Plan Service - Manages agent-generated task plans
|
||||
*
|
||||
* Provides functions for agents to create and update plans
|
||||
*/
|
||||
|
||||
import { todoStore } from "@stores/todo-store";
|
||||
import type { TodoStatus } from "@/types/todo";
|
||||
|
||||
/**
|
||||
* Create a new plan with tasks
|
||||
*/
|
||||
export const createPlan = (
|
||||
title: string,
|
||||
tasks: Array<{ title: string; description?: string }>,
|
||||
): string => {
|
||||
return todoStore.createPlan(title, tasks);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a task to the current plan
|
||||
*/
|
||||
export const addTask = (title: string, description?: string): string | null => {
|
||||
return todoStore.addItem(title, description);
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark the current task as completed and move to next
|
||||
*/
|
||||
export const completeCurrentTask = (): void => {
|
||||
const current = todoStore.getCurrentItem();
|
||||
if (current) {
|
||||
todoStore.updateItemStatus(current.id, "completed");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark a specific task as completed
|
||||
*/
|
||||
export const completeTask = (taskId: string): void => {
|
||||
todoStore.updateItemStatus(taskId, "completed");
|
||||
};
|
||||
|
||||
/**
|
||||
* Mark a task as failed
|
||||
*/
|
||||
export const failTask = (taskId: string): void => {
|
||||
todoStore.updateItemStatus(taskId, "failed");
|
||||
};
|
||||
|
||||
/**
|
||||
* Update task status
|
||||
*/
|
||||
export const updateTaskStatus = (taskId: string, status: TodoStatus): void => {
|
||||
todoStore.updateItemStatus(taskId, status);
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the current plan
|
||||
*/
|
||||
export const clearPlan = (): void => {
|
||||
todoStore.clearPlan();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there's an active plan
|
||||
*/
|
||||
export const hasPlan = (): boolean => {
|
||||
return todoStore.hasPlan();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current task being worked on
|
||||
*/
|
||||
export const getCurrentTask = () => {
|
||||
return todoStore.getCurrentItem();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get plan progress
|
||||
*/
|
||||
export const getProgress = () => {
|
||||
return todoStore.getProgress();
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the full current plan
|
||||
*/
|
||||
export const getPlan = () => {
|
||||
return todoStore.getPlan();
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse a plan from agent response text
|
||||
* Looks for numbered lists or task patterns
|
||||
*/
|
||||
export const parsePlanFromText = (
|
||||
text: string,
|
||||
): Array<{ title: string; description?: string }> | null => {
|
||||
const tasks: Array<{ title: string; description?: string }> = [];
|
||||
|
||||
// Pattern 1: Numbered list (1. Task, 2. Task, etc.)
|
||||
const numberedPattern = /^\s*(\d+)\.\s+(.+)$/gm;
|
||||
let match;
|
||||
|
||||
while ((match = numberedPattern.exec(text)) !== null) {
|
||||
tasks.push({ title: match[2].trim() });
|
||||
}
|
||||
|
||||
if (tasks.length > 0) {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// Pattern 2: Checkbox list (- [ ] Task, - [x] Task)
|
||||
const checkboxPattern = /^\s*-\s*\[[ x]\]\s+(.+)$/gm;
|
||||
|
||||
while ((match = checkboxPattern.exec(text)) !== null) {
|
||||
tasks.push({ title: match[1].trim() });
|
||||
}
|
||||
|
||||
if (tasks.length > 0) {
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// Pattern 3: Bullet list with "Step" or "Task" keywords
|
||||
const stepPattern = /^\s*[-*]\s*(Step|Task)\s*\d*:?\s*(.+)$/gim;
|
||||
|
||||
while ((match = stepPattern.exec(text)) !== null) {
|
||||
tasks.push({ title: match[2].trim() });
|
||||
}
|
||||
|
||||
return tasks.length > 0 ? tasks : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Detect if text contains a plan
|
||||
*/
|
||||
export const detectPlan = (text: string): boolean => {
|
||||
const planKeywords = [
|
||||
/here'?s? (my |the |a )?plan/i,
|
||||
/i'?ll? (do|perform|execute) the following/i,
|
||||
/steps? to (complete|accomplish|do)/i,
|
||||
/let me (outline|break down)/i,
|
||||
/the (plan|approach|strategy) is/i,
|
||||
];
|
||||
|
||||
return planKeywords.some((pattern) => pattern.test(text));
|
||||
};
|
||||
Reference in New Issue
Block a user