feat(task): add team_name routing to task_get tool

- Add optional team_name parameter to task_get
- Route to team-namespaced storage when team_name provided
- Preserve existing behavior when team_name absent
- Add tests for both team and regular task retrieval
- Part of Task 12 (2/4 files complete)
This commit is contained in:
YeonGyu-Kim 2026-02-12 03:08:06 +09:00
parent eabc20de9e
commit 3d5754089e
3 changed files with 64 additions and 6 deletions

View File

@ -3,6 +3,7 @@ import { existsSync, rmSync, mkdirSync, writeFileSync } from "fs"
import { join } from "path"
import type { TaskObject } from "./types"
import { createTaskGetTool } from "./task-get"
import { writeTeamTask } from "../agent-teams/team-task-store"
const TEST_STORAGE = ".test-task-get-tool"
const TEST_DIR = join(process.cwd(), TEST_STORAGE)
@ -10,6 +11,7 @@ const TEST_CONFIG = {
sisyphus: {
tasks: {
storage_path: TEST_STORAGE,
claude_code_compat: true,
},
},
}
@ -218,5 +220,55 @@ describe("task_get tool", () => {
expect(result.task.owner).toBeUndefined()
expect(result.task.metadata).toBeUndefined()
})
test("retrieves task from team namespace when team_name provided", async () => {
//#given
const teamName = "test-team"
const taskId = "T-team-task-404"
const taskData: TaskObject = {
id: taskId,
subject: "Team task",
description: "Team description",
status: "pending",
blocks: [],
blockedBy: [],
threadID: TEST_SESSION_ID,
}
writeTeamTask(teamName, taskId, taskData)
//#when
const resultStr = await tool.execute({ id: taskId, team_name: teamName }, TEST_CONTEXT)
const result = JSON.parse(resultStr)
//#then
expect(result).toHaveProperty("task")
expect(result.task).not.toBeNull()
expect(result.task.id).toBe(taskId)
expect(result.task.subject).toBe("Team task")
})
test("retrieves task from regular storage when no team_name", async () => {
//#given
const taskId = "T-regular-task-505"
const taskData: TaskObject = {
id: taskId,
subject: "Regular task",
description: "Regular",
status: "pending",
blocks: [],
blockedBy: [],
threadID: TEST_SESSION_ID,
}
const taskFile = join(TEST_DIR, `${taskId}.json`)
writeFileSync(taskFile, JSON.stringify(taskData, null, 2))
//#when
const resultStr = await tool.execute({ id: taskId }, TEST_CONTEXT)
const result = JSON.parse(resultStr)
//#then
expect(result.task).not.toBeNull()
expect(result.task.subject).toBe("Regular task")
})
})
})

View File

@ -4,6 +4,7 @@ import type { OhMyOpenCodeConfig } from "../../config/schema"
import type { TaskGetInput } from "./types"
import { TaskGetInputSchema, TaskObjectSchema } from "./types"
import { getTaskDir, readJsonSafe } from "../../features/claude-tasks/storage"
import { readTeamTask } from "../agent-teams/team-task-store"
const TASK_ID_PATTERN = /^T-[A-Za-z0-9-]+$/
@ -21,6 +22,7 @@ Returns the full task object including all fields: id, subject, description, sta
Returns null if the task does not exist or the file is invalid.`,
args: {
id: tool.schema.string().describe("Task ID to retrieve (format: T-{uuid})"),
team_name: tool.schema.string().optional().describe("Optional: team name for team-namespaced tasks"),
},
execute: async (args: Record<string, unknown>): Promise<string> => {
try {
@ -31,12 +33,15 @@ Returns null if the task does not exist or the file is invalid.`,
return JSON.stringify({ error: "invalid_task_id" })
}
const taskDir = getTaskDir(config)
const taskPath = join(taskDir, `${taskId}.json`)
const task = readJsonSafe(taskPath, TaskObjectSchema)
return JSON.stringify({ task: task ?? null })
if (validatedArgs.team_name) {
const task = readTeamTask(validatedArgs.team_name, taskId)
return JSON.stringify({ task: task ?? null })
} else {
const taskDir = getTaskDir(config)
const taskPath = join(taskDir, `${taskId}.json`)
const task = readJsonSafe(taskPath, TaskObjectSchema)
return JSON.stringify({ task: task ?? null })
}
} catch (error) {
if (error instanceof Error && error.message.includes("validation")) {
return JSON.stringify({ error: "invalid_arguments" })

View File

@ -51,6 +51,7 @@ export type TaskListInput = z.infer<typeof TaskListInputSchema>
export const TaskGetInputSchema = z.object({
id: z.string(),
team_name: z.string().optional(),
})
export type TaskGetInput = z.infer<typeof TaskGetInputSchema>