diff --git a/migrations/029_add_planning_mode_required.sql b/migrations/029_add_planning_mode_required.sql new file mode 100644 index 0000000..608ad99 --- /dev/null +++ b/migrations/029_add_planning_mode_required.sql @@ -0,0 +1,3 @@ +-- CF-314: Add planning_mode_required flag for smart planning mode auto-detection +-- NULL = auto-detect (scoring algorithm), true = always plan, false = never plan +ALTER TABLE tasks ADD COLUMN IF NOT EXISTS planning_mode_required BOOLEAN DEFAULT NULL; diff --git a/src/index.ts b/src/index.ts index d00d929..c392119 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,6 +120,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { type: a.type, priority: a.priority, description: a.description, + planning_mode_required: a.planning_mode_required, }); break; case 'task_list': @@ -144,6 +145,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { priority: a.priority, type: a.type, title: a.title, + planning_mode_required: a.planning_mode_required, }); break; case 'task_investigate': diff --git a/src/tools/crud.ts b/src/tools/crud.ts index 809892c..3198291 100644 --- a/src/tools/crud.ts +++ b/src/tools/crud.ts @@ -63,6 +63,7 @@ interface TaskAddArgs { type?: string; priority?: string; description?: string; + planning_mode_required?: boolean | null; } interface TaskListArgs { @@ -79,13 +80,14 @@ interface TaskUpdateArgs { priority?: string; type?: string; title?: string; + planning_mode_required?: boolean | null; } /** * Create a new task */ export async function taskAdd(args: TaskAddArgs): Promise { - const { title, project = 'Unknown', type = 'task', priority = 'P2', description = '' } = args; + const { title, project = 'Unknown', type = 'task', priority = 'P2', description = '', planning_mode_required } = args; // Get project key const projectKey = await getProjectKey(project); @@ -151,17 +153,19 @@ export async function taskAdd(args: TaskAddArgs): Promise { const session_id = getSessionId(); // Insert task with session_id + const planningValue = planning_mode_required !== undefined ? planning_mode_required : null; + if (embeddingValue) { await execute( - `INSERT INTO tasks (id, project, title, description, type, status, priority, session_id, embedding) - VALUES ($1, $2, $3, $4, $5, 'open', $6, $7, $8)`, - [taskId, projectKey, title, description, type, priority, session_id, embeddingValue] + `INSERT INTO tasks (id, project, title, description, type, status, priority, session_id, embedding, planning_mode_required) + VALUES ($1, $2, $3, $4, $5, 'open', $6, $7, $8, $9)`, + [taskId, projectKey, title, description, type, priority, session_id, embeddingValue, planningValue] ); } else { await execute( - `INSERT INTO tasks (id, project, title, description, type, status, priority, session_id) - VALUES ($1, $2, $3, $4, $5, 'open', $6, $7)`, - [taskId, projectKey, title, description, type, priority, session_id] + `INSERT INTO tasks (id, project, title, description, type, status, priority, session_id, planning_mode_required) + VALUES ($1, $2, $3, $4, $5, 'open', $6, $7, $8)`, + [taskId, projectKey, title, description, type, priority, session_id, planningValue] ); } @@ -326,7 +330,7 @@ export async function taskList(args: TaskListArgs): Promise { */ export async function taskShow(id: string): Promise { const task = await queryOne( - `SELECT id, project, title, description, type, status, priority, session_id, + `SELECT id, project, title, description, type, status, priority, session_id, planning_mode_required, to_char(created_at, 'YYYY-MM-DD HH24:MI') as created, to_char(updated_at, 'YYYY-MM-DD HH24:MI') as updated, to_char(completed_at, 'YYYY-MM-DD HH24:MI') as completed @@ -355,6 +359,9 @@ export async function taskShow(id: string): Promise { output += `**Created in session:** ${task.session_id}\n`; } + const planningLabel = task.planning_mode_required === true ? 'required' : task.planning_mode_required === false ? 'skipped' : 'auto-detect'; + output += `**Planning:** ${planningLabel}\n`; + if (task.description) { output += `\n**Description:**\n${task.description}\n`; } @@ -476,7 +483,7 @@ export async function taskClose(id: string): Promise { * Update a task */ export async function taskUpdate(args: TaskUpdateArgs): Promise { - const { id, status, priority, type, title } = args; + const { id, status, priority, type, title, planning_mode_required } = args; // Get current values for activity tracking const task = await queryOne<{ status: string }>(`SELECT status FROM tasks WHERE id = $1`, [id]); @@ -507,6 +514,10 @@ export async function taskUpdate(args: TaskUpdateArgs): Promise { updates.push(`title = $${paramIndex++}`); params.push(title); } + if (planning_mode_required !== undefined) { + updates.push(`planning_mode_required = $${paramIndex++}`); + params.push(planning_mode_required); + } if (updates.length === 0) { return 'No updates specified'; diff --git a/src/tools/index.ts b/src/tools/index.ts index 7edc02d..af6369c 100644 --- a/src/tools/index.ts +++ b/src/tools/index.ts @@ -13,6 +13,7 @@ export const toolDefinitions = [ type: { type: 'string', enum: ['task', 'bug', 'feature', 'debt', 'investigation'], description: 'Task type (default: task)' }, priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'], description: 'Priority level (default: P2)' }, description: { type: 'string', description: 'Optional description' }, + planning_mode_required: { type: 'boolean', description: 'Override planning mode: true=always plan, false=never plan, omit=auto-detect' }, }, required: ['title'], }, @@ -24,7 +25,7 @@ export const toolDefinitions = [ type: 'object', properties: { project: { type: 'string', description: 'Filter by project key' }, - status: { type: 'string', enum: ['open', 'in_progress', 'testing', 'blocked', 'completed'], description: 'Filter by status. Omit to show all non-completed tasks.' }, + status: { type: 'string', enum: ['open', 'in_progress', 'testing', 'blocked', 'completed'], description: 'Filter by exact status value. IMPORTANT: "open" only matches status=open, NOT in_progress/blocked/testing. Omit this parameter entirely to show ALL non-completed tasks.' }, type: { type: 'string', enum: ['task', 'bug', 'feature', 'debt', 'investigation'], description: 'Filter by type' }, priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'], description: 'Filter by priority' }, limit: { type: 'number', description: 'Max results (default: 20)' }, @@ -64,6 +65,7 @@ export const toolDefinitions = [ priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'], description: 'New priority' }, type: { type: 'string', enum: ['task', 'bug', 'feature', 'debt', 'investigation'], description: 'New type' }, title: { type: 'string', description: 'New title' }, + planning_mode_required: { type: 'boolean', description: 'Override planning mode: true=always plan, false=never plan, null=auto-detect' }, }, required: ['id'], }, diff --git a/src/types.ts b/src/types.ts index 8deb41f..3e557c0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,7 @@ export interface Task { priority: 'P0' | 'P1' | 'P2' | 'P3'; version_id?: string; epic_id?: string; + planning_mode_required?: boolean | null; created_at: Date; updated_at: Date; completed_at?: Date;