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:
2026-01-27 23:33:06 -05:00
commit 0062e5d9d9
521 changed files with 66418 additions and 0 deletions

134
src/tools/todo-write.ts Normal file
View File

@@ -0,0 +1,134 @@
/**
* TodoWrite Tool - Allows agent to create and update task lists
*
* The agent calls this tool to track progress through multi-step tasks.
*/
import { z } from "zod";
import { todoStore } from "@stores/todo-store";
import type { ToolDefinition } from "@tools/types";
import type { TodoStatus } from "@/types/todo";
const TodoItemSchema = z.object({
id: z.string().describe("Unique identifier for the todo item"),
title: z.string().describe("Brief description of the task"),
status: z
.enum(["pending", "in_progress", "completed", "failed"])
.describe("Current status of the task"),
});
const parametersSchema = z.object({
todos: z
.array(TodoItemSchema)
.describe(
"Complete list of todo items. Include all items, not just changes.",
),
});
type TodoWriteParams = z.infer<typeof parametersSchema>;
export const todoWriteTool: ToolDefinition = {
name: "todowrite",
description: `Update the todo list to track progress through multi-step tasks.
Use this tool to:
- Create a task list when starting complex work
- Update task status as you complete each step
- Add new tasks discovered during work
- Mark tasks as completed or failed
Always include the COMPLETE todo list, not just changes. The list will replace the current todos.
Example:
{
"todos": [
{ "id": "1", "title": "Read the source file", "status": "completed" },
{ "id": "2", "title": "Identify the bug", "status": "in_progress" },
{ "id": "3", "title": "Apply the fix", "status": "pending" },
{ "id": "4", "title": "Verify the build", "status": "pending" }
]
}`,
parameters: parametersSchema,
execute: async (args: TodoWriteParams) => {
const { todos } = args;
// Check if we have an existing plan or need to create one
const existingPlan = todoStore.getPlan();
if (!existingPlan) {
// Create new plan from todos
const tasks = todos.map((t) => ({
title: t.title,
description: undefined,
}));
if (tasks.length > 0) {
todoStore.createPlan("Task Plan", tasks);
// Update statuses after creation
const plan = todoStore.getPlan();
if (plan) {
todos.forEach((todo, index) => {
if (plan.items[index]) {
todoStore.updateItemStatus(
plan.items[index].id,
todo.status as TodoStatus,
);
}
});
}
}
} else {
// Update existing plan - sync with provided todos
const currentItems = existingPlan.items;
// Update existing items
todos.forEach((todo) => {
const existing = currentItems.find(
(item) => item.id === todo.id || item.title === todo.title,
);
if (existing) {
todoStore.updateItemStatus(existing.id, todo.status as TodoStatus);
} else {
// Add new item
const newId = todoStore.addItem(todo.title);
if (newId) {
todoStore.updateItemStatus(newId, todo.status as TodoStatus);
}
}
});
}
// Get final state
const plan = todoStore.getPlan();
const progress = todoStore.getProgress();
if (!plan) {
return {
success: true,
title: "Todos cleared",
output: "Todo list is now empty.",
};
}
const summary = plan.items
.map((item) => {
const icon =
item.status === "completed"
? "✓"
: item.status === "in_progress"
? "→"
: item.status === "failed"
? "✗"
: "○";
return `${icon} ${item.title}`;
})
.join("\n");
return {
success: true,
title: "Todos updated",
output: `Progress: ${progress.completed}/${progress.total} (${progress.percentage}%)\n\n${summary}`,
};
},
};