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:
parent
eabc20de9e
commit
3d5754089e
@ -3,6 +3,7 @@ import { existsSync, rmSync, mkdirSync, writeFileSync } from "fs"
|
|||||||
import { join } from "path"
|
import { join } from "path"
|
||||||
import type { TaskObject } from "./types"
|
import type { TaskObject } from "./types"
|
||||||
import { createTaskGetTool } from "./task-get"
|
import { createTaskGetTool } from "./task-get"
|
||||||
|
import { writeTeamTask } from "../agent-teams/team-task-store"
|
||||||
|
|
||||||
const TEST_STORAGE = ".test-task-get-tool"
|
const TEST_STORAGE = ".test-task-get-tool"
|
||||||
const TEST_DIR = join(process.cwd(), TEST_STORAGE)
|
const TEST_DIR = join(process.cwd(), TEST_STORAGE)
|
||||||
@ -10,6 +11,7 @@ const TEST_CONFIG = {
|
|||||||
sisyphus: {
|
sisyphus: {
|
||||||
tasks: {
|
tasks: {
|
||||||
storage_path: TEST_STORAGE,
|
storage_path: TEST_STORAGE,
|
||||||
|
claude_code_compat: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -218,5 +220,55 @@ describe("task_get tool", () => {
|
|||||||
expect(result.task.owner).toBeUndefined()
|
expect(result.task.owner).toBeUndefined()
|
||||||
expect(result.task.metadata).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")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import type { OhMyOpenCodeConfig } from "../../config/schema"
|
|||||||
import type { TaskGetInput } from "./types"
|
import type { TaskGetInput } from "./types"
|
||||||
import { TaskGetInputSchema, TaskObjectSchema } from "./types"
|
import { TaskGetInputSchema, TaskObjectSchema } from "./types"
|
||||||
import { getTaskDir, readJsonSafe } from "../../features/claude-tasks/storage"
|
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-]+$/
|
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.`,
|
Returns null if the task does not exist or the file is invalid.`,
|
||||||
args: {
|
args: {
|
||||||
id: tool.schema.string().describe("Task ID to retrieve (format: T-{uuid})"),
|
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> => {
|
execute: async (args: Record<string, unknown>): Promise<string> => {
|
||||||
try {
|
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" })
|
return JSON.stringify({ error: "invalid_task_id" })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (validatedArgs.team_name) {
|
||||||
|
const task = readTeamTask(validatedArgs.team_name, taskId)
|
||||||
|
return JSON.stringify({ task: task ?? null })
|
||||||
|
} else {
|
||||||
const taskDir = getTaskDir(config)
|
const taskDir = getTaskDir(config)
|
||||||
const taskPath = join(taskDir, `${taskId}.json`)
|
const taskPath = join(taskDir, `${taskId}.json`)
|
||||||
|
|
||||||
const task = readJsonSafe(taskPath, TaskObjectSchema)
|
const task = readJsonSafe(taskPath, TaskObjectSchema)
|
||||||
|
|
||||||
return JSON.stringify({ task: task ?? null })
|
return JSON.stringify({ task: task ?? null })
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error && error.message.includes("validation")) {
|
if (error instanceof Error && error.message.includes("validation")) {
|
||||||
return JSON.stringify({ error: "invalid_arguments" })
|
return JSON.stringify({ error: "invalid_arguments" })
|
||||||
|
|||||||
@ -51,6 +51,7 @@ export type TaskListInput = z.infer<typeof TaskListInputSchema>
|
|||||||
|
|
||||||
export const TaskGetInputSchema = z.object({
|
export const TaskGetInputSchema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
|
team_name: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export type TaskGetInput = z.infer<typeof TaskGetInputSchema>
|
export type TaskGetInput = z.infer<typeof TaskGetInputSchema>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user