feat(task): add real-time single-task todo sync via OpenCode API
- Add syncTaskTodoUpdate function for immediate todo updates - Integrate with TaskCreate and TaskUpdate tools - Preserve existing todos when updating single task - Add comprehensive tests for new sync function 🤖 Generated with [OhMyOpenCode](https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -1,18 +1,20 @@
|
||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool"
|
||||
import { join } from "path"
|
||||
import type { OhMyOpenCodeConfig } from "../../config/schema"
|
||||
import type { TaskObject } from "./types"
|
||||
import { TaskObjectSchema, TaskCreateInputSchema } from "./types"
|
||||
import type { PluginInput } from "@opencode-ai/plugin";
|
||||
import { tool, type ToolDefinition } from "@opencode-ai/plugin/tool";
|
||||
import { join } from "path";
|
||||
import type { OhMyOpenCodeConfig } from "../../config/schema";
|
||||
import type { TaskObject } from "./types";
|
||||
import { TaskObjectSchema, TaskCreateInputSchema } from "./types";
|
||||
import {
|
||||
getTaskDir,
|
||||
writeJsonAtomic,
|
||||
acquireLock,
|
||||
generateTaskId,
|
||||
} from "../../features/claude-tasks/storage"
|
||||
import { syncTaskToTodo } from "./todo-sync"
|
||||
} from "../../features/claude-tasks/storage";
|
||||
import { syncTaskTodoUpdate } from "./todo-sync";
|
||||
|
||||
export function createTaskCreateTool(
|
||||
config: Partial<OhMyOpenCodeConfig>
|
||||
config: Partial<OhMyOpenCodeConfig>,
|
||||
ctx?: PluginInput,
|
||||
): ToolDefinition {
|
||||
return tool({
|
||||
description: `Create a new task with auto-generated ID and threadID recording.
|
||||
@@ -22,7 +24,10 @@ Returns minimal response with task ID and subject.`,
|
||||
args: {
|
||||
subject: tool.schema.string().describe("Task subject (required)"),
|
||||
description: tool.schema.string().optional().describe("Task description"),
|
||||
activeForm: tool.schema.string().optional().describe("Active form (present continuous)"),
|
||||
activeForm: tool.schema
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Active form (present continuous)"),
|
||||
metadata: tool.schema
|
||||
.record(tool.schema.string(), tool.schema.unknown())
|
||||
.optional()
|
||||
@@ -39,27 +44,28 @@ Returns minimal response with task ID and subject.`,
|
||||
parentID: tool.schema.string().optional().describe("Parent task ID"),
|
||||
},
|
||||
execute: async (args, context) => {
|
||||
return handleCreate(args, config, context)
|
||||
return handleCreate(args, config, ctx, context);
|
||||
},
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
async function handleCreate(
|
||||
args: Record<string, unknown>,
|
||||
config: Partial<OhMyOpenCodeConfig>,
|
||||
context: { sessionID: string }
|
||||
ctx: PluginInput | undefined,
|
||||
context: { sessionID: string },
|
||||
): Promise<string> {
|
||||
try {
|
||||
const validatedArgs = TaskCreateInputSchema.parse(args)
|
||||
const taskDir = getTaskDir(config)
|
||||
const lock = acquireLock(taskDir)
|
||||
const validatedArgs = TaskCreateInputSchema.parse(args);
|
||||
const taskDir = getTaskDir(config);
|
||||
const lock = acquireLock(taskDir);
|
||||
|
||||
if (!lock.acquired) {
|
||||
return JSON.stringify({ error: "task_lock_unavailable" })
|
||||
return JSON.stringify({ error: "task_lock_unavailable" });
|
||||
}
|
||||
|
||||
try {
|
||||
const taskId = generateTaskId()
|
||||
const taskId = generateTaskId();
|
||||
const task: TaskObject = {
|
||||
id: taskId,
|
||||
subject: validatedArgs.subject,
|
||||
@@ -72,26 +78,29 @@ async function handleCreate(
|
||||
repoURL: validatedArgs.repoURL,
|
||||
parentID: validatedArgs.parentID,
|
||||
threadID: context.sessionID,
|
||||
}
|
||||
};
|
||||
|
||||
const validatedTask = TaskObjectSchema.parse(task)
|
||||
writeJsonAtomic(join(taskDir, `${taskId}.json`), validatedTask)
|
||||
const validatedTask = TaskObjectSchema.parse(task);
|
||||
writeJsonAtomic(join(taskDir, `${taskId}.json`), validatedTask);
|
||||
|
||||
syncTaskToTodo(validatedTask)
|
||||
await syncTaskTodoUpdate(ctx, validatedTask, context.sessionID);
|
||||
|
||||
return JSON.stringify({
|
||||
task: {
|
||||
id: validatedTask.id,
|
||||
subject: validatedTask.subject,
|
||||
},
|
||||
})
|
||||
});
|
||||
} finally {
|
||||
lock.release()
|
||||
lock.release();
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error && error.message.includes("Required")) {
|
||||
return JSON.stringify({ error: "validation_error", message: error.message })
|
||||
return JSON.stringify({
|
||||
error: "validation_error",
|
||||
message: error.message,
|
||||
});
|
||||
}
|
||||
return JSON.stringify({ error: "internal_error" })
|
||||
return JSON.stringify({ error: "internal_error" });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user