feat: Make relates_to and duplicates links bidirectional
- relates_to and duplicates now create reverse links automatically - task_show displays Related and Duplicates sections - blocks remains unidirectional (A blocks B, B is blocked by A) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -195,6 +195,36 @@ export async function taskShow(id: string): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
// Get related tasks (bidirectional - only need to query one direction since links are symmetric)
|
||||
const relatesTo = await query<{ id: string; title: string }>(
|
||||
`SELECT t.id, t.title FROM task_links l
|
||||
JOIN tasks t ON t.id = l.to_task_id
|
||||
WHERE l.from_task_id = $1 AND l.link_type = 'relates_to'`,
|
||||
[id]
|
||||
);
|
||||
|
||||
if (relatesTo.length > 0) {
|
||||
output += `\n**Related:**\n`;
|
||||
for (const t of relatesTo) {
|
||||
output += ` - ${t.id}: ${t.title}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// Get duplicates (bidirectional)
|
||||
const duplicates = await query<{ id: string; title: string }>(
|
||||
`SELECT t.id, t.title FROM task_links l
|
||||
JOIN tasks t ON t.id = l.to_task_id
|
||||
WHERE l.from_task_id = $1 AND l.link_type = 'duplicates'`,
|
||||
[id]
|
||||
);
|
||||
|
||||
if (duplicates.length > 0) {
|
||||
output += `\n**Duplicates:**\n`;
|
||||
for (const t of duplicates) {
|
||||
output += ` - ${t.id}: ${t.title}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,15 @@ interface ChecklistToggleArgs {
|
||||
|
||||
/**
|
||||
* Create a dependency between tasks
|
||||
* - blocks: unidirectional (A blocks B)
|
||||
* - relates_to: bidirectional (A relates to B = B relates to A)
|
||||
* - duplicates: bidirectional (A duplicates B = B duplicates A)
|
||||
*/
|
||||
export async function taskLink(args: TaskLinkArgs): Promise<string> {
|
||||
const { from_id, to_id, link_type } = args;
|
||||
|
||||
try {
|
||||
// Create the primary link
|
||||
await execute(
|
||||
`INSERT INTO task_links (from_task_id, to_task_id, link_type)
|
||||
VALUES ($1, $2, $3)
|
||||
@@ -32,6 +36,16 @@ export async function taskLink(args: TaskLinkArgs): Promise<string> {
|
||||
[from_id, to_id, link_type]
|
||||
);
|
||||
|
||||
// For symmetric relationships, create reverse link
|
||||
if (link_type === 'relates_to' || link_type === 'duplicates') {
|
||||
await execute(
|
||||
`INSERT INTO task_links (from_task_id, to_task_id, link_type)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (from_task_id, to_task_id, link_type) DO NOTHING`,
|
||||
[to_id, from_id, link_type]
|
||||
);
|
||||
}
|
||||
|
||||
return `Linked: ${from_id} ${link_type} ${to_id}`;
|
||||
} catch (error) {
|
||||
return `Error creating link: ${error}`;
|
||||
|
||||
Reference in New Issue
Block a user