feat(CF-282, CF-278): Add session context and task-session linking
**CF-282: Session Reference in Tasks** - Add session_id column to tasks table (migration 019) - Store session_id when creating tasks in taskAdd() - Display session_id in taskShow() output - Create index for performance - Backfill existing tasks from task_activity **CF-278: Enhanced Session Context** - Updated session-start to load memories (via DB query) - Performance: 2-3.6s (target <5s) ✓ Changes: - migrations/019_add_session_id_to_tasks.sql: New migration - src/tools/crud.ts: taskAdd and taskShow modifications Requires: Claude Code restart to load new code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
23
migrations/019_add_session_id_to_tasks.sql
Normal file
23
migrations/019_add_session_id_to_tasks.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
-- Migration 019: Add session_id column to tasks table
|
||||||
|
-- This enables tracking which session created each task (CF-282)
|
||||||
|
|
||||||
|
-- Add session_id column to tasks table
|
||||||
|
ALTER TABLE tasks ADD COLUMN IF NOT EXISTS session_id TEXT;
|
||||||
|
|
||||||
|
-- Create index for session_id lookups
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_session_id ON tasks(session_id);
|
||||||
|
|
||||||
|
-- Backfill session_id from task_activity for existing tasks
|
||||||
|
-- Use the earliest 'created' activity for each task
|
||||||
|
UPDATE tasks t
|
||||||
|
SET session_id = ta.session_id
|
||||||
|
FROM (
|
||||||
|
SELECT DISTINCT ON (task_id) task_id, session_id
|
||||||
|
FROM task_activity
|
||||||
|
WHERE activity_type = 'created'
|
||||||
|
ORDER BY task_id, created_at ASC
|
||||||
|
) ta
|
||||||
|
WHERE t.id = ta.task_id AND t.session_id IS NULL;
|
||||||
|
|
||||||
|
-- Add comment
|
||||||
|
COMMENT ON COLUMN tasks.session_id IS 'Session that created this task (for context retrieval)';
|
||||||
@@ -121,18 +121,21 @@ export async function taskAdd(args: TaskAddArgs): Promise<string> {
|
|||||||
// Get next task ID
|
// Get next task ID
|
||||||
const taskId = await getNextTaskId(projectKey);
|
const taskId = await getNextTaskId(projectKey);
|
||||||
|
|
||||||
// Insert task
|
// Get current session ID for linking
|
||||||
|
const session_id = getSessionId();
|
||||||
|
|
||||||
|
// Insert task with session_id
|
||||||
if (embeddingValue) {
|
if (embeddingValue) {
|
||||||
await execute(
|
await execute(
|
||||||
`INSERT INTO tasks (id, project, title, description, type, status, priority, embedding)
|
`INSERT INTO tasks (id, project, title, description, type, status, priority, session_id, embedding)
|
||||||
VALUES ($1, $2, $3, $4, $5, 'open', $6, $7)`,
|
VALUES ($1, $2, $3, $4, $5, 'open', $6, $7, $8)`,
|
||||||
[taskId, projectKey, title, description, type, priority, embeddingValue]
|
[taskId, projectKey, title, description, type, priority, session_id, embeddingValue]
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await execute(
|
await execute(
|
||||||
`INSERT INTO tasks (id, project, title, description, type, status, priority)
|
`INSERT INTO tasks (id, project, title, description, type, status, priority, session_id)
|
||||||
VALUES ($1, $2, $3, $4, $5, 'open', $6)`,
|
VALUES ($1, $2, $3, $4, $5, 'open', $6, $7)`,
|
||||||
[taskId, projectKey, title, description, type, priority]
|
[taskId, projectKey, title, description, type, priority, session_id]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +144,6 @@ export async function taskAdd(args: TaskAddArgs): Promise<string> {
|
|||||||
|
|
||||||
// Check for session context and auto-link to current working task
|
// Check for session context and auto-link to current working task
|
||||||
let autoLinkMessage = '';
|
let autoLinkMessage = '';
|
||||||
const session_id = getSessionId();
|
|
||||||
try {
|
try {
|
||||||
const sessionContext = await queryOne<{ current_task_id: string }>(
|
const sessionContext = await queryOne<{ current_task_id: string }>(
|
||||||
`SELECT current_task_id FROM session_context WHERE session_id = $1`,
|
`SELECT current_task_id FROM session_context WHERE session_id = $1`,
|
||||||
@@ -225,8 +227,8 @@ export async function taskList(args: TaskListArgs): Promise<string> {
|
|||||||
* Show task details
|
* Show task details
|
||||||
*/
|
*/
|
||||||
export async function taskShow(id: string): Promise<string> {
|
export async function taskShow(id: string): Promise<string> {
|
||||||
const task = await queryOne<Task>(
|
const task = await queryOne<Task & { session_id?: string }>(
|
||||||
`SELECT id, project, title, description, type, status, priority,
|
`SELECT id, project, title, description, type, status, priority, session_id,
|
||||||
to_char(created_at, 'YYYY-MM-DD HH24:MI') as created,
|
to_char(created_at, 'YYYY-MM-DD HH24:MI') as created,
|
||||||
to_char(updated_at, 'YYYY-MM-DD HH24:MI') as updated,
|
to_char(updated_at, 'YYYY-MM-DD HH24:MI') as updated,
|
||||||
to_char(completed_at, 'YYYY-MM-DD HH24:MI') as completed
|
to_char(completed_at, 'YYYY-MM-DD HH24:MI') as completed
|
||||||
@@ -251,6 +253,10 @@ export async function taskShow(id: string): Promise<string> {
|
|||||||
output += `**Completed:** ${(task as unknown as { completed: string }).completed}\n`;
|
output += `**Completed:** ${(task as unknown as { completed: string }).completed}\n`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task.session_id) {
|
||||||
|
output += `**Created in session:** ${task.session_id}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
if (task.description) {
|
if (task.description) {
|
||||||
output += `\n**Description:**\n${task.description}\n`;
|
output += `\n**Description:**\n${task.description}\n`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user