@nanocollective/nanocoder
Version:
A local-first CLI coding agent that brings the power of agentic coding tools like Claude Code and Gemini CLI to local models or controlled APIs like OpenRouter
101 lines • 3.9 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { TaskListDisplay } from '../../components/task-list-display.js';
import { jsonSchema, tool } from '../../types/core.js';
import { generateTaskId, loadTasks, saveTasks } from './storage.js';
const executeCreateTask = async (args) => {
const existingTasks = await loadTasks();
const now = new Date().toISOString();
const newTasks = args.tasks.map(input => ({
id: generateTaskId(),
title: input.title,
description: input.description,
status: 'pending',
createdAt: now,
updatedAt: now,
}));
const allTasks = [...existingTasks, ...newTasks];
await saveTasks(allTasks);
// Return formatted task list for LLM context
const createdList = newTasks.map(t => ` ○ [${t.id}] ${t.title}`).join('\n');
const counts = {
pending: allTasks.filter(t => t.status === 'pending').length,
in_progress: allTasks.filter(t => t.status === 'in_progress').length,
completed: allTasks.filter(t => t.status === 'completed').length,
};
const allTasksList = allTasks
.map(t => {
const icon = t.status === 'completed' ? '✓' : t.status === 'in_progress' ? '◐' : '○';
return ` ${icon} [${t.id}] ${t.title}`;
})
.join('\n');
return `Created ${newTasks.length} task(s):\n${createdList}\n\nAll Tasks (${counts.pending} pending, ${counts.in_progress} in progress, ${counts.completed} completed):\n${allTasksList}`;
};
const createTaskCoreTool = tool({
description: 'Create one or more tasks to track work. Use this to plan and track progress on multi-step operations. Pass an array of tasks to create multiple at once.',
inputSchema: jsonSchema({
type: 'object',
properties: {
tasks: {
type: 'array',
description: 'Array of tasks to create',
items: {
type: 'object',
properties: {
title: {
type: 'string',
description: 'The title of the task',
},
description: {
type: 'string',
description: 'Optional detailed description of the task',
},
},
required: ['title'],
},
},
},
required: ['tasks'],
}),
needsApproval: false,
execute: async (args, _options) => {
return await executeCreateTask(args);
},
});
const createTaskFormatter = async (args, _result) => {
const allTasks = await loadTasks();
const taskCount = args.tasks?.length || 0;
const title = `Created ${taskCount} task(s) - All Tasks`;
return _jsx(TaskListDisplay, { tasks: allTasks, title: title });
};
const createTaskValidator = (args) => {
if (!args.tasks || args.tasks.length === 0) {
return Promise.resolve({
valid: false,
error: '⚒ At least one task is required',
});
}
for (let i = 0; i < args.tasks.length; i++) {
const task = args.tasks[i];
const title = task?.title?.trim();
if (!title) {
return Promise.resolve({
valid: false,
error: `⚒ Task ${i + 1}: title cannot be empty`,
});
}
if (title.length > 200) {
return Promise.resolve({
valid: false,
error: `⚒ Task ${i + 1}: title is too long (max 200 characters)`,
});
}
}
return Promise.resolve({ valid: true });
};
export const createTaskTool = {
name: 'create_task',
tool: createTaskCoreTool,
formatter: createTaskFormatter,
validator: createTaskValidator,
};
//# sourceMappingURL=create-task.js.map