92 lines
3.9 KiB
TypeScript
92 lines
3.9 KiB
TypeScript
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
|
import { readTeamConfigOrThrow } from "./team-config-store"
|
|
import { validateAgentNameOrLead, validateTaskId, validateTeamName } from "./name-validation"
|
|
import { TeamTaskUpdateInputSchema, TeamToolContext } from "./types"
|
|
import { updateTeamTask } from "./team-task-update"
|
|
import { notifyOwnerAssignment, resolveTaskActorFromContext } from "./team-task-tools"
|
|
|
|
export function createTeamTaskUpdateTool(): ToolDefinition {
|
|
return tool({
|
|
description: "Update task status, owner, dependencies, and metadata in a team task list.",
|
|
args: {
|
|
team_name: tool.schema.string().describe("Team name"),
|
|
task_id: tool.schema.string().describe("Task id"),
|
|
status: tool.schema.enum(["pending", "in_progress", "completed", "deleted"]).optional().describe("Task status"),
|
|
owner: tool.schema.string().optional().describe("Task owner"),
|
|
subject: tool.schema.string().optional().describe("Task subject"),
|
|
description: tool.schema.string().optional().describe("Task description"),
|
|
active_form: tool.schema.string().optional().describe("Present-continuous form"),
|
|
add_blocks: tool.schema.array(tool.schema.string()).optional().describe("Add task ids this task blocks"),
|
|
add_blocked_by: tool.schema.array(tool.schema.string()).optional().describe("Add blocker task ids"),
|
|
metadata: tool.schema.record(tool.schema.string(), tool.schema.unknown()).optional().describe("Metadata patch (null removes key)"),
|
|
},
|
|
execute: async (args: Record<string, unknown>, context: TeamToolContext): Promise<string> => {
|
|
try {
|
|
const input = TeamTaskUpdateInputSchema.parse(args)
|
|
const teamError = validateTeamName(input.team_name)
|
|
if (teamError) {
|
|
return JSON.stringify({ error: teamError })
|
|
}
|
|
const taskIdError = validateTaskId(input.task_id)
|
|
if (taskIdError) {
|
|
return JSON.stringify({ error: taskIdError })
|
|
}
|
|
|
|
const config = readTeamConfigOrThrow(input.team_name)
|
|
const actor = resolveTaskActorFromContext(config, context)
|
|
if (!actor) {
|
|
return JSON.stringify({ error: "unauthorized_task_session" })
|
|
}
|
|
|
|
const memberNames = new Set(config.members.map((member) => member.name))
|
|
if (input.owner !== undefined) {
|
|
if (input.owner !== "") {
|
|
const ownerError = validateAgentNameOrLead(input.owner)
|
|
if (ownerError) {
|
|
return JSON.stringify({ error: ownerError })
|
|
}
|
|
|
|
if (!memberNames.has(input.owner)) {
|
|
return JSON.stringify({ error: "owner_not_in_team" })
|
|
}
|
|
}
|
|
}
|
|
if (input.add_blocks) {
|
|
for (const blockerId of input.add_blocks) {
|
|
const blockerError = validateTaskId(blockerId)
|
|
if (blockerError) {
|
|
return JSON.stringify({ error: blockerError })
|
|
}
|
|
}
|
|
}
|
|
if (input.add_blocked_by) {
|
|
for (const dependencyId of input.add_blocked_by) {
|
|
const dependencyError = validateTaskId(dependencyId)
|
|
if (dependencyError) {
|
|
return JSON.stringify({ error: dependencyError })
|
|
}
|
|
}
|
|
}
|
|
const task = updateTeamTask(input.team_name, input.task_id, {
|
|
status: input.status,
|
|
owner: input.owner,
|
|
subject: input.subject,
|
|
description: input.description,
|
|
activeForm: input.active_form,
|
|
addBlocks: input.add_blocks,
|
|
addBlockedBy: input.add_blocked_by,
|
|
metadata: input.metadata,
|
|
})
|
|
|
|
if (input.owner !== undefined) {
|
|
notifyOwnerAssignment(input.team_name, task, actor)
|
|
}
|
|
|
|
return JSON.stringify(task)
|
|
} catch (error) {
|
|
return JSON.stringify({ error: error instanceof Error ? error.message : "team_task_update_failed" })
|
|
}
|
|
},
|
|
})
|
|
}
|