feat(CF-166): Add investigation workflow with auto-linking
Implements comprehensive investigation task management: **Schema Changes (Migration 020):** - Add 'investigation' task type to tasks table - Add investigation_parent_id and auto_link_enabled columns to session_context - Add auto_linked and linked_at columns to task_links for tracking - Create indexes for efficient auto-linking queries **Auto-Linking Logic:** 1. Investigation Parent Linking: Tasks auto-link to active investigation 2. Current Task Linking: Tasks link to current working task 3. Time-Based Linking: Tasks within 1 hour auto-link (fallback) **New Tool:** - task_investigate: Start investigation workflow, sets session context **Documentation:** - Add comprehensive investigation workflow guide to README - Include examples and session context explanation All checklist items completed: ✓ Investigation task type in schema ✓ Session context table enhancements ✓ Auto-linking implementation ✓ task_investigate command ✓ Documentation updates Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -142,25 +142,75 @@ export async function taskAdd(args: TaskAddArgs): Promise<string> {
|
||||
// Record activity for session tracking
|
||||
await recordActivity(taskId, 'created', undefined, 'open');
|
||||
|
||||
// Check for session context and auto-link to current working task
|
||||
// Enhanced auto-linking logic (CF-166)
|
||||
let autoLinkMessage = '';
|
||||
try {
|
||||
const sessionContext = await queryOne<{ current_task_id: string }>(
|
||||
`SELECT current_task_id FROM session_context WHERE session_id = $1`,
|
||||
const sessionContext = await queryOne<{
|
||||
current_task_id: string | null;
|
||||
investigation_parent_id: string | null;
|
||||
auto_link_enabled: boolean;
|
||||
}>(
|
||||
`SELECT current_task_id, investigation_parent_id, auto_link_enabled
|
||||
FROM session_context WHERE session_id = $1`,
|
||||
[session_id]
|
||||
);
|
||||
|
||||
if (sessionContext?.current_task_id) {
|
||||
// Auto-link to current working task
|
||||
await taskLink({
|
||||
from_id: taskId,
|
||||
to_id: sessionContext.current_task_id,
|
||||
link_type: 'relates_to'
|
||||
});
|
||||
autoLinkMessage = `\n\n🔗 Auto-linked to: ${sessionContext.current_task_id} (current working task)`;
|
||||
if (sessionContext?.auto_link_enabled !== false) {
|
||||
const linkedTasks: string[] = [];
|
||||
|
||||
// 1. Auto-link to investigation parent if this is created during an investigation
|
||||
if (sessionContext?.investigation_parent_id) {
|
||||
await execute(
|
||||
`INSERT INTO task_links (from_task_id, to_task_id, link_type, auto_linked)
|
||||
VALUES ($1, $2, 'relates_to', true)
|
||||
ON CONFLICT DO NOTHING`,
|
||||
[taskId, sessionContext.investigation_parent_id]
|
||||
);
|
||||
linkedTasks.push(`${sessionContext.investigation_parent_id} (investigation)`);
|
||||
}
|
||||
|
||||
// 2. Auto-link to current working task if different from investigation parent
|
||||
if (sessionContext?.current_task_id &&
|
||||
sessionContext.current_task_id !== sessionContext?.investigation_parent_id) {
|
||||
await execute(
|
||||
`INSERT INTO task_links (from_task_id, to_task_id, link_type, auto_linked)
|
||||
VALUES ($1, $2, 'relates_to', true)
|
||||
ON CONFLICT DO NOTHING`,
|
||||
[taskId, sessionContext.current_task_id]
|
||||
);
|
||||
linkedTasks.push(`${sessionContext.current_task_id} (current task)`);
|
||||
}
|
||||
|
||||
// 3. Time-based auto-linking: find tasks created within 1 hour in same session
|
||||
if (!sessionContext?.investigation_parent_id && !sessionContext?.current_task_id) {
|
||||
const recentTasks = await query<{ id: string; title: string }>(
|
||||
`SELECT id, title FROM tasks
|
||||
WHERE session_id = $1 AND id != $2
|
||||
AND created_at > NOW() - INTERVAL '1 hour'
|
||||
AND status != 'completed'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 3`,
|
||||
[session_id, taskId]
|
||||
);
|
||||
|
||||
for (const task of recentTasks) {
|
||||
await execute(
|
||||
`INSERT INTO task_links (from_task_id, to_task_id, link_type, auto_linked)
|
||||
VALUES ($1, $2, 'relates_to', true)
|
||||
ON CONFLICT DO NOTHING`,
|
||||
[taskId, task.id]
|
||||
);
|
||||
linkedTasks.push(`${task.id} (recent)`);
|
||||
}
|
||||
}
|
||||
|
||||
if (linkedTasks.length > 0) {
|
||||
autoLinkMessage = `\n\n🔗 Auto-linked to: ${linkedTasks.join(', ')}`;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Silently fail if session context unavailable
|
||||
} catch (error) {
|
||||
// Log but don't fail if auto-linking fails
|
||||
console.error('Auto-linking failed:', error);
|
||||
}
|
||||
|
||||
return `Created: ${taskId}\n Title: ${title}\n Type: ${type}\n Priority: ${priority}\n Project: ${projectKey}${embedding ? '\n (embedded for semantic search)' : ''}${duplicateWarning}${autoLinkMessage}`;
|
||||
@@ -460,3 +510,44 @@ export async function taskUpdate(args: TaskUpdateArgs): Promise<string> {
|
||||
|
||||
return `Updated: ${id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start an investigation workflow (CF-166)
|
||||
* Creates an investigation task and sets it as the session context parent
|
||||
* All subsequent tasks will auto-link to this investigation
|
||||
*/
|
||||
export async function taskInvestigate(args: TaskAddArgs): Promise<string> {
|
||||
const { title, project, priority = 'P1', description = '' } = args;
|
||||
|
||||
// Create investigation task
|
||||
const taskResult = await taskAdd({
|
||||
title,
|
||||
project,
|
||||
type: 'investigation',
|
||||
priority,
|
||||
description: description || 'Investigation task to coordinate related subtasks',
|
||||
});
|
||||
|
||||
// Extract task ID from result (format: "Created: XX-123\n...")
|
||||
const taskIdMatch = taskResult.match(/Created: ([\w-]+)/);
|
||||
if (!taskIdMatch) {
|
||||
return taskResult; // Return original message if format unexpected
|
||||
}
|
||||
const taskId = taskIdMatch[1];
|
||||
|
||||
// Set as investigation parent in session context
|
||||
const session_id = getSessionId();
|
||||
try {
|
||||
await execute(
|
||||
`INSERT INTO session_context (session_id, current_task_id, investigation_parent_id)
|
||||
VALUES ($1, $2, $2)
|
||||
ON CONFLICT (session_id) DO UPDATE
|
||||
SET investigation_parent_id = $2, current_task_id = $2, updated_at = NOW()`,
|
||||
[session_id, taskId]
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to set investigation context:', error);
|
||||
}
|
||||
|
||||
return taskResult + '\n\n🔍 Investigation started! All new tasks will auto-link to this investigation.';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user