diff --git a/github/index.ts b/github/index.ts index 4e1af9cf55..e8acd9a9ce 100644 --- a/github/index.ts +++ b/github/index.ts @@ -495,7 +495,6 @@ async function subscribeSessionEvents() { console.log("Subscribing to session events...") const TOOL: Record = { - todowrite: ["Todo", "\x1b[33m\x1b[1m"], bash: ["Bash", "\x1b[31m\x1b[1m"], edit: ["Edit", "\x1b[32m\x1b[1m"], glob: ["Glob", "\x1b[34m\x1b[1m"], diff --git a/packages/app/e2e/performance/timeline-stability/tools.spec.ts b/packages/app/e2e/performance/timeline-stability/tools.spec.ts index d28fdaa65f..d26968e1cb 100644 --- a/packages/app/e2e/performance/timeline-stability/tools.spec.ts +++ b/packages/app/e2e/performance/timeline-stability/tools.spec.ts @@ -33,11 +33,9 @@ test.describe("timeline tool state stability", () => { } const names = { webfetch: "webfetch", websearch: "websearch", task: "task", skill: "skill", custom: "mcp_probe" } const questionID = "prt_state_question" - const todoID = "prt_state_todo" const initial = [ ...ids.map((id) => toolPart(`prt_state_${id}`, names[id], "pending", inputs[id])), toolPart(questionID, "question", "pending", questionInput()), - toolPart(todoID, "todowrite", "pending", { todos: [{ content: "Hidden", status: "pending" }] }), textPart("prt_state_following", "Following lightweight tools"), ] const childID = "ses_timeline_child" @@ -49,7 +47,6 @@ test.describe("timeline tool state stability", () => { await timeline.send(status("busy"), 120) for (const id of ids) await timeline.waitForPart(`prt_state_${id}`) await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toHaveCount(0) - await expect(page.locator(`[data-timeline-part-id="${todoID}"]`)).toHaveCount(0) const regionIDs = [ "prt_state_webfetch", @@ -105,7 +102,6 @@ test.describe("timeline tool state stability", () => { ]), ) await expect(page.locator(`[data-timeline-part-id="${questionID}"]`)).toContainText("Keep it stable") - await expect(page.locator(`[data-timeline-part-id="${todoID}"]`)).toHaveCount(0) await expect( page.locator(`a[href$="/session/${childID}"]`, { has: page.locator('[data-component="task-tool-card"]') }), ).toBeVisible() diff --git a/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts b/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts index e6fdd5d47b..2e20d98415 100644 --- a/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts +++ b/packages/app/e2e/performance/timeline/session-timeline-stress.fixture.ts @@ -269,7 +269,6 @@ const childMessages = Array.from({ length: 4 }, (_, index) => [ ]).flat() function renderable(part: MessagePart) { - if (part.type === "tool" && part.tool === "todowrite") return false if (part.type === "text") return !!part.text.trim() if (part.type === "reasoning") return !!part.text.trim() return part.type !== "step-start" && part.type !== "step-finish" && part.type !== "patch" diff --git a/packages/app/e2e/regression/cross-server-tab-close.spec.ts b/packages/app/e2e/regression/cross-server-tab-close.spec.ts index 159b5a5067..9fd7991437 100644 --- a/packages/app/e2e/regression/cross-server-tab-close.spec.ts +++ b/packages/app/e2e/regression/cross-server-tab-close.spec.ts @@ -90,7 +90,7 @@ async function mockServers(page: Page, requests: string[]) { if (url.pathname === `/session/${current.id}`) return json(route, current) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (url.pathname === `/session/${current.id}/message`) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(url.pathname)) diff --git a/packages/app/e2e/regression/remote-tab-busy.spec.ts b/packages/app/e2e/regression/remote-tab-busy.spec.ts index 119fc7ee2d..ad7e2e1d99 100644 --- a/packages/app/e2e/regression/remote-tab-busy.spec.ts +++ b/packages/app/e2e/regression/remote-tab-busy.spec.ts @@ -65,7 +65,7 @@ async function mockServers(page: Page) { if (url.pathname === `/session/${current.id}`) return json(route, current) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (url.pathname === `/session/${current.id}/message`) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp"].includes(url.pathname)) return json(route, {}) diff --git a/packages/app/e2e/regression/session-timeline-projection.spec.ts b/packages/app/e2e/regression/session-timeline-projection.spec.ts index b6679ab4ed..45304df365 100644 --- a/packages/app/e2e/regression/session-timeline-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-projection.spec.ts @@ -35,7 +35,6 @@ test.describe("session timeline projection", () => { editPart("prt_edit"), toolPart("prt_write", "write", "completed", { filePath: "src/new.ts", content: "export const stable = true\n" }), patchPart("prt_patch"), - toolPart("prt_todo", "todowrite", "completed", { todos: [{ content: "Hidden", status: "pending" }] }), toolPart( "prt_question", "question", @@ -65,7 +64,6 @@ test.describe("session timeline projection", () => { ]) { await expect(page.locator(`[data-timeline-part-id="${id}"]`).first(), id).toBeVisible() } - await expect(page.locator('[data-timeline-part-id="prt_todo"]')).toHaveCount(0) }) test("projects gaps, dividers, assistant parts, and errors together", async ({ page }) => { diff --git a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts index 071b030078..4c2c1c4ead 100644 --- a/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts +++ b/packages/app/e2e/regression/session-timeline-tool-projection.spec.ts @@ -17,13 +17,11 @@ test("renders every tool error outcome without leaking hidden tools", async ({ p error: "The user dismissed this question", }), toolPart("prt_question_error", "question", "error", questionInput(), { error: "Question transport failed" }), - toolPart("prt_todo_error", "todowrite", "error", { todos: [] }, { error: "Hidden todo failure" }), ) await setupTimeline(page, { messages: [userMessage(), assistantMessage(parts)] }) await expect(page.locator('[data-kind="tool-error-card"]')).toHaveCount(ordinary.length + 1) await expect(page.getByText(/dismissed/i)).toBeVisible() - await expect(page.locator('[data-timeline-part-id="prt_todo_error"]')).toHaveCount(0) for (let index = 0; index < ordinary.length; index++) { await expect(page.locator(`[data-timeline-part-id="prt_error_${index}"]`)).toBeVisible() } diff --git a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts b/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts deleted file mode 100644 index 603c411d55..0000000000 --- a/packages/app/e2e/regression/session-todo-dock-navigation.spec.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { base64Encode } from "@opencode-ai/core/util/encode" -import { expect, test, type Page } from "@playwright/test" -import { mockOpenCodeServer } from "../utils/mock-server" -import { expectSessionTitle } from "../utils/waits" - -const directory = "C:/OpenCode/TodoDockNavigation" -const projectID = "proj_todo_dock_navigation" -const sourceID = "ses_todo_dock_source" -const otherID = "ses_todo_dock_other" -const sourceTitle = "Todo dock animation" -const otherTitle = "Separate session" - -const activeTodos = [ - { id: "todo-1", content: "Receive todos in the active session", status: "completed", priority: "high" }, - { id: "todo-2", content: "Keep the dock visible across tabs", status: "completed", priority: "high" }, - { id: "todo-3", content: "Close after the final todo", status: "in_progress", priority: "high" }, -] - -type EventPayload = { - directory: string - payload: Record -} - -test.use({ viewport: { width: 1440, height: 900 }, reducedMotion: "no-preference" }) - -test("animates todo lifecycle without replaying it across session tabs", async ({ page }) => { - test.setTimeout(90_000) - const events: EventPayload[] = [] - const todos: Record = { [sourceID]: [], [otherID]: [] } - - await mockOpenCodeServer(page, { - directory, - project: { - id: projectID, - worktree: directory, - vcs: "git", - name: "todo-dock-navigation", - time: { created: 1700000000000, updated: 1700000000000 }, - sandboxes: [], - }, - provider: { - all: [ - { - id: "opencode", - name: "OpenCode", - models: { - "claude-opus-4-6": { - id: "claude-opus-4-6", - name: "Claude Opus 4.6", - limit: { context: 200_000 }, - }, - }, - }, - ], - connected: ["opencode"], - default: { providerID: "opencode", modelID: "claude-opus-4-6" }, - }, - sessions: [session(sourceID, sourceTitle, 1700000000000), session(otherID, otherTitle, 1700000001000)], - pageMessages: () => ({ items: [] }), - events: () => events.splice(0, 1), - eventRetry: 16, - todos: (sessionID) => todos[sessionID] ?? [], - }) - await configurePage(page) - - await page.goto(sessionHref(sourceID)) - await expectSessionTitle(page, sourceTitle) - const dock = page.locator('[data-component="session-todo-dock"]') - await expect(dock).toHaveCount(0) - - events.push(statusEvent(sourceID, "busy")) - await expect(page.getByRole("button", { name: "Stop" })).toBeVisible() - - await page.waitForTimeout(700) - const opening = sampleDock(page, 1_000) - todos[sourceID] = activeTodos - events.push(todoEvent(sourceID, activeTodos)) - await expect(dock).toBeVisible() - await expect(dock.locator('[data-state="in_progress"]')).toHaveCount(1) - expect((await opening).some((sample) => sample.opacity > 0.05 && sample.opacity < 0.95)).toBe(true) - - await switchSession(page, otherID, otherTitle) - await expect(dock).toHaveCount(0) - - const returningOpen = sampleDock(page, 700) - await switchSession(page, sourceID, sourceTitle) - const openSamples = (await returningOpen).filter((sample) => sample.present) - expect(openSamples.length).toBeGreaterThan(0) - expect(openSamples[0]!.opacity).toBeGreaterThan(0.98) - expect(openSamples[0]!.height).toBeGreaterThan(70) - await expect(dock.locator('[data-state="in_progress"]')).toHaveCount(1) - - const completedTodos = activeTodos.map((todo) => ({ ...todo, status: "completed" })) - const closing = sampleDock(page, 1_000) - todos[sourceID] = completedTodos - events.push(todoEvent(sourceID, completedTodos)) - await expect(dock).toHaveCount(0) - expect((await closing).some((sample) => sample.opacity > 0.05 && sample.opacity < 0.95)).toBe(true) - todos[sourceID] = [] - events.push(todoEvent(sourceID, [])) - - await switchSession(page, otherID, otherTitle) - const returningEmpty = sampleDock(page, 700) - await switchSession(page, sourceID, sourceTitle) - await expect(dock).toHaveCount(0) - expect((await returningEmpty).every((sample) => !sample.present)).toBe(true) -}) - -function session(id: string, title: string, created: number) { - return { - id, - slug: id, - projectID, - directory, - title, - version: "dev", - time: { created, updated: created }, - } -} - -function statusEvent(sessionID: string, type: "busy" | "idle"): EventPayload { - return { - directory, - payload: { type: "session.status", properties: { sessionID, status: { type } } }, - } -} - -function todoEvent(sessionID: string, next: typeof activeTodos): EventPayload { - return { - directory, - payload: { type: "todo.updated", properties: { sessionID, todos: next } }, - } -} - -async function configurePage(page: Page) { - const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}` - await page.addInitScript( - ({ directory, dirBase64, server, sessionIDs }) => { - localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } })) - localStorage.setItem( - "opencode.global.dat:server", - JSON.stringify({ - projects: { local: [{ worktree: directory, expanded: true }] }, - lastProject: { local: directory }, - }), - ) - localStorage.setItem( - "opencode.window.browser.dat:tabs", - JSON.stringify(sessionIDs.map((sessionId) => ({ type: "session", server, dirBase64, sessionId }))), - ) - }, - { directory, dirBase64: base64Encode(directory), server, sessionIDs: [sourceID, otherID] }, - ) -} - -function sessionHref(sessionID: string) { - const server = `http://${process.env.PLAYWRIGHT_SERVER_HOST ?? "127.0.0.1"}:${process.env.PLAYWRIGHT_SERVER_PORT ?? "4096"}` - return `/server/${base64Encode(server)}/session/${sessionID}` -} - -async function switchSession(page: Page, sessionID: string, title: string) { - const href = sessionHref(sessionID) - const tab = page.locator(`[data-slot="titlebar-tabs"] a[href="${href}"]`).first() - await expect(tab).toBeVisible() - await tab.click() - await expectSessionTitle(page, title) -} - -function sampleDock(page: Page, duration: number) { - return page.evaluate(async (duration) => { - const samples: { present: boolean; height: number; opacity: number }[] = [] - const start = performance.now() - while (performance.now() - start < duration) { - const dock = document.querySelector('[data-component="session-todo-dock"]') - const clip = dock?.parentElement?.parentElement - const label = dock?.querySelector('[data-action="session-todo-toggle"] span[aria-label]') - samples.push({ - present: !!dock, - height: clip?.getBoundingClientRect().height ?? 0, - opacity: label ? Number.parseFloat(getComputedStyle(label).opacity) : 0, - }) - await new Promise(requestAnimationFrame) - } - return samples - }, duration) -} diff --git a/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts b/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts index 94afbc9a9d..6bc417af80 100644 --- a/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts +++ b/packages/app/e2e/regression/tab-navigate-mousedown.spec.ts @@ -63,7 +63,7 @@ async function mockServer(page: Page) { if (byId) return json(route, byId) if (/^\/session\/[^/]+$/.test(url.pathname)) return json(route, { name: "NotFoundError" }, 404) if (/^\/session\/[^/]+\/message$/.test(url.pathname)) return json(route, []) - if (/^\/session\/[^/]+\/(children|todo|diff)$/.test(url.pathname)) return json(route, []) + if (/^\/session\/[^/]+\/(children|diff)$/.test(url.pathname)) return json(route, []) if (["/skill", "/command", "/lsp", "/formatter", "/permission", "/question", "/vcs/diff"].includes(url.pathname)) return json(route, []) if (["/global/config", "/config", "/provider/auth", "/mcp", "/session/status"].includes(url.pathname)) diff --git a/packages/app/e2e/smoke/session-timeline.fixture.ts b/packages/app/e2e/smoke/session-timeline.fixture.ts index ff857d8179..beb2d7cf75 100644 --- a/packages/app/e2e/smoke/session-timeline.fixture.ts +++ b/packages/app/e2e/smoke/session-timeline.fixture.ts @@ -229,7 +229,6 @@ const sourceMessages = Array.from({ length: 12 }, (_, index) => [ ]).flat() function renderable(part: MessagePart) { - if (part.type === "tool" && part.tool === "todowrite") return false if (part.type === "text") return !!part.text.trim() if (part.type === "reasoning") return !!part.text.trim() return part.type !== "step-start" && part.type !== "step-finish" && part.type !== "patch" diff --git a/packages/app/e2e/utils/mock-server.ts b/packages/app/e2e/utils/mock-server.ts index 53adfd155b..c69382bba3 100644 --- a/packages/app/e2e/utils/mock-server.ts +++ b/packages/app/e2e/utils/mock-server.ts @@ -17,7 +17,6 @@ export interface MockServerConfig { onMessage?: (input: { sessionID: string; messageID: string }) => void events?: () => unknown[] eventRetry?: number - todos?: (sessionID: string) => unknown[] permissions?: unknown[] | (() => unknown[]) questions?: unknown[] | (() => unknown[]) fileList?: (path: string) => unknown | Promise @@ -96,8 +95,6 @@ export async function mockOpenCodeServer(page: Page, config: MockServerConfig) { return json(route, message) } - const todoMatch = path.match(/^\/session\/([^/]+)\/todo$/) - if (todoMatch) return json(route, config.todos?.(todoMatch[1]!) ?? []) if (/^\/session\/[^/]+\/(children|diff)$/.test(path)) return json(route, []) const messagesMatch = path.match(/^\/session\/([^/]+)\/message$/) diff --git a/packages/app/src/components/prompt-input.stories.tsx b/packages/app/src/components/prompt-input.stories.tsx index 362a741401..272079e106 100644 --- a/packages/app/src/components/prompt-input.stories.tsx +++ b/packages/app/src/components/prompt-input.stories.tsx @@ -1,8 +1,6 @@ // @ts-nocheck import { createStore } from "solid-js/store" -import type { Todo } from "@opencode-ai/sdk/v2" import { createPromptState } from "@/context/prompt" -import { SessionComposerRegion, createSessionComposerRegionController } from "@/pages/session/composer" import { createPromptInputHistory, PromptInput } from "./prompt-input" function createPromptInputStoryRuntime() { @@ -104,94 +102,6 @@ function PromptInputExample() { ) } -const todos: Todo[] = [ - { id: "todo-1", content: "Inspect the session composer animation", status: "completed" }, - { id: "todo-2", content: "Keep the dock settled on initial render", status: "in_progress" }, - { id: "todo-3", content: "Verify session navigation behavior", status: "pending" }, -] - -function PromptInputWithOpenDock() { - const input = createPromptInputStoryRuntime() - const [controls, setControls] = createStore({ - agent: "build", - activeTab: undefined as string | undefined, - todoCollapsed: false, - }) - const inputControls = { - agents: { - available: [], - options: ["build"], - get current() { - return controls.agent - }, - loading: false, - visible: true, - select: (agent?: string) => setControls("agent", agent ?? "build"), - }, - model: { - selection: { - current: () => ({ id: "claude-3-7-sonnet", name: "Claude 3.7 Sonnet", provider: { id: "anthropic" } }), - variant: { list: () => [], current: () => undefined, set: () => {} }, - }, - paid: true, - loading: false, - }, - session: { - id: "story-session", - tabs: { - active: () => controls.activeTab, - all: () => [], - open: () => {}, - setActive: (tab: string) => setControls("activeTab", tab), - }, - reviewPanel: { opened: () => false, open: () => {} }, - }, - newLayoutDesigns: true, - } - const state = { - blocked: () => false, - questionRequest: () => undefined, - permissionRequest: () => undefined, - permissionResponding: () => false, - decide: () => {}, - todos: () => todos, - dock: () => true, - closing: () => false, - opening: () => false, - } - return ( - "story-session", - sessionID: () => "story-session", - prompt: input.state, - ready: () => true, - centered: () => false, - todo: { - collapsed: () => controls.todoCollapsed, - onToggle: () => setControls("todoCollapsed", (collapsed) => !collapsed), - }, - followup: () => undefined, - revert: () => undefined, - onResponseSubmit: () => {}, - openParent: () => {}, - setPromptRef: () => {}, - setDockRef: () => {}, - })} - promptInput={ - {}} - newSessionWorktree="" - onNewSessionWorktreeReset={() => {}} - /> - } - /> - ) -} - export default { title: "App/PromptInput", id: "app-prompt-input", @@ -206,12 +116,3 @@ export const Basic = { ), } - -export const DockAlreadyOpen = { - render: () => ( -
-

Prompt Input with open Todo dock

- -
- ), -} diff --git a/packages/app/src/components/prompt-input/submit.ts b/packages/app/src/components/prompt-input/submit.ts index 05d978a947..cba1e4c885 100644 --- a/packages/app/src/components/prompt-input/submit.ts +++ b/packages/app/src/components/prompt-input/submit.ts @@ -221,8 +221,6 @@ export function createPromptSubmit(input: PromptSubmitInput) { const sessionID = params.id if (!sessionID) return Promise.resolve() - serverSync().session.set("todo", sessionID, []) - input.onAbort?.() const key = pendingKey(sessionID) diff --git a/packages/app/src/context/directory-sync.ts b/packages/app/src/context/directory-sync.ts index 68e6b19cef..7ccd6e975e 100644 --- a/packages/app/src/context/directory-sync.ts +++ b/packages/app/src/context/directory-sync.ts @@ -11,7 +11,6 @@ const sessionFields = new Set([ "session_status", "session_working", "session_diff", - "todo", "permission", "question", "message", @@ -115,7 +114,6 @@ export const createDirSyncContext = ( index(sessionID) }, diff: serverSync.session.diff, - todo: serverSync.session.todo, history: serverSync.session.history, evict(sessionID: string) { serverSync.session.evict(sessionID) diff --git a/packages/app/src/context/global-sync/bootstrap.test.ts b/packages/app/src/context/global-sync/bootstrap.test.ts index 40735fb822..872f0929c8 100644 --- a/packages/app/src/context/global-sync/bootstrap.test.ts +++ b/packages/app/src/context/global-sync/bootstrap.test.ts @@ -30,7 +30,6 @@ function directoryState() { return this.session_status[id]?.type !== "idle" }, session_diff: {}, - todo: {}, permission: {}, question: {}, mcp_ready: true, diff --git a/packages/app/src/context/global-sync/child-store.ts b/packages/app/src/context/global-sync/child-store.ts index 53b9536182..66e40f66ec 100644 --- a/packages/app/src/context/global-sync/child-store.ts +++ b/packages/app/src/context/global-sync/child-store.ts @@ -223,7 +223,6 @@ export function createChildStoreManager(input: { return (type ?? "idle") !== "idle" }, session_diff: {}, - todo: {}, permission: {}, question: {}, get mcp_ready() { diff --git a/packages/app/src/context/global-sync/event-reducer.test.ts b/packages/app/src/context/global-sync/event-reducer.test.ts index 2811e6e3c6..8e2113709b 100644 --- a/packages/app/src/context/global-sync/event-reducer.test.ts +++ b/packages/app/src/context/global-sync/event-reducer.test.ts @@ -72,7 +72,6 @@ const baseState = (input: Partial = {}) => sessionTotal: 0, session_status: {}, session_diff: {}, - todo: {}, permission: {}, question: {}, mcp: {}, @@ -216,7 +215,6 @@ describe("applyDirectoryEvent", () => { message: { ses_1: [message] }, part: { [message.id]: [textPart("prt_1", "ses_1", message.id)] }, session_diff: { ses_1: [] }, - todo: { ses_1: [] }, permission: { ses_1: [] }, question: { ses_1: [] }, session_status: { ses_1: { type: "busy" } }, @@ -237,7 +235,6 @@ describe("applyDirectoryEvent", () => { expect(store.message.ses_1).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff.ses_1).toBeUndefined() - expect(store.todo.ses_1).toBeUndefined() expect(store.permission.ses_1).toBeUndefined() expect(store.question.ses_1).toBeUndefined() expect(store.session_status.ses_1).toBeUndefined() @@ -262,7 +259,6 @@ describe("applyDirectoryEvent", () => { message: { [item.info.id]: [message] }, part: { [message.id]: [textPart("prt_1", item.info.id, message.id)] }, session_diff: { [item.info.id]: [] }, - todo: { [item.info.id]: [] }, permission: { [item.info.id]: [] }, question: { [item.info.id]: [] }, session_status: { [item.info.id]: { type: "busy" } }, @@ -283,7 +279,6 @@ describe("applyDirectoryEvent", () => { expect(store.message[item.info.id]).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff[item.info.id]).toBeUndefined() - expect(store.todo[item.info.id]).toBeUndefined() expect(store.permission[item.info.id]).toBeUndefined() expect(store.question[item.info.id]).toBeUndefined() expect(store.session_status[item.info.id]).toBeUndefined() @@ -294,7 +289,6 @@ describe("applyDirectoryEvent", () => { const dropped = rootSession({ id: "ses_b" }) const kept = rootSession({ id: "ses_a" }) const message = userMessage("msg_1", dropped.id) - const todos: string[] = [] const [store, setStore] = createStore( baseState({ limit: 1, @@ -302,7 +296,6 @@ describe("applyDirectoryEvent", () => { message: { [dropped.id]: [message] }, part: { [message.id]: [textPart("prt_1", dropped.id, message.id)] }, session_diff: { [dropped.id]: [] }, - todo: { [dropped.id]: [] }, permission: { [dropped.id]: [] }, question: { [dropped.id]: [] }, session_status: { [dropped.id]: { type: "busy" } }, @@ -316,21 +309,15 @@ describe("applyDirectoryEvent", () => { push() {}, directory: "/tmp", loadLsp() {}, - setSessionTodo(sessionID, value) { - if (value !== undefined) return - todos.push(sessionID) - }, }) expect(store.session.map((x) => x.id)).toEqual([kept.id]) expect(store.message[dropped.id]).toBeUndefined() expect(store.part[message.id]).toBeUndefined() expect(store.session_diff[dropped.id]).toBeUndefined() - expect(store.todo[dropped.id]).toBeUndefined() expect(store.permission[dropped.id]).toBeUndefined() expect(store.question[dropped.id]).toBeUndefined() expect(store.session_status[dropped.id]).toBeUndefined() - expect(todos).toEqual([dropped.id]) }) test("cleanupDroppedSessionCaches clears part-only orphan state", () => { diff --git a/packages/app/src/context/global-sync/event-reducer.ts b/packages/app/src/context/global-sync/event-reducer.ts index 40b7acbbd3..935fc14e33 100644 --- a/packages/app/src/context/global-sync/event-reducer.ts +++ b/packages/app/src/context/global-sync/event-reducer.ts @@ -9,7 +9,6 @@ import type { Session, SessionStatus, FileDiffInfo, - Todo, } from "@opencode-ai/sdk/v2/client" import type { State, VcsCache } from "./types" import { trimSessions } from "./session-trim" @@ -19,7 +18,6 @@ import { diffs as list, message as clean } from "@/utils/diffs" const SKIP_PARTS = new Set(["patch", "step-start", "step-finish"]) const SESSION_CONTENT_EVENTS = new Set([ "session.diff", - "todo.updated", "session.status", "message.updated", "message.removed", @@ -62,13 +60,8 @@ export function applyGlobalEvent(input: { ) } -function cleanupSessionCaches( - setStore: SetStoreFunction, - sessionID: string, - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, -) { +function cleanupSessionCaches(setStore: SetStoreFunction, sessionID: string) { if (!sessionID) return - setSessionTodo?.(sessionID, undefined) setStore( produce((draft) => { dropSessionCaches(draft, [sessionID]) @@ -76,17 +69,11 @@ function cleanupSessionCaches( ) } -export function cleanupDroppedSessionCaches( - store: Store, - setStore: SetStoreFunction, - next: Session[], - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void, -) { +export function cleanupDroppedSessionCaches(store: Store, setStore: SetStoreFunction, next: Session[]) { const keep = new Set(next.map((item) => item.id)) const stale = [ ...Object.keys(store.message), ...Object.keys(store.session_diff), - ...Object.keys(store.todo), ...Object.keys(store.permission), ...Object.keys(store.question), ...Object.keys(store.session_status), @@ -95,9 +82,6 @@ export function cleanupDroppedSessionCaches( .filter((sessionID): sessionID is string => !!sessionID), ].filter((sessionID, index, list) => !keep.has(sessionID) && list.indexOf(sessionID) === index) if (stale.length === 0) return - for (const sessionID of stale) { - setSessionTodo?.(sessionID, undefined) - } setStore( produce((draft) => { dropSessionCaches(draft, stale) @@ -114,7 +98,6 @@ export function applyDirectoryEvent(input: { loadLsp: () => void loadReferences?: () => void vcsCache?: VcsCache - setSessionTodo?: (sessionID: string, todos: Todo[] | undefined) => void retainedLimit?: number sessionContent?: boolean permission?: State["permission"] @@ -138,7 +121,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit, permission: input.permission ?? input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) - cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed) if (!info.parentID) input.setStore("sessionTotal", (value) => value + 1) break } @@ -155,7 +138,7 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break @@ -168,7 +151,7 @@ export function applyDirectoryEvent(input: { next.splice(result.index, 0, info) const trimmed = trimSessions(next, { limit, permission: input.permission ?? input.store.permission }) input.setStore("session", reconcile(trimmed, { key: "id" })) - cleanupDroppedSessionCaches(input.store, input.setStore, trimmed, input.setSessionTodo) + cleanupDroppedSessionCaches(input.store, input.setStore, trimmed) break } case "session.deleted": { @@ -182,7 +165,7 @@ export function applyDirectoryEvent(input: { }), ) } - cleanupSessionCaches(input.setStore, info.id, input.setSessionTodo) + cleanupSessionCaches(input.setStore, info.id) if (info.parentID) break input.setStore("sessionTotal", (value) => Math.max(0, value - 1)) break @@ -192,12 +175,6 @@ export function applyDirectoryEvent(input: { input.setStore("session_diff", props.sessionID, reconcile(list(props.diff), { key: "file" })) break } - case "todo.updated": { - const props = event.properties as { sessionID: string; todos: Todo[] } - input.setStore("todo", props.sessionID, reconcile(props.todos, { key: "id" })) - input.setSessionTodo?.(props.sessionID, props.todos) - break - } case "session.status": { const props = event.properties as { sessionID: string; status: SessionStatus } input.setStore("session_status", props.sessionID, reconcile(props.status)) diff --git a/packages/app/src/context/global-sync/session-cache.test.ts b/packages/app/src/context/global-sync/session-cache.test.ts index 3dda5a5429..41034186e6 100644 --- a/packages/app/src/context/global-sync/session-cache.test.ts +++ b/packages/app/src/context/global-sync/session-cache.test.ts @@ -6,7 +6,6 @@ import type { QuestionRequest, SessionStatus, FileDiffInfo, - Todo, } from "@opencode-ai/sdk/v2/client" import { dropSessionCaches, pickSessionCacheEvictions } from "./session-cache" @@ -34,7 +33,6 @@ describe("app session cache", () => { const store: { session_status: Record session_diff: Record - todo: Record message: Record part: Record permission: Record @@ -43,7 +41,6 @@ describe("app session cache", () => { } = { session_status: { ses_1: { type: "busy" } as SessionStatus }, session_diff: { ses_1: [] }, - todo: { ses_1: [] as Todo[] }, message: {}, part: { msg_1: [part("prt_1", "ses_1", "msg_1")] }, permission: { ses_1: [] as PermissionRequest[] }, @@ -56,7 +53,6 @@ describe("app session cache", () => { expect(store.message.ses_1).toBeUndefined() expect(store.part.msg_1).toBeUndefined() expect(store.part_text_accum_delta.prt_1).toBeUndefined() - expect(store.todo.ses_1).toBeUndefined() expect(store.session_diff.ses_1).toBeUndefined() expect(store.session_status.ses_1).toBeUndefined() expect(store.permission.ses_1).toBeUndefined() @@ -68,7 +64,6 @@ describe("app session cache", () => { const store: { session_status: Record session_diff: Record - todo: Record message: Record part: Record permission: Record @@ -77,7 +72,6 @@ describe("app session cache", () => { } = { session_status: {}, session_diff: {}, - todo: {}, message: { ses_1: [m] }, part: { [m.id]: [part("prt_1", "ses_1", m.id)] }, permission: {}, diff --git a/packages/app/src/context/global-sync/session-cache.ts b/packages/app/src/context/global-sync/session-cache.ts index 39535abe2f..6f2c3dc540 100644 --- a/packages/app/src/context/global-sync/session-cache.ts +++ b/packages/app/src/context/global-sync/session-cache.ts @@ -5,7 +5,6 @@ import type { QuestionRequest, SessionStatus, FileDiffInfo, - Todo, } from "@opencode-ai/sdk/v2/client" export const SESSION_CACHE_LIMIT = 40 @@ -13,7 +12,6 @@ export const SESSION_CACHE_LIMIT = 40 type SessionCache = { session_status: Record session_diff: Record - todo: Record message: Record part: Record permission: Record @@ -36,7 +34,6 @@ export function dropSessionCaches(store: SessionCache, sessionIDs: Iterable s().todoCollapsed ?? false, - set(collapsed: boolean) { - const session = key() - const current = store.sessionView[session] - if (!current) { - setStore("sessionView", session, { scroll: {}, todoCollapsed: collapsed }) - } else { - setStore("sessionView", session, "todoCollapsed", collapsed) - } - }, - }, terminal: { opened: terminalOpened, open() { diff --git a/packages/app/src/context/server-session.test.ts b/packages/app/src/context/server-session.test.ts index 46a0dc8266..fb4443a3ef 100644 --- a/packages/app/src/context/server-session.test.ts +++ b/packages/app/src/context/server-session.test.ts @@ -151,7 +151,6 @@ function setup(sessions: Record) { return response() }, diff: async () => ({ data: [] }), - todo: async () => ({ data: [] }), }, } as unknown as OpencodeClient return { get, messages, store: createServerSession(client) } diff --git a/packages/app/src/context/server-session.ts b/packages/app/src/context/server-session.ts index a46eb744d1..12c3d8abb8 100644 --- a/packages/app/src/context/server-session.ts +++ b/packages/app/src/context/server-session.ts @@ -9,7 +9,6 @@ import type { Session, SessionStatus, FileDiffInfo, - Todo, } from "@opencode-ai/sdk/v2/client" import { batch } from "solid-js" import { createStore, produce, reconcile } from "solid-js/store" @@ -140,7 +139,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: info: {} as Record, session_status: {} as Record, session_diff: {} as Record, - todo: {} as Record, permission: {} as Record, question: {} as Record, message: {} as Record, @@ -153,7 +151,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: const requests = new Map>() const inflight = new Map>() const inflightDiff = new Map>() - const inflightTodo = new Map>() const optimistic = new Map>() const messageLoads = new Map() const pendingParts = new Map>>() @@ -199,7 +196,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: ...requests.keys(), ...inflight.keys(), ...inflightDiff.keys(), - ...inflightTodo.keys(), ...messageLoads.keys(), ...optimistic.keys(), ...Object.entries(data.permission) @@ -254,8 +250,7 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: !requests.has(sessionID) && !messageLoads.has(sessionID) && !inflight.has(sessionID) && - !inflightDiff.has(sessionID) && - !inflightTodo.has(sessionID) + !inflightDiff.has(sessionID) ) generations.delete(sessionID) } @@ -418,7 +413,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: requests.delete(sessionID) inflight.delete(sessionID) inflightDiff.delete(sessionID) - inflightTodo.delete(sessionID) messageLoads.delete(sessionID) pendingParts.delete(sessionID) orphanParts.delete(sessionID) @@ -448,7 +442,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: ...requests.keys(), ...inflight.keys(), ...inflightDiff.keys(), - ...inflightTodo.keys(), ...messageLoads.keys(), ...optimistic.keys(), ...Object.entries(data.permission) @@ -773,11 +766,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: setData("session_diff", props.sessionID, reconcile(cleanDiffs(props.diff), { key: "file" })) return } - case "todo.updated": { - const props = event.properties as { sessionID: string; todos: Todo[] } - setData("todo", props.sessionID, reconcile(props.todos, { key: "id" })) - return - } case "session.status": { const props = event.properties as { sessionID: string; status: SessionStatus } setData("session_status", props.sessionID, reconcile(props.status)) @@ -1140,17 +1128,6 @@ export function createServerSession(client: OpencodeClient, options?: { retry?: }) }) }, - todo(sessionID: string, options?: { force?: boolean }) { - touch(sessionID) - if (data.todo[sessionID] !== undefined && !options?.force) return Promise.resolve() - return runInflight(inflightTodo, sessionID, () => { - const active = generation(sessionID) - return retry(() => client.session.todo({ sessionID })).then((result) => { - if (generations.get(sessionID) !== active) return - setData("todo", sessionID, reconcile(result.data ?? [], { key: "id" })) - }) - }) - }, history: { more: (sessionID: string) => data.message[sessionID] !== undefined && diff --git a/packages/app/src/i18n/ar.ts b/packages/app/src/i18n/ar.ts index c60920d107..b824354401 100644 --- a/packages/app/src/i18n/ar.ts +++ b/packages/app/src/i18n/ar.ts @@ -577,9 +577,6 @@ export const dict = { "session.messages.loading": "جارٍ تحميل الرسائل...", "session.messages.jumpToLatest": "الانتقال إلى الأحدث", "session.context.addToContext": "إضافة {{selection}} إلى السياق", - "session.todo.title": "المهام", - "session.todo.collapse": "طي", - "session.todo.expand": "توسيع", "session.question.minimize": "تصغير السؤال", "session.question.restore": "استعادة السؤال", "session.question.pending.one": "{{count}} سؤال معلق", @@ -867,8 +864,6 @@ export const dict = { "settings.permissions.tool.skill.description": "تحميل مهارة بالاسم", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "تشغيل استعلامات خادم اللغة", - "settings.permissions.tool.todowrite.title": "كتابة المهام", - "settings.permissions.tool.todowrite.description": "تحديث قائمة المهام", "settings.permissions.tool.webfetch.title": "جلب الويب", "settings.permissions.tool.webfetch.description": "جلب محتوى من عنوان URL", "settings.permissions.tool.websearch.title": "بحث الويب", @@ -931,7 +926,6 @@ export const dict = { "session.review.noVcs.createGit.description": "تتبع ومراجعة والتراجع عن التغييرات في هذا المشروع", "session.review.noVcs.createGit.actionLoading": "جاري إنشاء مستودع Git...", "session.review.noVcs.createGit.action": "إنشاء مستودع Git", - "session.todo.progress": "تم إكمال {{done}} من {{total}} مهام", "session.question.progress": "{{current}} من {{total}} أسئلة", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "مستكشف الملفات", diff --git a/packages/app/src/i18n/br.ts b/packages/app/src/i18n/br.ts index 12911744e2..f431dbc8fc 100644 --- a/packages/app/src/i18n/br.ts +++ b/packages/app/src/i18n/br.ts @@ -582,9 +582,6 @@ export const dict = { "session.messages.loading": "Carregando mensagens...", "session.messages.jumpToLatest": "Ir para a mais recente", "session.context.addToContext": "Adicionar {{selection}} ao contexto", - "session.todo.title": "Tarefas", - "session.todo.collapse": "Recolher", - "session.todo.expand": "Expandir", "session.question.minimize": "Minimizar pergunta", "session.question.restore": "Restaurar pergunta", "session.question.pending.one": "{{count}} pergunta pendente", @@ -880,8 +877,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Carregar uma habilidade por nome", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Executar consultas de servidor de linguagem", - "settings.permissions.tool.todowrite.title": "Escrever Tarefas", - "settings.permissions.tool.todowrite.description": "Atualizar a lista de tarefas", "settings.permissions.tool.webfetch.title": "Buscar Web", "settings.permissions.tool.webfetch.description": "Buscar conteúdo de uma URL", "settings.permissions.tool.websearch.title": "Pesquisa Web", @@ -944,7 +939,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Rastreie, revise e desfaça alterações neste projeto", "session.review.noVcs.createGit.actionLoading": "Criando repositório Git...", "session.review.noVcs.createGit.action": "Criar repositório Git", - "session.todo.progress": "{{done}} de {{total}} tarefas concluídas", "session.question.progress": "{{current}} de {{total}} perguntas", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorador de Arquivos", diff --git a/packages/app/src/i18n/bs.ts b/packages/app/src/i18n/bs.ts index 086ecc1b4c..e5d48e5d19 100644 --- a/packages/app/src/i18n/bs.ts +++ b/packages/app/src/i18n/bs.ts @@ -637,9 +637,6 @@ export const dict = { "session.messages.jumpToLatest": "Idi na najnovije", "session.context.addToContext": "Dodaj {{selection}} u kontekst", - "session.todo.title": "Zadaci", - "session.todo.collapse": "Sažmi", - "session.todo.expand": "Proširi", "session.question.minimize": "Minimiziraj pitanje", "session.question.restore": "Vrati pitanje", "session.question.pending.one": "{{count}} pitanje na čekanju", @@ -954,8 +951,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Učitaj vještinu po nazivu", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Pokreni upite jezičnog servera", - "settings.permissions.tool.todowrite.title": "Ažuriranje liste zadataka", - "settings.permissions.tool.todowrite.description": "Ažuriraj listu zadataka", "settings.permissions.tool.webfetch.title": "Web preuzimanje", "settings.permissions.tool.webfetch.description": "Preuzmi sadržaj sa URL-a", "settings.permissions.tool.websearch.title": "Web pretraga", @@ -1020,7 +1015,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Pratite, pregledajte i poništite promjene u ovom projektu", "session.review.noVcs.createGit.actionLoading": "Kreiranje Git repozitorija...", "session.review.noVcs.createGit.action": "Kreiraj Git repozitorij", - "session.todo.progress": "{{done}} od {{total}} zadataka završeno", "session.question.progress": "{{current}} od {{total}} pitanja", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "File Explorer", diff --git a/packages/app/src/i18n/da.ts b/packages/app/src/i18n/da.ts index 859bea230b..8435d9e378 100644 --- a/packages/app/src/i18n/da.ts +++ b/packages/app/src/i18n/da.ts @@ -632,9 +632,6 @@ export const dict = { "session.messages.jumpToLatest": "Gå til seneste", "session.context.addToContext": "Tilføj {{selection}} til kontekst", - "session.todo.title": "Opgaver", - "session.todo.collapse": "Skjul", - "session.todo.expand": "Udvid", "session.question.minimize": "Minimer spørgsmål", "session.question.restore": "Gendan spørgsmål", "session.question.pending.one": "{{count}} afventende spørgsmål", @@ -946,8 +943,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Indlæs en færdighed efter navn", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Kør sprogserverforespørgsler", - "settings.permissions.tool.todowrite.title": "Skriv To-do", - "settings.permissions.tool.todowrite.description": "Opdater to-do listen", "settings.permissions.tool.webfetch.title": "Webhentning", "settings.permissions.tool.webfetch.description": "Hent indhold fra en URL", "settings.permissions.tool.websearch.title": "Websøgning", @@ -1012,7 +1007,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Spor, gennemgå og fortryd ændringer i dette projekt", "session.review.noVcs.createGit.actionLoading": "Opretter Git-repository...", "session.review.noVcs.createGit.action": "Opret Git-repository", - "session.todo.progress": "{{done}} af {{total}} opgaver fuldført", "session.question.progress": "{{current}} af {{total}} spørgsmål", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Stifinder", diff --git a/packages/app/src/i18n/de.ts b/packages/app/src/i18n/de.ts index c96dc232a5..2895f57837 100644 --- a/packages/app/src/i18n/de.ts +++ b/packages/app/src/i18n/de.ts @@ -591,9 +591,6 @@ export const dict = { "session.messages.loading": "Lade Nachrichten...", "session.messages.jumpToLatest": "Zum neuesten springen", "session.context.addToContext": "{{selection}} zum Kontext hinzufügen", - "session.todo.title": "Aufgaben", - "session.todo.collapse": "Einklappen", - "session.todo.expand": "Ausklappen", "session.question.minimize": "Frage minimieren", "session.question.restore": "Frage wiederherstellen", "session.question.pending.one": "{{count}} ausstehende Frage", @@ -892,8 +889,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Eine Fähigkeit nach Namen laden", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Language-Server-Abfragen ausführen", - "settings.permissions.tool.todowrite.title": "Todo schreiben", - "settings.permissions.tool.todowrite.description": "Die Todo-Liste aktualisieren", "settings.permissions.tool.webfetch.title": "Web-Abruf", "settings.permissions.tool.webfetch.description": "Inhalt von einer URL abrufen", "settings.permissions.tool.websearch.title": "Web-Suche", @@ -957,7 +952,6 @@ export const dict = { "Änderungen in diesem Projekt verfolgen, überprüfen und rückgängig machen", "session.review.noVcs.createGit.actionLoading": "Git-Repository wird erstellt...", "session.review.noVcs.createGit.action": "Git-Repository erstellen", - "session.todo.progress": "{{done}} von {{total}} Aufgaben erledigt", "session.question.progress": "{{current}} von {{total}} Fragen", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Datei-Explorer", diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index 3da8183bb7..559c6ba17b 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -659,10 +659,6 @@ export const dict = { "session.messages.jumpToLatest": "Jump to latest", "session.context.addToContext": "Add {{selection}} to context", - "session.todo.title": "Todos", - "session.todo.collapse": "Collapse", - "session.todo.expand": "Expand", - "session.todo.progress": "{{done}} of {{total}} todos completed", "session.question.progress": "{{current}} of {{total}} questions", "session.question.minimize": "Minimize question", "session.question.restore": "Restore question", @@ -1040,8 +1036,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Load a skill by name", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Run language server queries", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Update the todo list", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Fetch content from a URL", "settings.permissions.tool.websearch.title": "Web Search", diff --git a/packages/app/src/i18n/es.ts b/packages/app/src/i18n/es.ts index 5ef7862cd6..ec6205cf99 100644 --- a/packages/app/src/i18n/es.ts +++ b/packages/app/src/i18n/es.ts @@ -638,9 +638,6 @@ export const dict = { "session.messages.jumpToLatest": "Ir al último", "session.context.addToContext": "Añadir {{selection}} al contexto", - "session.todo.title": "Tareas", - "session.todo.collapse": "Contraer", - "session.todo.expand": "Expandir", "session.question.minimize": "Minimizar pregunta", "session.question.restore": "Restaurar pregunta", "session.question.pending.one": "{{count}} pregunta pendiente", @@ -962,8 +959,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Cargar una habilidad por nombre", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Ejecutar consultas de servidor de lenguaje", - "settings.permissions.tool.todowrite.title": "Escribir Todo", - "settings.permissions.tool.todowrite.description": "Actualizar la lista de tareas", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Obtener contenido de una URL", "settings.permissions.tool.websearch.title": "Búsqueda Web", @@ -1028,7 +1023,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Rastrea, revisa y deshaz cambios en este proyecto", "session.review.noVcs.createGit.actionLoading": "Creando repositorio Git...", "session.review.noVcs.createGit.action": "Crear repositorio Git", - "session.todo.progress": "{{done}} de {{total}} tareas completadas", "session.question.progress": "{{current}} de {{total}} preguntas", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorador de archivos", diff --git a/packages/app/src/i18n/fr.ts b/packages/app/src/i18n/fr.ts index 77a543180d..c5da265344 100644 --- a/packages/app/src/i18n/fr.ts +++ b/packages/app/src/i18n/fr.ts @@ -587,9 +587,6 @@ export const dict = { "session.messages.loading": "Chargement des messages...", "session.messages.jumpToLatest": "Aller au dernier", "session.context.addToContext": "Ajouter {{selection}} au contexte", - "session.todo.title": "Tâches", - "session.todo.collapse": "Réduire", - "session.todo.expand": "Développer", "session.question.minimize": "Réduire la question", "session.question.restore": "Restaurer la question", "session.question.pending.one": "{{count}} question en attente", @@ -891,8 +888,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Charger une compétence par son nom", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Exécuter des requêtes de serveur de langage", - "settings.permissions.tool.todowrite.title": "Écrire Todo", - "settings.permissions.tool.todowrite.description": "Mettre à jour la liste de tâches", "settings.permissions.tool.webfetch.title": "Récupération Web", "settings.permissions.tool.webfetch.description": "Récupérer le contenu d'une URL", "settings.permissions.tool.websearch.title": "Recherche Web", @@ -955,7 +950,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Suivre, examiner et annuler les modifications dans ce projet", "session.review.noVcs.createGit.actionLoading": "Création du dépôt Git...", "session.review.noVcs.createGit.action": "Créer un dépôt Git", - "session.todo.progress": "{{done}} tâches sur {{total}} terminées", "session.question.progress": "{{current}} questions sur {{total}}", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Explorateur de fichiers", diff --git a/packages/app/src/i18n/ja.ts b/packages/app/src/i18n/ja.ts index 24d1a29e8a..435def9b19 100644 --- a/packages/app/src/i18n/ja.ts +++ b/packages/app/src/i18n/ja.ts @@ -579,9 +579,6 @@ export const dict = { "session.messages.loading": "メッセージを読み込み中...", "session.messages.jumpToLatest": "最新へジャンプ", "session.context.addToContext": "{{selection}}をコンテキストに追加", - "session.todo.title": "ToDo", - "session.todo.collapse": "折りたたむ", - "session.todo.expand": "展開", "session.question.minimize": "質問を最小化", "session.question.restore": "質問を復元", "session.question.pending.one": "{{count}}件の保留中の質問", @@ -874,8 +871,6 @@ export const dict = { "settings.permissions.tool.skill.description": "名前によるスキルの読み込み", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "言語サーバークエリの実行", - "settings.permissions.tool.todowrite.title": "Todo書き込み", - "settings.permissions.tool.todowrite.description": "Todoリストの更新", "settings.permissions.tool.webfetch.title": "Web取得", "settings.permissions.tool.webfetch.description": "URLからコンテンツを取得", "settings.permissions.tool.websearch.title": "Web検索", @@ -938,7 +933,6 @@ export const dict = { "session.review.noVcs.createGit.description": "このプロジェクトの変更を追跡、レビュー、元に戻す", "session.review.noVcs.createGit.actionLoading": "Git リポジトリを作成中...", "session.review.noVcs.createGit.action": "Git リポジトリを作成", - "session.todo.progress": "{{done}} 個中 {{total}} 個の Todo が完了", "session.question.progress": "{{total}} 問中 {{current}} 問", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "エクスプローラー", diff --git a/packages/app/src/i18n/ko.ts b/packages/app/src/i18n/ko.ts index cf789f5644..c6e7f142bc 100644 --- a/packages/app/src/i18n/ko.ts +++ b/packages/app/src/i18n/ko.ts @@ -471,9 +471,6 @@ export const dict = { "session.messages.loading": "메시지 로드 중...", "session.messages.jumpToLatest": "최신으로 이동", "session.context.addToContext": "컨텍스트에 {{selection}} 추가", - "session.todo.title": "할 일", - "session.todo.collapse": "접기", - "session.todo.expand": "펼치기", "session.followupDock.summary.one": "{{count}}개의 대기 중인 메시지", "session.followupDock.summary.other": "{{count}}개의 대기 중인 메시지", "session.followupDock.sendNow": "지금 전송", @@ -721,8 +718,6 @@ export const dict = { "settings.permissions.tool.skill.description": "이름으로 기술 로드", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "언어 서버 쿼리 실행", - "settings.permissions.tool.todowrite.title": "할 일 쓰기", - "settings.permissions.tool.todowrite.description": "할 일 목록 업데이트", "settings.permissions.tool.webfetch.title": "웹 가져오기", "settings.permissions.tool.webfetch.description": "URL에서 콘텐츠 가져오기", "settings.permissions.tool.websearch.title": "웹 검색", @@ -785,7 +780,6 @@ export const dict = { "session.review.noVcs.createGit.description": "이 프로젝트의 변경 사항을 추적, 검토 및 실행 취소", "session.review.noVcs.createGit.actionLoading": "Git 저장소 생성 중...", "session.review.noVcs.createGit.action": "Git 저장소 생성", - "session.todo.progress": "{{total}}개의 할 일 중 {{done}}개 완료", "session.question.progress": "{{total}}개의 질문 중 {{current}}개", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "파일 탐색기", diff --git a/packages/app/src/i18n/no.ts b/packages/app/src/i18n/no.ts index f3faa31382..e066ff379b 100644 --- a/packages/app/src/i18n/no.ts +++ b/packages/app/src/i18n/no.ts @@ -532,9 +532,6 @@ export const dict = { "session.messages.jumpToLatest": "Hopp til nyeste", "session.context.addToContext": "Legg til {{selection}} i kontekst", - "session.todo.title": "Oppgaver", - "session.todo.collapse": "Skjul", - "session.todo.expand": "Utvid", "session.followupDock.summary.one": "{{count}} melding i kø", "session.followupDock.summary.other": "{{count}} meldinger i kø", "session.followupDock.sendNow": "Send nå", @@ -806,8 +803,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Last en ferdighet etter navn", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Kjør språkserverforespørsler", - "settings.permissions.tool.todowrite.title": "Skriv gjøremål", - "settings.permissions.tool.todowrite.description": "Oppdater gjøremålslisten", "settings.permissions.tool.webfetch.title": "Webhenting", "settings.permissions.tool.webfetch.description": "Hent innhold fra en URL", "settings.permissions.tool.websearch.title": "Websøk", @@ -872,7 +867,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Spor, gjennomgå og angre endringer i dette prosjektet", "session.review.noVcs.createGit.actionLoading": "Oppretter Git-depot...", "session.review.noVcs.createGit.action": "Opprett Git-depot", - "session.todo.progress": "{{done}} av {{total}} oppgaver fullført", "session.question.progress": "{{current}} av {{total}} spørsmål", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Filutforsker", diff --git a/packages/app/src/i18n/pl.ts b/packages/app/src/i18n/pl.ts index 295d8e615a..9bc10269fa 100644 --- a/packages/app/src/i18n/pl.ts +++ b/packages/app/src/i18n/pl.ts @@ -582,9 +582,6 @@ export const dict = { "session.messages.loading": "Ładowanie wiadomości...", "session.messages.jumpToLatest": "Przejdź do najnowszych", "session.context.addToContext": "Dodaj {{selection}} do kontekstu", - "session.todo.title": "Zadania", - "session.todo.collapse": "Zwiń", - "session.todo.expand": "Rozwiń", "session.question.minimize": "Zminimalizuj pytanie", "session.question.restore": "Przywróć pytanie", "session.question.pending.one": "{{count}} oczekujące pytanie", @@ -879,8 +876,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Ładowanie umiejętności według nazwy", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Uruchamianie zapytań serwera językowego", - "settings.permissions.tool.todowrite.title": "Zapis Todo", - "settings.permissions.tool.todowrite.description": "Aktualizacja listy zadań", "settings.permissions.tool.webfetch.title": "Pobieranie z sieci", "settings.permissions.tool.webfetch.description": "Pobieranie zawartości z adresu URL", "settings.permissions.tool.websearch.title": "Wyszukiwanie w sieci", @@ -943,7 +938,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Śledź, przeglądaj i cofaj zmiany w tym projekcie", "session.review.noVcs.createGit.actionLoading": "Tworzenie repozytorium Git...", "session.review.noVcs.createGit.action": "Utwórz repozytorium Git", - "session.todo.progress": "Ukończono {{done}} z {{total}} zadań", "session.question.progress": "{{current}} z {{total}} pytań", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Eksplorator plików", diff --git a/packages/app/src/i18n/ru.ts b/packages/app/src/i18n/ru.ts index 7ef78bb480..466f18b1c0 100644 --- a/packages/app/src/i18n/ru.ts +++ b/packages/app/src/i18n/ru.ts @@ -635,9 +635,6 @@ export const dict = { "session.messages.jumpToLatest": "Перейти к последнему", "session.context.addToContext": "Добавить {{selection}} в контекст", - "session.todo.title": "Задачи", - "session.todo.collapse": "Свернуть", - "session.todo.expand": "Развернуть", "session.question.minimize": "Свернуть вопрос", "session.question.restore": "Восстановить вопрос", "session.question.pending.one": "{{count}} вопрос без ответа", @@ -956,8 +953,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Загрузка навыка по имени", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Запросы к языковому серверу", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Обновление списка задач", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Получение контента по URL", "settings.permissions.tool.websearch.title": "Web Search", @@ -1023,7 +1018,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Отслеживайте, просматривайте и отменяйте изменения в этом проекте", "session.review.noVcs.createGit.actionLoading": "Создание репозитория Git...", "session.review.noVcs.createGit.action": "Создать репозиторий Git", - "session.todo.progress": "Выполнено {{done}} из {{total}} задач", "session.question.progress": "{{current}} из {{total}} вопросов", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Проводник", diff --git a/packages/app/src/i18n/th.ts b/packages/app/src/i18n/th.ts index 686db7407c..cd42cc46d3 100644 --- a/packages/app/src/i18n/th.ts +++ b/packages/app/src/i18n/th.ts @@ -632,9 +632,6 @@ export const dict = { "session.messages.jumpToLatest": "ไปที่ล่าสุด", "session.context.addToContext": "เพิ่ม {{selection}} ไปยังบริบท", - "session.todo.title": "สิ่งที่ต้องทำ", - "session.todo.collapse": "ย่อ", - "session.todo.expand": "ขยาย", "session.question.minimize": "ย่อคำถาม", "session.question.restore": "คืนค่าคำถาม", "session.question.pending.one": "คำถามที่รอดำเนินการ {{count}} ข้อ", @@ -942,8 +939,6 @@ export const dict = { "settings.permissions.tool.skill.description": "โหลดทักษะตามชื่อ", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "เรียกใช้การสืบค้นเซิร์ฟเวอร์ภาษา", - "settings.permissions.tool.todowrite.title": "เขียนรายการงาน", - "settings.permissions.tool.todowrite.description": "อัปเดตรายการงาน", "settings.permissions.tool.webfetch.title": "ดึงข้อมูลจากเว็บ", "settings.permissions.tool.webfetch.description": "ดึงเนื้อหาจาก URL", "settings.permissions.tool.websearch.title": "ค้นหาเว็บ", @@ -1008,7 +1003,6 @@ export const dict = { "session.review.noVcs.createGit.description": "ติดตาม ตรวจสอบ และเลิกทำสิ่งเปลี่ยนแปลงในโปรเจกต์นี้", "session.review.noVcs.createGit.actionLoading": "กำลังสร้าง Git รีโพซิทอรี...", "session.review.noVcs.createGit.action": "สร้าง Git รีโพซิทอรี", - "session.todo.progress": "เสร็จสิ้น {{done}} จาก {{total}} รายการ", "session.question.progress": "{{current}} จาก {{total}} คำถาม", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "File Explorer", diff --git a/packages/app/src/i18n/tr.ts b/packages/app/src/i18n/tr.ts index b578f89cca..c3cc62c942 100644 --- a/packages/app/src/i18n/tr.ts +++ b/packages/app/src/i18n/tr.ts @@ -642,9 +642,6 @@ export const dict = { "session.messages.jumpToLatest": "En sona atla", "session.context.addToContext": "{{selection}} bağlama ekle", - "session.todo.title": "Görevler", - "session.todo.collapse": "Daralt", - "session.todo.expand": "Genişlet", "session.question.minimize": "Soruyu küçült", "session.question.restore": "Soruyu geri yükle", "session.question.pending.one": "{{count}} bekleyen soru", @@ -962,8 +959,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Ada göre bir beceri yükle", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Dil sunucusu sorguları çalıştır", - "settings.permissions.tool.todowrite.title": "Görev Yaz", - "settings.permissions.tool.todowrite.description": "Görev listesini güncelle", "settings.permissions.tool.webfetch.title": "Web Getir", "settings.permissions.tool.webfetch.description": "Bir URL'den içerik getir", "settings.permissions.tool.websearch.title": "Web Ara", @@ -1028,7 +1023,6 @@ export const dict = { "session.review.noVcs.createGit.description": "Bu projedeki değişiklikleri takip et, incele ve geri al", "session.review.noVcs.createGit.actionLoading": "Git deposu oluşturuluyor...", "session.review.noVcs.createGit.action": "Git deposu oluştur", - "session.todo.progress": "{{total}} görevin {{done}} tanesi tamamlandı", "session.question.progress": "{{total}} sorunun {{current}} tanesi", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "Dosya Gezgini", diff --git a/packages/app/src/i18n/uk.ts b/packages/app/src/i18n/uk.ts index ff18c8e342..f4bc44eb23 100644 --- a/packages/app/src/i18n/uk.ts +++ b/packages/app/src/i18n/uk.ts @@ -663,10 +663,6 @@ export const dict = { "session.messages.jumpToLatest": "Перейти до останніх", "session.context.addToContext": "Додати {{selection}} до контексту", - "session.todo.title": "Завдання", - "session.todo.collapse": "Згорнути", - "session.todo.expand": "Розгорнути", - "session.todo.progress": "Виконано {{done}} з {{total}} завдань", "session.question.progress": "{{current}} з {{total}} запитань", "session.question.minimize": "Згорнути запитання", "session.question.restore": "Відновити запитання", @@ -1047,8 +1043,6 @@ export const dict = { "settings.permissions.tool.skill.description": "Завантаження навички за назвою", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "Виконання запитів мовного сервера", - "settings.permissions.tool.todowrite.title": "Todo Write", - "settings.permissions.tool.todowrite.description": "Оновлення списку завдань", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "Отримання вмісту з URL", "settings.permissions.tool.websearch.title": "Web Search", diff --git a/packages/app/src/i18n/zh.ts b/packages/app/src/i18n/zh.ts index 3cccc0c82d..bd12a9dba2 100644 --- a/packages/app/src/i18n/zh.ts +++ b/packages/app/src/i18n/zh.ts @@ -630,9 +630,6 @@ export const dict = { "session.messages.loading": "正在加载消息...", "session.messages.jumpToLatest": "跳转到最新", "session.context.addToContext": "将 {{selection}} 添加到上下文", - "session.todo.title": "待办事项", - "session.todo.collapse": "折叠", - "session.todo.expand": "展开", "session.question.minimize": "最小化问题", "session.question.restore": "恢复问题", "session.question.pending.one": "{{count}} 个待处理问题", @@ -935,8 +932,6 @@ export const dict = { "settings.permissions.tool.skill.description": "按名称加载技能", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "运行语言服务器查询", - "settings.permissions.tool.todowrite.title": "更新待办", - "settings.permissions.tool.todowrite.description": "更新待办列表", "settings.permissions.tool.webfetch.title": "网页获取", "settings.permissions.tool.webfetch.description": "从 URL 获取内容", "settings.permissions.tool.websearch.title": "网页搜索", @@ -1001,7 +996,6 @@ export const dict = { "session.review.noVcs.createGit.description": "在此项目中跟踪、审查和撤消更改", "session.review.noVcs.createGit.actionLoading": "正在创建 Git 仓库...", "session.review.noVcs.createGit.action": "创建 Git 仓库", - "session.todo.progress": "已完成 {{done}} 个任务(共 {{total}} 个)", "session.question.progress": "{{current}}/{{total}} 个问题", "session.header.open.finder": "访达", "session.header.open.fileExplorer": "文件资源管理器", diff --git a/packages/app/src/i18n/zht.ts b/packages/app/src/i18n/zht.ts index afe285f6e5..b2a1a6f3ad 100644 --- a/packages/app/src/i18n/zht.ts +++ b/packages/app/src/i18n/zht.ts @@ -626,9 +626,6 @@ export const dict = { "session.messages.jumpToLatest": "跳到最新", "session.context.addToContext": "將 {{selection}} 新增到上下文", - "session.todo.title": "待辦事項", - "session.todo.collapse": "折疊", - "session.todo.expand": "展開", "session.question.minimize": "最小化問題", "session.question.restore": "還原問題", "session.question.pending.one": "{{count}} 個待處理問題", @@ -931,8 +928,6 @@ export const dict = { "settings.permissions.tool.skill.description": "按名稱載入技能", "settings.permissions.tool.lsp.title": "LSP", "settings.permissions.tool.lsp.description": "執行語言伺服器查詢", - "settings.permissions.tool.todowrite.title": "更新待辦", - "settings.permissions.tool.todowrite.description": "更新待辦清單", "settings.permissions.tool.webfetch.title": "Web Fetch", "settings.permissions.tool.webfetch.description": "從 URL 取得內容", "settings.permissions.tool.websearch.title": "Web Search", @@ -997,7 +992,6 @@ export const dict = { "session.review.noVcs.createGit.description": "追蹤、檢閱及復原此專案中的變更", "session.review.noVcs.createGit.actionLoading": "正在建立 Git 儲存庫...", "session.review.noVcs.createGit.action": "建立 Git 儲存庫", - "session.todo.progress": "已完成 {{done}} 個待辦事項(共 {{total}} 個)", "session.question.progress": "{{current}}/{{total}} 個問題", "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "檔案總管", diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 2d06109bdf..bbbadb7567 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -565,8 +565,6 @@ export default function Page() { }) let reviewFrame: number | undefined - let todoFrame: number | undefined - let todoTimer: number | undefined let diffFrame: number | undefined let diffTimer: number | undefined @@ -773,41 +771,6 @@ export default function Page() { const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs - createEffect( - on( - () => { - const id = params.id - return [ - sdk().directory, - id, - id ? (sync().data.session_status[id]?.type ?? "idle") : "idle", - id ? composer.blocked() : false, - ] as const - }, - ([dir, id, status, blocked]) => { - if (todoFrame !== undefined) cancelAnimationFrame(todoFrame) - if (todoTimer !== undefined) window.clearTimeout(todoTimer) - todoFrame = undefined - todoTimer = undefined - if (!id) return - if (status === "idle" && !blocked) return - const cached = untrack(() => sync().data.todo[id] !== undefined) - - todoFrame = requestAnimationFrame(() => { - todoFrame = undefined - todoTimer = window.setTimeout(() => { - todoTimer = undefined - if (sdk().directory !== dir || params.id !== id) return - untrack(() => { - void sync().session.todo(id, cached ? { force: true } : undefined) - }) - }, 0) - }) - }, - { defer: true }, - ), - ) - createEffect( on( () => visibleUserMessages().at(-1)?.id, @@ -1882,8 +1845,6 @@ export default function Page() { onCleanup(() => { if (reviewFrame !== undefined) cancelAnimationFrame(reviewFrame) - if (todoFrame !== undefined) cancelAnimationFrame(todoFrame) - if (todoTimer !== undefined) window.clearTimeout(todoTimer) if (diffFrame !== undefined) cancelAnimationFrame(diffFrame) if (diffTimer !== undefined) window.clearTimeout(diffTimer) if (scrollStateFrame !== undefined) cancelAnimationFrame(scrollStateFrame) @@ -1898,12 +1859,7 @@ export default function Page() { sessionKey, sessionID: () => params.id, prompt, - ready: () => !store.deferRender && messagesReady(), centered, - todo: { - collapsed: () => view().todoCollapsed.get(), - onToggle: () => view().todoCollapsed.set(!view().todoCollapsed.get()), - }, followup: () => params.id && !isChildSession() ? { diff --git a/packages/app/src/pages/session/composer/session-composer-region-controller.ts b/packages/app/src/pages/session/composer/session-composer-region-controller.ts index 4073f1c191..ff425b4c20 100644 --- a/packages/app/src/pages/session/composer/session-composer-region-controller.ts +++ b/packages/app/src/pages/session/composer/session-composer-region-controller.ts @@ -1,7 +1,4 @@ -import { createResizeObserver } from "@solid-primitives/resize-observer" -import { useSpring } from "@opencode-ai/ui/motion-spring" -import { type Accessor, createEffect, createMemo, createResource, onCleanup } from "solid-js" -import { createStore } from "solid-js/store" +import { type Accessor, createEffect, createMemo, createResource } from "solid-js" import type { PromptInputState } from "@/components/prompt-input" import { useSync } from "@/context/sync" import { getSessionHandoff, setSessionHandoff } from "@/pages/session/handoff" @@ -26,12 +23,7 @@ export function createSessionComposerRegionController(input: { sessionKey: Accessor sessionID: Accessor prompt: PromptInputState - ready: Accessor centered: Accessor - todo: { - collapsed: Accessor - onToggle: () => void - } followup: Accessor revert: Accessor onResponseSubmit: () => void @@ -40,41 +32,6 @@ export function createSessionComposerRegionController(input: { setDockRef: (el: HTMLDivElement) => void }) { const sync = useSync() - const [store, setStore] = createStore({ - ready: input.ready() || input.state.dock(), - height: 320, - body: undefined as HTMLDivElement | undefined, - }) - let timer: number | undefined - let frame: number | undefined - - const clear = () => { - if (timer !== undefined) window.clearTimeout(timer) - if (frame !== undefined) cancelAnimationFrame(frame) - timer = undefined - frame = undefined - } - - createEffect(() => { - input.sessionKey() - const ready = input.ready() - const dock = input.state.dock() - - clear() - if (store.ready || (!ready && !dock)) return - if (dock) { - setStore("ready", true) - return - } - - frame = requestAnimationFrame(() => { - frame = undefined - timer = window.setTimeout(() => { - setStore("ready", true) - timer = undefined - }, 140) - }) - }) createEffect(() => { if (!input.prompt.ready()) return @@ -92,27 +49,10 @@ export function createSessionComposerRegionController(input: { }) }) - createEffect(() => { - const el = store.body - if (!el) return - const update = () => setStore("height", el.getBoundingClientRect().height) - createResizeObserver(el, update) - update() - }) - - onCleanup(clear) - const parentID = createMemo(() => { const id = input.sessionID() return id ? sync().session.get(id)?.parentID : undefined }) - const open = createMemo(() => store.ready && input.state.dock() && !input.state.closing()) - const progress = useSpring( - () => (open() ? 1 : 0), - { visualDuration: 0.3, bounce: 0 }, - () => `${input.sessionKey()}\0${store.ready}`, - ) - const value = createMemo(() => Math.max(0, Math.min(1, progress()))) const ready = Promise.resolve() const [promptReady] = createResource( () => input.prompt.ready.promise ?? ready, @@ -122,7 +62,6 @@ export function createSessionComposerRegionController(input: { return { state: input.state, centered: input.centered, - todo: input.todo, followup: input.followup, revert: input.revert, onResponseSubmit: input.onResponseSubmit, @@ -134,11 +73,7 @@ export function createSessionComposerRegionController(input: { showComposer: () => !input.state.blocked() || !!parentID(), handoffPrompt: () => getSessionHandoff(input.sessionKey())?.prompt, promptReady: () => input.prompt.ready() || promptReady(), - dock: () => (store.ready && input.state.dock()) || value() > 0.001, - dockProgress: value, - dockHeight: () => Math.max(78, store.height), - lift: () => (input.revert()?.items.length ? 18 : 36 * value()), - setDockBodyRef: (el: HTMLDivElement) => setStore("body", el), + lift: () => (input.revert()?.items.length ? 18 : 0), } } diff --git a/packages/app/src/pages/session/composer/session-composer-region.tsx b/packages/app/src/pages/session/composer/session-composer-region.tsx index 600ff41e3d..feb2b0aee4 100644 --- a/packages/app/src/pages/session/composer/session-composer-region.tsx +++ b/packages/app/src/pages/session/composer/session-composer-region.tsx @@ -5,7 +5,6 @@ import { SessionPermissionDock } from "@/pages/session/composer/session-permissi import { SessionQuestionDock } from "@/pages/session/composer/session-question-dock" import { SessionFollowupDock } from "@/pages/session/composer/session-followup-dock" import { SessionRevertDock } from "@/pages/session/composer/session-revert-dock" -import { SessionTodoDock } from "@/pages/session/composer/session-todo-dock" import type { SessionComposerRegionController } from "./session-composer-region-controller" export function SessionComposerRegion(props: { @@ -60,28 +59,6 @@ export function SessionComposerRegion(props: { - -
-
- -
-
-
)} -
+
{controller.handoffPrompt() || language.t("prompt.loading")}
@@ -109,11 +83,7 @@ export function SessionComposerRegion(props: { > {(revert) => ( -
+
@@ -104,35 +103,3 @@ describe("sessionQuestionRequest", () => { expect(sessionQuestionRequest(sessions, questions, "root")?.id).toBe("q-grand") }) }) - -describe("todoState", () => { - test("hides when there are no todos", () => { - expect(todoState({ count: 0, done: false, live: true })).toBe("hide") - }) - - test("opens while the session is still working", () => { - expect(todoState({ count: 2, done: false, live: true })).toBe("open") - }) - - test("closes completed todos after a running turn", () => { - expect(todoState({ count: 2, done: true, live: true })).toBe("close") - }) - - test("clears stale todos when the turn ends", () => { - expect(todoState({ count: 2, done: false, live: false })).toBe("clear") - }) - - test("clears completed todos when the session is no longer live", () => { - expect(todoState({ count: 2, done: true, live: false })).toBe("clear") - }) -}) - -describe("todoDockAtBoundary", () => { - test("shows active todos when entering a session", () => { - expect(todoDockAtBoundary("open")).toBe(true) - }) - - test("hides completed todos when entering a session", () => { - expect(todoDockAtBoundary("close")).toBe(false) - }) -}) diff --git a/packages/app/src/pages/session/composer/session-composer-state.ts b/packages/app/src/pages/session/composer/session-composer-state.ts index 45f5e4cb26..eb282c15fc 100644 --- a/packages/app/src/pages/session/composer/session-composer-state.ts +++ b/packages/app/src/pages/session/composer/session-composer-state.ts @@ -1,35 +1,20 @@ -import { createEffect, createMemo, on, onCleanup } from "solid-js" +import { createMemo } from "solid-js" import { createStore } from "solid-js/store" -import type { PermissionRequest, QuestionRequest, Todo } from "@opencode-ai/sdk/v2" +import type { PermissionRequest, QuestionRequest } from "@opencode-ai/sdk/v2" import { useParams } from "@solidjs/router" import { showToast } from "@/utils/toast" -import { useServerSync } from "@/context/server-sync" import { useLanguage } from "@/context/language" import { usePermission } from "@/context/permission" import { useSDK } from "@/context/sdk" import { useSync } from "@/context/sync" import { sessionPermissionRequest, sessionQuestionRequest } from "./session-request-tree" -export const todoState = (input: { - count: number - done: boolean - live: boolean -}): "hide" | "clear" | "open" | "close" => { - if (input.count === 0) return "hide" - if (!input.live) return "clear" - if (!input.done) return "open" - return "close" -} - -export const todoDockAtBoundary = (state: ReturnType) => state === "open" - const idle = { type: "idle" as const } -export function createSessionComposerController(options?: { closeMs?: number | (() => number) }) { +export function createSessionComposerController() { const params = useParams() const sdk = useSDK() const sync = useSync() - const serverSync = useServerSync() const language = useLanguage() const permission = usePermission() @@ -49,24 +34,8 @@ export function createSessionComposerController(options?: { closeMs?: number | ( return !!permissionRequest() || !!questionRequest() }) - const todos = createMemo((): Todo[] => { - const id = params.id - if (!id) return [] - return serverSync().session.data.todo[id] ?? [] - }) - - const done = createMemo( - () => todos().length > 0 && todos().every((todo) => todo.status === "completed" || todo.status === "cancelled"), - ) - - const live = createMemo(() => sync().data.session_working(params.id ?? "") || blocked()) - const [store, setStore] = createStore({ - sessionID: params.id, responding: undefined as string | undefined, - dock: todos().length > 0 && !done() && live(), - closing: false, - opening: false, }) const permissionResponding = createMemo(() => { @@ -92,112 +61,12 @@ export function createSessionComposerController(options?: { closeMs?: number | ( }) } - let timer: number | undefined - let raf: number | undefined - - const closeMs = () => { - const value = options?.closeMs - if (typeof value === "function") return Math.max(0, value()) - if (typeof value === "number") return Math.max(0, value) - return 400 - } - - const scheduleClose = () => { - if (timer) window.clearTimeout(timer) - timer = window.setTimeout(() => { - setStore({ dock: false, closing: false }) - timer = undefined - }, closeMs()) - } - - // Keep stale turn todos from reopening if the model never clears them. - const clear = () => { - const id = params.id - if (!id) return - sync().set("todo", id, []) - } - - createEffect( - on( - () => [params.id, todos().length, done(), live()] as const, - ([id, count, complete, active], previous) => { - if (raf) cancelAnimationFrame(raf) - raf = undefined - - const next = todoState({ - count, - done: complete, - live: active, - }) - - if (!previous || previous[0] !== id) { - if (timer) window.clearTimeout(timer) - timer = undefined - setStore({ sessionID: id, dock: todoDockAtBoundary(next), closing: false, opening: false }) - if (next === "clear") clear() - return - } - - if (next === "hide") { - if (timer) window.clearTimeout(timer) - timer = undefined - setStore({ dock: false, closing: false, opening: false }) - return - } - - if (next === "clear") { - if (timer) window.clearTimeout(timer) - timer = undefined - clear() - return - } - - if (next === "open") { - if (timer) window.clearTimeout(timer) - timer = undefined - const hidden = !store.dock || store.closing - setStore({ dock: true, closing: false }) - if (hidden) { - setStore("opening", true) - raf = requestAnimationFrame(() => { - setStore("opening", false) - raf = undefined - }) - return - } - setStore("opening", false) - return - } - - setStore({ dock: true, opening: false, closing: true }) - if (!timer) scheduleClose() - }, - ), - ) - - onCleanup(() => { - if (!timer) return - window.clearTimeout(timer) - }) - - onCleanup(() => { - if (!raf) return - cancelAnimationFrame(raf) - }) - return { blocked, questionRequest, permissionRequest, permissionResponding, decide, - todos, - dock: () => - store.sessionID === params.id - ? store.dock - : todoDockAtBoundary(todoState({ count: todos().length, done: done(), live: live() })), - closing: () => store.sessionID === params.id && store.closing, - opening: () => store.sessionID === params.id && store.opening, } } diff --git a/packages/app/src/pages/session/composer/session-todo-dock.tsx b/packages/app/src/pages/session/composer/session-todo-dock.tsx deleted file mode 100644 index f68428fcda..0000000000 --- a/packages/app/src/pages/session/composer/session-todo-dock.tsx +++ /dev/null @@ -1,256 +0,0 @@ -import type { Todo } from "@opencode-ai/sdk/v2" -import { AnimatedNumber } from "@opencode-ai/ui/animated-number" -import { Checkbox } from "@opencode-ai/ui/checkbox" -import { DockTray } from "@opencode-ai/ui/dock-surface" -import { IconButton } from "@opencode-ai/ui/icon-button" -import { useSpring } from "@opencode-ai/ui/motion-spring" -import { TextReveal } from "@opencode-ai/ui/text-reveal" -import { TextStrikethrough } from "@opencode-ai/ui/text-strikethrough" -import { createResizeObserver } from "@solid-primitives/resize-observer" -import { Index, createEffect, createMemo } from "solid-js" -import { createStore } from "solid-js/store" -import { useLanguage } from "@/context/language" - -const doneToken = "\u0000done\u0000" -const totalToken = "\u0000total\u0000" - -function dot(status: Todo["status"]) { - if (status !== "in_progress") return undefined - return ( - - - - ) -} - -export function SessionTodoDock(props: { - todos: Todo[] - collapsed: boolean - onToggle: () => void - collapseLabel: string - expandLabel: string - dockProgress: number -}) { - const language = useLanguage() - const [store, setStore] = createStore({ - height: 78, - }) - - const total = createMemo(() => props.todos.length) - const done = createMemo(() => props.todos.filter((todo) => todo.status === "completed").length) - const label = createMemo(() => language.t("session.todo.progress", { done: done(), total: total() })) - const progress = createMemo(() => - language - .t("session.todo.progress", { done: doneToken, total: totalToken }) - .split(/(\u0000done\u0000|\u0000total\u0000)/), - ) - - const active = createMemo( - () => - props.todos.find((todo) => todo.status === "in_progress") ?? - props.todos.find((todo) => todo.status === "pending") ?? - props.todos.filter((todo) => todo.status === "completed").at(-1) ?? - props.todos[0], - ) - - const preview = createMemo(() => active()?.content ?? "") - const collapse = useSpring(() => (props.collapsed ? 1 : 0), { visualDuration: 0.3, bounce: 0 }) - const dock = createMemo(() => Math.max(0, Math.min(1, props.dockProgress))) - const shut = createMemo(() => 1 - dock()) - const value = createMemo(() => Math.max(0, Math.min(1, collapse()))) - const hide = createMemo(() => Math.max(value(), shut())) - const off = createMemo(() => hide() > 0.98) - const turn = createMemo(() => Math.max(0, Math.min(1, value()))) - const full = createMemo(() => Math.max(78, store.height)) - let contentRef: HTMLDivElement | undefined - - createEffect(() => { - const el = contentRef - if (!el) return - const update = () => { - setStore("height", (height) => Math.max(height, el.scrollHeight)) - } - update() - createResizeObserver(el, update) - }) - - return ( - -
-
{ - if (event.key !== "Enter" && event.key !== " ") return - event.preventDefault() - props.onToggle() - }} - > - - - {(item) => - item() === doneToken ? ( - - ) : item() === totalToken ? ( - - ) : ( - {item()} - ) - } - - -
- -
-
- { - event.preventDefault() - event.stopPropagation() - }} - onClick={(event) => { - event.stopPropagation() - props.onToggle() - }} - aria-label={props.collapsed ? props.expandLabel : props.collapseLabel} - /> -
-
- -
0.1, - }} - style={{ - visibility: off() ? "hidden" : "visible", - opacity: `${Math.max(0, Math.min(1, 1 - hide()))}`, - }} - > - -
-
-
- ) -} - -function TodoList(props: { todos: Todo[] }) { - const [store, setStore] = createStore({ - stuck: false, - }) - - return ( -
-
{ - setStore("stuck", e.currentTarget.scrollTop > 0) - }} - > - - {(todo) => ( - - - - )} - -
-
-
- ) -} diff --git a/packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx b/packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx deleted file mode 100644 index 61cfaf931b..0000000000 --- a/packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx +++ /dev/null @@ -1,623 +0,0 @@ -// @ts-nocheck -import { createEffect, createMemo, onCleanup } from "solid-js" -import { createStore } from "solid-js/store" -import type { Todo } from "@opencode-ai/sdk/v2" -import { useServerSync } from "@/context/global-sync" -import { PromptInput } from "@/components/prompt-input" -import { usePrompt } from "@/context/prompt" -import { - SessionComposerRegion, - createSessionComposerController, - createSessionComposerRegionController, -} from "@/pages/session/composer" - -export default { - title: "UI/Todo Panel Motion", - id: "components-todo-panel-motion", - tags: ["autodocs"], - parameters: { - docs: { - description: { - component: `### Overview -This playground renders the real session composer region from app code. - -### Source path -- \`packages/app/src/pages/session/composer/session-composer-region.tsx\` - -### Includes -- \`SessionTodoDock\` (real) -- \`PromptInput\` (real) - -No visual reimplementation layer is used for the dock/input stack.`, - }, - }, - }, -} - -const pool = [ - "Refactor ToolStatusTitle DOM measurement to offscreen global measurer (unconstrained by timeline layout)", - "Remove inline measure nodes/CSS hooks and keep width morph behavior intact", - "Run typechecks/tests and report what changed", - "Verify reduced-motion behavior in timeline", - "Review diff for animation edge cases", - "Document rollout notes in PR description", - "Check keyboard and screen reader semantics", - "Add storybook controls for iteration speed", -] - -const btn = (accent?: boolean) => - ({ - padding: "6px 14px", - "border-radius": "6px", - border: "1px solid var(--color-divider, #333)", - background: accent ? "var(--color-accent, #58f)" : "var(--color-fill-element, #222)", - color: "var(--color-text, #eee)", - cursor: "pointer", - "font-size": "13px", - }) as const - -const controls = { - agents: { available: [], options: ["build"], current: "build", loading: false, visible: true, select: () => {} }, - model: { - selection: { - current: () => ({ id: "claude-3-7-sonnet", name: "Claude 3.7 Sonnet", provider: { id: "anthropic" } }), - variant: { list: () => [], current: () => undefined, set: () => {} }, - }, - paid: true, - loading: false, - }, - session: { - id: "story-session", - tabs: { active: () => undefined, all: () => [], open: () => {}, setActive: () => {} }, - reviewPanel: { opened: () => false, open: () => {} }, - }, - newLayoutDesigns: true, -} - -const css = ` -[data-component="todo-stage"] { - display: grid; - gap: 20px; - padding: 20px; -} - -[data-component="todo-preview"] { - height: 560px; - min-height: 0; -} - -[data-component="todo-session-root"] { - position: relative; - width: 100%; - height: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - background: var(--background-base); - border: 1px solid var(--border-weak-base); - border-radius: 12px; -} - -[data-component="todo-session-frame"] { - flex: 1 1 auto; - min-height: 0; - display: flex; - flex-direction: column; -} - -[data-component="todo-session-panel"] { - position: relative; - flex: 1 1 auto; - min-height: 0; - height: 100%; - display: flex; - flex-direction: column; - background: var(--background-stronger); -} - -[data-slot="todo-preview-content"] { - flex: 1 1 auto; - min-height: 0; - overflow: hidden; -} - -[data-slot="todo-preview-scroll"] { - height: 100%; - overflow: auto; - min-height: 0; - padding: 14px 16px; - display: flex; - flex-direction: column; - gap: 10px; -} - -[data-slot="todo-preview-spacer"] { - flex: 1 1 auto; - min-height: 0; -} - -[data-slot="todo-preview-msg"] { - border-radius: 8px; - border: 1px solid var(--border-weak-base); - background: var(--surface-base); - color: var(--text-weak); - padding: 8px 10px; - font-size: 13px; - line-height: 1.35; -} - -[data-slot="todo-preview-msg"][data-strong="true"] { - color: var(--text-strong); -} -` - -export const Playground = { - render: () => { - const global = useServerSync() - const prompt = usePrompt() - const [cfg, setCfg] = createStore({ - open: true, - collapsed: false, - step: 1, - dockOpenDuration: 0.3, - dockOpenBounce: 0, - dockCloseDuration: 0.3, - dockCloseBounce: 0, - drawerExpandDuration: 0.3, - drawerExpandBounce: 0, - drawerCollapseDuration: 0.3, - drawerCollapseBounce: 0, - subtitleDuration: 600, - subtitleAuto: true, - subtitleTravel: 25, - subtitleEdge: 17, - countDuration: 600, - countMask: 18, - countMaskHeight: 0, - countWidthDuration: 560, - }) - const open = () => cfg.open - const step = () => cfg.step - const dockOpenDuration = () => cfg.dockOpenDuration - const dockOpenBounce = () => cfg.dockOpenBounce - const dockCloseDuration = () => cfg.dockCloseDuration - const dockCloseBounce = () => cfg.dockCloseBounce - const drawerExpandDuration = () => cfg.drawerExpandDuration - const drawerExpandBounce = () => cfg.drawerExpandBounce - const drawerCollapseDuration = () => cfg.drawerCollapseDuration - const drawerCollapseBounce = () => cfg.drawerCollapseBounce - const subtitleDuration = () => cfg.subtitleDuration - const subtitleAuto = () => cfg.subtitleAuto - const subtitleTravel = () => cfg.subtitleTravel - const subtitleEdge = () => cfg.subtitleEdge - const countDuration = () => cfg.countDuration - const countMask = () => cfg.countMask - const countMaskHeight = () => cfg.countMaskHeight - const countWidthDuration = () => cfg.countWidthDuration - const state = createSessionComposerController({ closeMs: () => Math.round(dockCloseDuration() * 1000) }) - let frame - let scrollRef - - const todos = createMemo(() => { - const done = Math.max(0, Math.min(3, step())) - return pool.slice(0, 3).map((content, i) => ({ - id: `todo-${i + 1}`, - content, - status: i < done ? "completed" : i === done && done < 3 ? "in_progress" : "pending", - })) - }) - - createEffect(() => { - global.todo.set("story-session", todos()) - }) - - const clear = () => { - if (frame) cancelAnimationFrame(frame) - frame = undefined - } - - const pin = () => { - if (!scrollRef) return - scrollRef.scrollTop = scrollRef.scrollHeight - } - - const collapsed = () => cfg.collapsed - const setCollapsed = (value: boolean) => setCfg("collapsed", value) - const openDock = () => { - clear() - setCfg("open", true) - frame = requestAnimationFrame(() => { - pin() - frame = undefined - }) - } - - const closeDock = () => { - clear() - setCfg("open", false) - } - - const dockOpen = () => open() - - const toggleDock = () => { - if (dockOpen()) { - closeDock() - return - } - openDock() - } - - const toggleDrawer = () => { - if (!dockOpen()) { - openDock() - frame = requestAnimationFrame(() => { - pin() - setCollapsed(true) - frame = undefined - }) - return - } - setCollapsed(!collapsed()) - } - - const cycle = () => { - setCfg("step", (value) => (value + 1) % 4) - } - - onCleanup(clear) - - return ( -
- - -
-
-
-
-
-
-
-
- Thinking Checking type safety -
-
Shell Prints five topic blocks between timed commands
-
-
- -
- "story-session", - sessionID: () => "story-session", - prompt, - ready: () => true, - centered: () => false, - todo: { collapsed, onToggle: () => setCollapsed(!collapsed()) }, - followup: () => undefined, - revert: () => undefined, - onResponseSubmit: pin, - openParent: () => {}, - setPromptRef: () => {}, - setDockRef: () => {}, - })} - promptInput={ - {}, handleSubmit: (event) => event.preventDefault() }} - ref={() => {}} - newSessionWorktree="" - onNewSessionWorktreeReset={() => {}} - /> - } - /> -
-
-
-
-
- -
- - - - {[0, 1, 2, 3].map((value) => ( - - ))} -
- -
-
Dock open
- - - -
- Dock close -
- - - -
- Drawer expand -
- - - -
- Drawer collapse -
- - - -
- Subtitle odometer -
- - - - - -
- Count odometer -
- - - - -
-
- ) - }, -} diff --git a/packages/cli/src/mini/demo.ts b/packages/cli/src/mini/demo.ts index ed0b6878f5..93790ce653 100644 --- a/packages/cli/src/mini/demo.ts +++ b/packages/cli/src/mini/demo.ts @@ -10,7 +10,7 @@ // /permission [kind] → triggers a permission request variant // /question [kind] → triggers a question request variant // /fmt → emits a specific tool/text type (text, reasoning, bash, -// write, edit, patch, task, todo, question, error, mix) +// write, edit, patch, task, question, error, mix) // // Demo mode also handles permission and question replies locally, completing // or failing the synthetic tool parts as appropriate. @@ -30,7 +30,6 @@ const KINDS = [ "edit", "patch", "task", - "todo", "question", "error", "mix", @@ -733,30 +732,6 @@ function emitTask(state: State): void { }) } -function emitTodo(state: State): void { - const ref = make(state, "todowrite", { - todos: [ - { - content: "Trigger permission UI", - status: "completed", - }, - { - content: "Trigger question UI", - status: "in_progress", - }, - { - content: "Tune tool formatting", - status: "pending", - }, - ], - }) - doneTool(state, ref, { - title: "todowrite", - output: "", - metadata: {}, - }) -} - function emitQuestionTool(state: State): void { const ref = make(state, "question", { questions: [ @@ -952,7 +927,6 @@ function emitQuestion(state: State, kind: QuestionKind = "multi"): void { options: [ { label: "Diff", description: "Show an edit diff in the footer" }, { label: "Task", description: "Show a structured task summary" }, - { label: "Todo", description: "Show a todo snapshot" }, { label: "Error", description: "Show an error transcript row" }, ], multiple: true, @@ -992,7 +966,6 @@ function emitQuestion(state: State, kind: QuestionKind = "multi"): void { options: [ { label: "Diff", description: "Emit edit diff" }, { label: "Task", description: "Emit task card" }, - { label: "Todo", description: "Emit todo card" }, ], multiple: true, custom: true, @@ -1066,11 +1039,6 @@ async function emitFmt(state: State, kind: string, body: string, signal?: AbortS return true } - if (kind === "todo") { - emitTodo(state) - return true - } - if (kind === "question") { emitQuestionTool(state) return true @@ -1091,7 +1059,6 @@ async function emitFmt(state: State, kind: string, body: string, signal?: AbortS emitEdit(state) emitPatch(state) emitTask(state) - emitTodo(state) emitQuestionTool(state) emitError(state, "demo mixed scenario error") return true diff --git a/packages/cli/src/mini/scrollback.writer.tsx b/packages/cli/src/mini/scrollback.writer.tsx index be814dbbfa..74f4a97adf 100644 --- a/packages/cli/src/mini/scrollback.writer.tsx +++ b/packages/cli/src/mini/scrollback.writer.tsx @@ -7,26 +7,6 @@ import { toolFiletype, toolStructuredFinal } from "./tool" import { RUN_THEME_FALLBACK, transparent, type RunTheme } from "./theme" import type { EntryLayout, RunEntryBody, ScrollbackOptions, StreamCommit } from "./types" -function todoText(item: { status: string; content: string }): string { - if (item.status === "completed") { - return `[✓] ${item.content}` - } - - if (item.status === "cancelled") { - return `~[ ] ${item.content}~` - } - - if (item.status === "in_progress") { - return `[•] ${item.content}` - } - - return `[ ] ${item.content}` -} - -function todoColor(theme: RunTheme, status: string) { - return status === "in_progress" ? theme.block.warning : theme.block.muted -} - export function entryGroupKey(commit: StreamCommit): string | undefined { if (!commit.partID) { return undefined @@ -137,10 +117,6 @@ export function RunEntryContent(props: { const next = structured() return next?.kind === "task" ? next : undefined }) - const todo_snapshot = createMemo(() => { - const next = structured() - return next?.kind === "todo" ? next : undefined - }) const question_snapshot = createMemo(() => { const next = structured() return next?.kind === "question" ? next : undefined @@ -242,25 +218,6 @@ export function RunEntryContent(props: { - - - - # Todos - - - {todo_snapshot()!.items.map((item) => ( - - {todoText(item)} - - ))} - {todo_snapshot()!.tail ? ( - - {todo_snapshot()!.tail} - - ) : null} - - - diff --git a/packages/cli/src/mini/tool.ts b/packages/cli/src/mini/tool.ts index 9eb8782a17..9c13d1ee29 100644 --- a/packages/cli/src/mini/tool.ts +++ b/packages/cli/src/mini/tool.ts @@ -55,7 +55,6 @@ type ToolInput = ToolDict & { content?: string command?: string workdir?: string - todos?: Array<{ status?: string; content?: string }> questions?: Array<{ question?: string }> diff?: string } @@ -122,7 +121,6 @@ type ToolName = | "patch" | "batch" | "task" - | "todowrite" | "question" | "read" | "glob" @@ -398,25 +396,6 @@ function runTask(p: ToolProps): ToolInline { } } -function runTodo(p: ToolProps): ToolInline { - return { - icon: "#", - title: "Todos", - mode: "block", - body: list<{ status?: string; content?: string }>(p.frame.input.todos) - .flatMap((item) => { - const body = typeof item?.content === "string" ? item.content : "" - if (!body) { - return [] - } - - const mark = item.status === "completed" ? "[✓]" : item.status === "in_progress" ? "[•]" : "[ ]" - return [`${mark} ${body}`] - }) - .join("\n"), - } -} - function runSkill(p: ToolProps): ToolInline { return { icon: "→", @@ -604,28 +583,6 @@ function snapTask(p: ToolProps): ToolSnapshot { } } -function snapTodo(p: ToolProps): ToolSnapshot { - const items = list<{ status?: string; content?: string }>(p.frame.input.todos).flatMap((item) => { - const content = typeof item?.content === "string" ? item.content : "" - if (!content) { - return [] - } - - return [ - { - status: typeof item.status === "string" ? item.status : "", - content, - }, - ] - }) - - return { - kind: "todo", - items, - tail: "", - } -} - function snapQuestion(p: ToolProps): ToolSnapshot { const answers = list(p.frame.meta.answers) const items = list<{ question?: string }>(p.frame.input.questions).map((item, i) => { @@ -814,42 +771,6 @@ function scrollTaskFinal(p: ToolProps): string { return `# ${kind} Task\n${row}` } -function scrollTodoStart(_: ToolProps): string { - return "" -} - -function scrollTodoFinal(p: ToolProps): string { - const items = list<{ status?: string }>(p.input.todos) - const time = span(p.frame.state) - if (items.length === 0) { - if (!time) { - return "0 todos" - } - - return `0 todos · ${time}` - } - - const doneN = items.filter((item) => item.status === "completed").length - const runN = items.filter((item) => item.status === "in_progress").length - const left = items.length - doneN - runN - const tail = [`${items.length} total`] - if (doneN > 0) { - tail.push(`${doneN} done`) - } - if (runN > 0) { - tail.push(`${runN} active`) - } - if (left > 0) { - tail.push(`${left} pending`) - } - - if (time) { - tail.push(time) - } - - return tail.join(" · ") -} - function scrollQuestionStart(_: ToolProps): string { return "" } @@ -1131,19 +1052,6 @@ const TOOL_RULES = { }, permission: permTask, }, - todowrite: { - view: { - output: false, - final: true, - snap: "structured", - }, - run: runTodo, - snap: snapTodo, - scroll: { - start: scrollTodoStart, - final: scrollTodoFinal, - }, - }, question: { view: { output: false, diff --git a/packages/cli/src/mini/types.ts b/packages/cli/src/mini/types.ts index 00f8d8daed..0e3b4bea3b 100644 --- a/packages/cli/src/mini/types.ts +++ b/packages/cli/src/mini/types.ts @@ -199,15 +199,6 @@ export type ToolTaskSnapshot = { tail: string } -export type ToolTodoSnapshot = { - kind: "todo" - items: Array<{ - status: string - content: string - }> - tail: string -} - export type ToolQuestionSnapshot = { kind: "question" items: Array<{ @@ -217,12 +208,7 @@ export type ToolQuestionSnapshot = { tail: string } -export type ToolSnapshot = - | ToolCodeSnapshot - | ToolDiffSnapshot - | ToolTaskSnapshot - | ToolTodoSnapshot - | ToolQuestionSnapshot +export type ToolSnapshot = ToolCodeSnapshot | ToolDiffSnapshot | ToolTaskSnapshot | ToolQuestionSnapshot export type EntryLayout = "inline" | "block" diff --git a/packages/client/src/promise/generated/types.ts b/packages/client/src/promise/generated/types.ts index 45e44c5217..c61fdb5eea 100644 --- a/packages/client/src/promise/generated/types.ts +++ b/packages/client/src/promise/generated/types.ts @@ -5583,17 +5583,6 @@ export type EventSubscribeOutput = readonly location?: { readonly directory: string; readonly workspaceID?: string } readonly data: { readonly id: string; readonly sessionID: string } } - | { - readonly id: string - readonly created: number - readonly metadata?: { readonly [x: string]: unknown } - readonly type: "todo.updated" - readonly location?: { readonly directory: string; readonly workspaceID?: string } - readonly data: { - readonly sessionID: string - readonly todos: ReadonlyArray<{ readonly content: string; readonly status: string; readonly priority: string }> - } - } | { readonly id: string readonly created: number diff --git a/packages/codemode/test/fixtures/opencode-v2-openapi.json b/packages/codemode/test/fixtures/opencode-v2-openapi.json index c2cd5a1d21..543a418173 100644 --- a/packages/codemode/test/fixtures/opencode-v2-openapi.json +++ b/packages/codemode/test/fixtures/opencode-v2-openapi.json @@ -75,6 +75,62 @@ "summary": "Check server health" } }, + "/api/server": { + "get": { + "tags": [ + "server" + ], + "operationId": "v2.server.get", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "urls" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Return the URLs that can be used to connect to this server.", + "summary": "Get server information" + } + }, "/api/location": { "get": { "tags": [ @@ -18676,6 +18732,7 @@ "required": [ "id", "sessionID", + "title", "mode", "fields" ], @@ -18714,6 +18771,7 @@ "required": [ "id", "sessionID", + "title", "mode", "url" ], @@ -18791,6 +18849,7 @@ } }, "required": [ + "title", "mode" ], "additionalProperties": false @@ -24584,6 +24643,7 @@ "required": [ "id", "sessionID", + "title", "mode", "fields" ], @@ -24622,6 +24682,7 @@ "required": [ "id", "sessionID", + "title", "mode", "url" ], @@ -24844,88 +24905,6 @@ ], "additionalProperties": false }, - "Todo": { - "type": "object", - "properties": { - "content": { - "type": "string", - "description": "Brief description of the task" - }, - "status": { - "type": "string", - "description": "Current status of the task: pending, in_progress, completed, cancelled" - }, - "priority": { - "type": "string", - "description": "Priority level of the task: high, medium, low" - } - }, - "required": [ - "content", - "status", - "priority" - ], - "additionalProperties": false - }, - "todo.updated": { - "type": "object", - "properties": { - "id": { - "type": "string", - "allOf": [ - { - "pattern": "^evt_" - } - ] - }, - "created": { - "type": "number" - }, - "metadata": { - "type": "object" - }, - "type": { - "type": "string", - "enum": [ - "todo.updated" - ] - }, - "location": { - "$ref": "#/components/schemas/Location.Ref" - }, - "data": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "allOf": [ - { - "pattern": "^ses" - } - ] - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": [ - "sessionID", - "todos" - ], - "additionalProperties": false - } - }, - "required": [ - "id", - "created", - "type", - "data" - ], - "additionalProperties": false - }, "SessionStatus": { "anyOf": [ { @@ -26475,9 +26454,6 @@ { "$ref": "#/components/schemas/form.cancelled" }, - { - "$ref": "#/components/schemas/todo.updated" - }, { "$ref": "#/components/schemas/session.status" }, @@ -27072,6 +27048,9 @@ { "name": "health" }, + { + "name": "server" + }, { "name": "location" }, diff --git a/packages/core/schema.json b/packages/core/schema.json index acfa072f6e..77884cc9ff 100644 --- a/packages/core/schema.json +++ b/packages/core/schema.json @@ -1,9 +1,9 @@ { "version": "7", "dialect": "sqlite", - "id": "beb91b32-23e2-405f-99b8-1e8763db94f8", + "id": "8c1748cc-f978-4df4-879d-fe7fda5c4c34", "prevIds": [ - "00000000-0000-0000-0000-000000000000" + "beb91b32-23e2-405f-99b8-1e8763db94f8" ], "ddl": [ { @@ -78,10 +78,6 @@ "name": "session", "entityType": "tables" }, - { - "name": "todo", - "entityType": "tables" - }, { "name": "session_share", "entityType": "tables" @@ -1446,76 +1442,6 @@ "entityType": "columns", "table": "session" }, - { - "type": "text", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "session_id", - "entityType": "columns", - "table": "todo" - }, - { - "type": "text", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "content", - "entityType": "columns", - "table": "todo" - }, - { - "type": "text", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "status", - "entityType": "columns", - "table": "todo" - }, - { - "type": "text", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "priority", - "entityType": "columns", - "table": "todo" - }, - { - "type": "integer", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "position", - "entityType": "columns", - "table": "todo" - }, - { - "type": "integer", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "time_created", - "entityType": "columns", - "table": "todo" - }, - { - "type": "integer", - "notNull": true, - "autoincrement": false, - "default": null, - "generated": null, - "name": "time_updated", - "entityType": "columns", - "table": "todo" - }, { "type": "text", "notNull": false, @@ -1756,21 +1682,6 @@ "entityType": "fks", "table": "session" }, - { - "columns": [ - "session_id" - ], - "tableTo": "session", - "columnsTo": [ - "id" - ], - "onUpdate": "NO ACTION", - "onDelete": "CASCADE", - "nameExplicit": false, - "name": "fk_todo_session_id_session_id_fk", - "entityType": "fks", - "table": "todo" - }, { "columns": [ "session_id" @@ -1816,16 +1727,6 @@ "entityType": "pks", "table": "instruction_entry" }, - { - "columns": [ - "session_id", - "position" - ], - "nameExplicit": false, - "name": "todo_pk", - "entityType": "pks", - "table": "todo" - }, { "columns": [ "id" @@ -2279,20 +2180,6 @@ "name": "session_parent_idx", "entityType": "indexes", "table": "session" - }, - { - "columns": [ - { - "value": "session_id", - "isExpression": false - } - ], - "isUnique": false, - "where": null, - "origin": "manual", - "name": "todo_session_idx", - "entityType": "indexes", - "table": "todo" } ], "renames": [] diff --git a/packages/core/src/database/migration.gen.ts b/packages/core/src/database/migration.gen.ts index e2f17df568..70cbfca731 100644 --- a/packages/core/src/database/migration.gen.ts +++ b/packages/core/src/database/migration.gen.ts @@ -50,5 +50,6 @@ export const migrations = ( import("./migration/20260707010146_durable_session_inbox"), import("./migration/20260707120000_migrate_prelaunch_v2_state"), import("./migration/20260709013000_generic_session_input"), + import("./migration/20260709025533_drop-todo"), ]) ).map((module) => module.default) satisfies DatabaseMigration.Migration[] diff --git a/packages/core/src/database/migration/20260709025533_drop-todo.ts b/packages/core/src/database/migration/20260709025533_drop-todo.ts new file mode 100644 index 0000000000..1557f889b1 --- /dev/null +++ b/packages/core/src/database/migration/20260709025533_drop-todo.ts @@ -0,0 +1,12 @@ +import { Effect } from "effect" +import type { DatabaseMigration } from "../migration" + +export default { + id: "20260709025533_drop-todo", + up(tx) { + return Effect.gen(function* () { + yield* tx.run(`DROP INDEX IF EXISTS \`todo_session_idx\`;`) + yield* tx.run(`DROP TABLE \`todo\`;`) + }) + }, +} satisfies DatabaseMigration.Migration diff --git a/packages/core/src/database/schema.gen.ts b/packages/core/src/database/schema.gen.ts index bc7cc5f7ab..d175f7cf7a 100644 --- a/packages/core/src/database/schema.gen.ts +++ b/packages/core/src/database/schema.gen.ts @@ -227,19 +227,6 @@ export default { CONSTRAINT \`fk_session_project_id_project_id_fk\` FOREIGN KEY (\`project_id\`) REFERENCES \`project\`(\`id\`) ON DELETE CASCADE ); `) - yield* tx.run(` - CREATE TABLE \`todo\` ( - \`session_id\` text NOT NULL, - \`content\` text NOT NULL, - \`status\` text NOT NULL, - \`priority\` text NOT NULL, - \`position\` integer NOT NULL, - \`time_created\` integer NOT NULL, - \`time_updated\` integer NOT NULL, - CONSTRAINT \`todo_pk\` PRIMARY KEY(\`session_id\`, \`position\`), - CONSTRAINT \`fk_todo_session_id_session_id_fk\` FOREIGN KEY (\`session_id\`) REFERENCES \`session\`(\`id\`) ON DELETE CASCADE - ); - `) yield* tx.run(` CREATE TABLE \`session_share\` ( \`session_id\` text PRIMARY KEY, @@ -286,7 +273,6 @@ export default { yield* tx.run(`CREATE INDEX \`session_project_idx\` ON \`session\` (\`project_id\`);`) yield* tx.run(`CREATE INDEX \`session_workspace_idx\` ON \`session\` (\`workspace_id\`);`) yield* tx.run(`CREATE INDEX \`session_parent_idx\` ON \`session\` (\`parent_id\`);`) - yield* tx.run(`CREATE INDEX \`todo_session_idx\` ON \`todo\` (\`session_id\`);`) }) }, } satisfies Omit diff --git a/packages/core/src/location-services.ts b/packages/core/src/location-services.ts index 7e52aea140..2da72df1dd 100644 --- a/packages/core/src/location-services.ts +++ b/packages/core/src/location-services.ts @@ -32,7 +32,6 @@ import { SessionRunnerLLM } from "./session/runner/llm" import { SessionRunnerModel } from "./session/runner/model" import { SessionCompaction } from "./session/compaction" import { SessionTitle } from "./session/title" -import { SessionTodo } from "./session/todo" import { SkillV2 } from "./skill" import { SkillGuidance } from "./skill/guidance" import { Snapshot } from "./snapshot" @@ -78,7 +77,6 @@ const locationServiceNodes = [ Image.node, SkillGuidance.node, ReferenceGuidance.node, - SessionTodo.node, InstructionEntry.node, Form.node, QuestionV2.node, diff --git a/packages/core/src/plugin/agent.ts b/packages/core/src/plugin/agent.ts index e6e03a4f15..8b94e219ae 100644 --- a/packages/core/src/plugin/agent.ts +++ b/packages/core/src/plugin/agent.ts @@ -161,12 +161,7 @@ export const Plugin = define({ item.description = "General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel." item.mode = "subagent" - item.permissions.push( - ...PermissionV2.merge(defaults, [ - { action: "subagent", resource: "*", effect: "deny" }, - { action: "todowrite", resource: "*", effect: "deny" }, - ]), - ) + item.permissions.push(...PermissionV2.merge(defaults, [{ action: "subagent", resource: "*", effect: "deny" }])) }) draft.update(AgentV2.ID.make("explore"), (item) => { diff --git a/packages/core/src/plugin/internal.ts b/packages/core/src/plugin/internal.ts index ad5553928a..9b75645db4 100644 --- a/packages/core/src/plugin/internal.ts +++ b/packages/core/src/plugin/internal.ts @@ -28,7 +28,6 @@ import { PermissionV2 } from "../permission" import { Reference } from "../reference" import { Ripgrep } from "../ripgrep" import { SessionInstructions } from "../session/instructions" -import { SessionTodo } from "../session/todo" import { Shell } from "../shell" import { SkillV2 } from "../skill" import { PatchTool } from "../tool/patch" @@ -41,7 +40,6 @@ import { ReadTool } from "../tool/read" import { ShellTool } from "../tool/shell" import { SkillTool } from "../tool/skill" import { SubagentTool } from "../tool/subagent" -import { TodoWriteTool } from "../tool/todowrite" import { Tools } from "../tool/tools" import { WebFetchTool } from "../tool/webfetch" import { WebSearchTool } from "../tool/websearch" @@ -78,7 +76,6 @@ const services = Effect.fn("PluginInternal.services")(function* () { const reference = yield* Reference.Service const ripgrep = yield* Ripgrep.Service const instructions = yield* SessionInstructions.Service - const todo = yield* SessionTodo.Service const shell = yield* Shell.Service const skill = yield* SkillV2.Service const tools = yield* Tools.Service @@ -107,7 +104,6 @@ const services = Effect.fn("PluginInternal.services")(function* () { Context.make(Reference.Service, reference), Context.make(Ripgrep.Service, ripgrep), Context.make(SessionInstructions.Service, instructions), - Context.make(SessionTodo.Service, todo), Context.make(Shell.Service, shell), Context.make(SkillV2.Service, skill), Context.make(Tools.Service, tools), @@ -136,7 +132,6 @@ const pre = [ ShellTool.Plugin, SkillTool.Plugin, SubagentTool.Plugin, - TodoWriteTool.Plugin, WebFetchTool.Plugin, WebSearchTool.Plugin, WriteTool.Plugin, diff --git a/packages/core/src/plugin/supervisor.ts b/packages/core/src/plugin/supervisor.ts index 5b29d643ab..0dd3a31d72 100644 --- a/packages/core/src/plugin/supervisor.ts +++ b/packages/core/src/plugin/supervisor.ts @@ -30,7 +30,6 @@ import { PluginPromise } from "../plugin/promise" import { Reference } from "../reference" import { Ripgrep } from "../ripgrep" import { SessionInstructions } from "../session/instructions" -import { SessionTodo } from "../session/todo" import { Shell } from "../shell" import { SkillV2 } from "../skill" import { ReadToolFileSystem } from "../tool/read-filesystem" @@ -368,7 +367,6 @@ export const node = makeLocationNode({ Reference.node, Ripgrep.node, SessionInstructions.node, - SessionTodo.node, Shell.node, SkillV2.node, ToolRegistry.toolsNode, diff --git a/packages/core/src/session/runner/prompt/anthropic.txt b/packages/core/src/session/runner/prompt/anthropic.txt index 0fdf700d5f..1df6f4d693 100644 --- a/packages/core/src/session/runner/prompt/anthropic.txt +++ b/packages/core/src/session/runner/prompt/anthropic.txt @@ -20,58 +20,8 @@ When the user directly asks about OpenCode (eg. "can OpenCode do...", "does Open # Professional objectivity Prioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical info without any unnecessary superlatives, praise, or emotional validation. It is best for the user if OpenCode honestly applies the same rigorous standards to all ideas and disagrees when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, it's best to investigate to find the truth first rather than instinctively confirming the user's beliefs. -# Task Management -You have access to the todowrite tool to help you manage and plan tasks. Use it VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress. -This tool is also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable. - -It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed. - -Examples: - - -user: Run the build and fix any type errors -assistant: I'm going to use the todowrite tool to write the following items to the todo list: -- Run the build -- Fix any type errors - -I'm now going to run the build using the shell tool. - -Looks like I found 10 type errors. I'm going to use the todowrite tool to write 10 items to the todo list. - -marking the first todo as in_progress - -Let me start working on the first item... - -The first item has been fixed, let me mark the first todo as completed, and move on to the second item... -.. -.. - -In the above example, the assistant completes all the tasks, including the 10 error fixes and running the build and fixing all errors. - - -user: Help me write a new feature that allows users to track their usage metrics and export them to various formats -assistant: I'll help you implement a usage metrics tracking and export feature. Let me first use the todowrite tool to plan this task. -Adding the following todos to the todo list: -1. Research existing metrics tracking in the codebase -2. Design the metrics collection system -3. Implement core metrics tracking functionality -4. Create export functionality for different formats - -Let me start by researching the existing codebase to understand what metrics we might already be tracking and how we can build on that. - -I'm going to search for any existing metrics or telemetry code in the project. - -I've found some existing telemetry code. Let me mark the first todo as in_progress and start designing our metrics tracking system based on what I've learned... - -[Assistant continues implementing the feature step by step, marking todos as in_progress and completed as they go] - - - # Doing tasks The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended: -- -- Use the todowrite tool to plan the task if required - - Tool results and user messages may include tags. tags contain useful information and reminders. They are automatically added by the system, and bear no direct relation to the specific tool results or user messages in which they appear. @@ -93,8 +43,6 @@ user: What is the codebase structure? assistant: [Uses the subagent tool] -IMPORTANT: Always use the todowrite tool to plan and track tasks throughout the conversation. - # Code References When referencing specific functions or pieces of code include the pattern `file_path:line_number` to allow the user to easily navigate to the source code location. diff --git a/packages/core/src/session/runner/prompt/beast.txt b/packages/core/src/session/runner/prompt/beast.txt index e92e4d020f..a0a927a6d0 100644 --- a/packages/core/src/session/runner/prompt/beast.txt +++ b/packages/core/src/session/runner/prompt/beast.txt @@ -6,7 +6,7 @@ You MUST iterate and keep going until the problem is solved. You have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me. -Only terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn. +Only terminate your turn when you are sure that the problem is solved. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn. THE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH. @@ -19,13 +19,13 @@ understanding of third party packages and dependencies is up to date. You must u Always tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why. -If the user request is "resume" or "continue" or "try again", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is. +If the user request is "resume" or "continue" or "try again", check the previous conversation history to identify the next incomplete step. Continue from that step, and do not hand back control to the user until the request is complete. Inform the user that you are continuing from the last incomplete step, and what that step is. Take your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided. You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully. -You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. +You MUST keep working until the problem is completely solved. Do not end your turn until you have completed the necessary work and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input. @@ -39,7 +39,7 @@ You are a highly capable and autonomous agent, and you can definitely solve this - What are the dependencies and interactions with other parts of the code? 3. Investigate the codebase. Explore relevant files, search for key functions, and gather context. 4. Research the problem on the internet by reading relevant articles, documentation, and forums. -5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item. +5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. 6. Implement the fix incrementally. Make small, testable code changes. 7. Debug as needed. Use debugging techniques to isolate and resolve issues. 8. Test frequently. Run tests after each change to verify correctness. @@ -73,10 +73,7 @@ Carefully read the issue and think hard about a plan to solve it before coding. ## 5. Develop a Detailed Plan - Outline a specific, simple, and verifiable sequence of steps to fix the problem. -- Create a todo list in markdown format to track your progress. -- Each time you complete a step, check it off using `[x]` syntax. -- Each time you check off a step, display the updated todo list to the user. -- Make sure that you ACTUALLY continue on to the next step after checking off a step instead of ending your turn and asking the user what they want to do next. +- Continue through the planned steps instead of ending your turn and asking the user what they want to do next. ## 6. Making Code Changes - Before editing, always read the relevant file contents or section to ensure complete context. @@ -139,8 +136,6 @@ If you are asked to write a prompt, you should always generate the prompt in ma If you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat. -Remember that todo lists must always be written in markdown format and must always be wrapped in triple backticks. - # Git If the user tells you to stage and commit, you may do so. diff --git a/packages/core/src/session/sql.ts b/packages/core/src/session/sql.ts index e8cdebd90c..bdc7b07967 100644 --- a/packages/core/src/session/sql.ts +++ b/packages/core/src/session/sql.ts @@ -101,25 +101,6 @@ export const PartTable = sqliteTable( ], ) -export const TodoTable = sqliteTable( - "todo", - { - session_id: text() - .$type() - .notNull() - .references(() => SessionTable.id, { onDelete: "cascade" }), - content: text().notNull(), - status: text().notNull(), - priority: text().notNull(), - position: integer().notNull(), - ...Timestamps, - }, - (table) => [ - primaryKey({ columns: [table.session_id, table.position] }), - index("todo_session_idx").on(table.session_id), - ], -) - export const SessionMessageTable = sqliteTable( "session_message", { diff --git a/packages/core/src/session/todo.ts b/packages/core/src/session/todo.ts deleted file mode 100644 index 56c73042c4..0000000000 --- a/packages/core/src/session/todo.ts +++ /dev/null @@ -1,78 +0,0 @@ -export * as SessionTodo from "./todo" - -import { asc, eq } from "drizzle-orm" -import { Context, Effect, Layer } from "effect" -import { SessionTodo } from "@opencode-ai/schema/session-todo" -import { Database } from "../database/database" -import { makeLocationNode } from "../effect/app-node" -import { EventV2 } from "../event" -import { SessionSchema } from "./schema" -import { TodoTable } from "./sql" - -export const Info = SessionTodo.Info -export type Info = typeof Info.Type -export const Event = SessionTodo.Event - -export interface Interface { - readonly update: (input: { - readonly sessionID: SessionSchema.ID - readonly todos: ReadonlyArray - }) => Effect.Effect - readonly get: (sessionID: SessionSchema.ID) => Effect.Effect> -} - -export class Service extends Context.Service()("@opencode/v2/SessionTodo") {} - -const layer = Layer.effect( - Service, - Effect.gen(function* () { - const { db } = yield* Database.Service - const events = yield* EventV2.Service - - const update = Effect.fn("SessionTodo.update")(function* (input: { - readonly sessionID: SessionSchema.ID - readonly todos: ReadonlyArray - }) { - yield* db - .transaction((tx) => - Effect.gen(function* () { - yield* tx.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run() - if (input.todos.length === 0) return - yield* tx - .insert(TodoTable) - .values( - input.todos.map((todo, position) => ({ - session_id: input.sessionID, - content: todo.content, - status: todo.status, - priority: todo.priority, - position, - })), - ) - .run() - }), - ) - .pipe(Effect.orDie) - yield* events.publish(Event.Updated, input) - }) - - const get = Effect.fn("SessionTodo.get")(function* (sessionID: SessionSchema.ID) { - const rows = yield* db - .select() - .from(TodoTable) - .where(eq(TodoTable.session_id, sessionID)) - .orderBy(asc(TodoTable.position)) - .all() - .pipe(Effect.orDie) - return rows.map((row) => ({ - content: row.content, - status: row.status, - priority: row.priority, - })) - }) - - return Service.of({ update, get }) - }), -) - -export const node = makeLocationNode({ service: Service, layer, deps: [EventV2.node, Database.node] }) diff --git a/packages/core/src/tool/todowrite.ts b/packages/core/src/tool/todowrite.ts deleted file mode 100644 index 96c0f10f1a..0000000000 --- a/packages/core/src/tool/todowrite.ts +++ /dev/null @@ -1,57 +0,0 @@ -export * as TodoWriteTool from "./todowrite" - -import type { Context as PluginContext } from "@opencode-ai/plugin/v2/effect/plugin" -import { ToolFailure } from "@opencode-ai/llm" -import { Effect, Schema } from "effect" -import { PermissionV2 } from "../permission" -import { SessionTodo } from "../session/todo" -import { Tool } from "./tool" - -export const name = "todowrite" - -export const Input = Schema.Struct({ - todos: Schema.Array(SessionTodo.Info).annotate({ description: "The updated todo list" }), -}) - -export const Output = Schema.Struct({ - todos: Schema.Array(SessionTodo.Info), -}) -export type Output = typeof Output.Type - -export const toModelOutput = (output: Output) => JSON.stringify(output.todos, null, 2) - -export const Plugin = { - id: "opencode.tool.todowrite", - effect: Effect.fn("TodoWriteTool.Plugin")(function* (ctx: PluginContext) { - const todos = yield* SessionTodo.Service - const permission = yield* PermissionV2.Service - - yield* ctx.tool - .transform((draft) => - draft.add( - name, - Tool.make({ - description: - "Create and maintain a structured task list for the current coding session. Use it to track progress during multi-step work and keep todo statuses current.", - input: Input, - output: Output, - toModelOutput: ({ output }) => [{ type: "text", text: toModelOutput(output) }], - execute: (input, context) => - Effect.gen(function* () { - yield* permission.assert({ - action: name, - resources: ["*"], - save: ["*"], - sessionID: context.sessionID, - agent: context.agent, - source: { type: "tool", messageID: context.assistantMessageID, callID: context.toolCallID }, - }) - yield* todos.update({ sessionID: context.sessionID, todos: input.todos }) - return { todos: input.todos } - }).pipe(Effect.mapError((error) => new ToolFailure({ message: "Unable to update todos", error }))), - }), - ), - ) - .pipe(Effect.orDie) - }), -} diff --git a/packages/core/src/v1/config/permission.ts b/packages/core/src/v1/config/permission.ts index 475dc7bbf3..ef2da34e99 100644 --- a/packages/core/src/v1/config/permission.ts +++ b/packages/core/src/v1/config/permission.ts @@ -24,7 +24,6 @@ const InputObject = Schema.StructWithRest( bash: Schema.optional(Rule), task: Schema.optional(Rule), external_directory: Schema.optional(Rule), - todowrite: Schema.optional(Action), question: Schema.optional(Action), webfetch: Schema.optional(Action), websearch: Schema.optional(Action), diff --git a/packages/core/test/fixtures/recordings/session-runner/openai-chat-streams-text.json b/packages/core/test/fixtures/recordings/session-runner/openai-chat-streams-text.json index ff501af21f..90154112d2 100644 --- a/packages/core/test/fixtures/recordings/session-runner/openai-chat-streams-text.json +++ b/packages/core/test/fixtures/recordings/session-runner/openai-chat-streams-text.json @@ -13,7 +13,7 @@ "headers": { "content-type": "application/json" }, - "body": "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"system\",\"content\":\"You are opencode, an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.\\n\\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\\n\\nYou MUST iterate and keep going until the problem is solved.\\n\\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\\n\\nOnly terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\\n\\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\\n\\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\\n\\nYour knowledge on everything is out of date because your training date is in the past. \\n\\nYou CANNOT successfully complete this task without using Google to verify your\\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\\n\\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\\n\\nIf the user request is \\\"resume\\\" or \\\"continue\\\" or \\\"try again\\\", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is.\\n\\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\\n\\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\\n\\nYou MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say \\\"Next I will do X\\\" or \\\"Now I will do Y\\\" or \\\"I will do X\\\", you MUST actually do X or Y instead just saying that you will do it. \\n\\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\\n\\n# Workflow\\n1. Fetch any URL's provided by the user using the `webfetch` tool.\\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\\n - What is the expected behavior?\\n - What are the edge cases?\\n - What are the potential pitfalls?\\n - How does this fit into the larger context of the codebase?\\n - What are the dependencies and interactions with other parts of the code?\\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item.\\n6. Implement the fix incrementally. Make small, testable code changes.\\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\\n8. Test frequently. Run tests after each change to verify correctness.\\n9. Iterate until the root cause is fixed and all tests pass.\\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\\n\\nRefer to the detailed sections below for more information on each step.\\n\\n## 1. Fetch Provided URLs\\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\\n- After fetching, review the content returned by the webfetch tool.\\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\\n\\n## 2. Deeply Understand the Problem\\nCarefully read the issue and think hard about a plan to solve it before coding.\\n\\n## 3. Codebase Investigation\\n- Explore relevant files and directories.\\n- Search for key functions, classes, or variables related to the issue.\\n- Read and understand relevant code snippets.\\n- Identify the root cause of the problem.\\n- Validate and update your understanding continuously as you gather more context.\\n\\n## 4. Internet Research\\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\\n- After fetching, review the content returned by the fetch tool.\\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find within the content that are relevant to the problem.\\n- Recursively gather all relevant information by fetching links until you have all the information you need.\\n\\n## 5. Develop a Detailed Plan \\n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\\n- Create a todo list in markdown format to track your progress.\\n- Each time you complete a step, check it off using `[x]` syntax.\\n- Each time you check off a step, display the updated todo list to the user.\\n- Make sure that you ACTUALLY continue on to the next step after checking off a step instead of ending your turn and asking the user what they want to do next.\\n\\n## 6. Making Code Changes\\n- Before editing, always read the relevant file contents or section to ensure complete context.\\n- Always read 2000 lines of code at a time to ensure you have enough context.\\n- If a patch is not applied correctly, attempt to reapply it.\\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\\n\\n## 7. Debugging\\n- Make code changes only if you have high confidence they can solve the problem\\n- When debugging, try to determine the root cause rather than addressing symptoms\\n- Debug for as long as needed to identify the root cause and identify a fix\\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\\n- To test hypotheses, you can also add test statements or functions\\n- Revisit your assumptions if unexpected behavior occurs.\\n\\n\\n# Communication Guidelines\\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \\n\\n\\\"Let me fetch the URL you provided to gather more information.\\\"\\n\\\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\\\"\\n\\\"Now, I will search the codebase for the function that handles the LIFX API requests.\\\"\\n\\\"I need to update several files here - stand by\\\"\\n\\\"OK! Now let's run the tests to make sure everything is working correctly.\\\"\\n\\\"Whelp - I see we have some problems. Let's fix those up.\\\"\\n\\n\\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \\n- Always write code directly to the correct files.\\n- Do not display code to the user unless they specifically ask for it.\\n- Only elaborate when clarification is essential for accuracy or user understanding.\\n\\n# Memory\\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \\n\\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\\n```yaml\\n---\\napplyTo: '**'\\n---\\n```\\n\\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\\n\\n# Reading Files and Folders\\n\\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\\n\\n- If you have already read the content and it has not changed, do NOT re-read it.\\n- Only re-read files or folders if:\\n - You suspect the content has changed since your last read.\\n - You have made edits to the file or folder.\\n - You encounter an error that suggests the context may be stale or incomplete.\\n- Use your internal memory and previous context to avoid redundant reads.\\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\\n\\n# Writing Prompts\\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\\n\\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\\n\\nRemember that todo lists must always be written in markdown format and must always be wrapped in triple backticks.\\n\\n# Git \\nIf the user tells you to stage and commit, you may do so. \\n\\nYou are NEVER allowed to stage and commit files automatically.\\n\"},{\"role\":\"user\",\"content\":\"Say hello in one short sentence.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"max_tokens\":20,\"temperature\":0}" + "body": "{\"model\":\"gpt-4o-mini\",\"messages\":[{\"role\":\"system\",\"content\":\"You are opencode, an agent - please keep going until the user’s query is completely resolved, before ending your turn and yielding back to the user.\\n\\nYour thinking should be thorough and so it's fine if it's very long. However, avoid unnecessary repetition and verbosity. You should be concise, but thorough.\\n\\nYou MUST iterate and keep going until the problem is solved.\\n\\nYou have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me.\\n\\nOnly terminate your turn when you are sure that the problem is solved. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn.\\n\\nTHE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH.\\n\\nYou must use the webfetch tool to recursively gather all information from URL's provided to you by the user, as well as any links you find in the content of those pages.\\n\\nYour knowledge on everything is out of date because your training date is in the past. \\n\\nYou CANNOT successfully complete this task without using Google to verify your\\nunderstanding of third party packages and dependencies is up to date. You must use the webfetch tool to search google for how to properly use libraries, packages, frameworks, dependencies, etc. every single time you install or implement one. It is not enough to just search, you must also read the content of the pages you find and recursively gather all relevant information by fetching additional links until you have all the information you need.\\n\\nAlways tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why.\\n\\nIf the user request is \\\"resume\\\" or \\\"continue\\\" or \\\"try again\\\", check the previous conversation history to identify the next incomplete step. Continue from that step, and do not hand back control to the user until the request is complete. Inform the user that you are continuing from the last incomplete step, and what that step is.\\n\\nTake your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided.\\n\\nYou MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.\\n\\nYou MUST keep working until the problem is completely solved. Do not end your turn until you have completed the necessary work and verified that everything is working correctly. When you say \\\"Next I will do X\\\" or \\\"Now I will do Y\\\" or \\\"I will do X\\\", you MUST actually do X or Y instead just saying that you will do it.\\n\\nYou are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input.\\n\\n# Workflow\\n1. Fetch any URL's provided by the user using the `webfetch` tool.\\n2. Understand the problem deeply. Carefully read the issue and think critically about what is required. Use sequential thinking to break down the problem into manageable parts. Consider the following:\\n - What is the expected behavior?\\n - What are the edge cases?\\n - What are the potential pitfalls?\\n - How does this fit into the larger context of the codebase?\\n - What are the dependencies and interactions with other parts of the code?\\n3. Investigate the codebase. Explore relevant files, search for key functions, and gather context.\\n4. Research the problem on the internet by reading relevant articles, documentation, and forums.\\n5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps.\\n6. Implement the fix incrementally. Make small, testable code changes.\\n7. Debug as needed. Use debugging techniques to isolate and resolve issues.\\n8. Test frequently. Run tests after each change to verify correctness.\\n9. Iterate until the root cause is fixed and all tests pass.\\n10. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete.\\n\\nRefer to the detailed sections below for more information on each step.\\n\\n## 1. Fetch Provided URLs\\n- If the user provides a URL, use the `webfetch` tool to retrieve the content of the provided URL.\\n- After fetching, review the content returned by the webfetch tool.\\n- If you find any additional URLs or links that are relevant, use the `webfetch` tool again to retrieve those links.\\n- Recursively gather all relevant information by fetching additional links until you have all the information you need.\\n\\n## 2. Deeply Understand the Problem\\nCarefully read the issue and think hard about a plan to solve it before coding.\\n\\n## 3. Codebase Investigation\\n- Explore relevant files and directories.\\n- Search for key functions, classes, or variables related to the issue.\\n- Read and understand relevant code snippets.\\n- Identify the root cause of the problem.\\n- Validate and update your understanding continuously as you gather more context.\\n\\n## 4. Internet Research\\n- Use the `webfetch` tool to search google by fetching the URL `https://www.google.com/search?q=your+search+query`.\\n- After fetching, review the content returned by the fetch tool.\\n- You MUST fetch the contents of the most relevant links to gather information. Do not rely on the summary that you find in the search results.\\n- As you fetch each link, read the content thoroughly and fetch any additional links that you find within the content that are relevant to the problem.\\n- Recursively gather all relevant information by fetching links until you have all the information you need.\\n\\n## 5. Develop a Detailed Plan \\n- Outline a specific, simple, and verifiable sequence of steps to fix the problem.\\n- Continue through the planned steps instead of ending your turn and asking the user what they want to do next.\\n\\n## 6. Making Code Changes\\n- Before editing, always read the relevant file contents or section to ensure complete context.\\n- Always read 2000 lines of code at a time to ensure you have enough context.\\n- If a patch is not applied correctly, attempt to reapply it.\\n- Make small, testable, incremental changes that logically follow from your investigation and plan.\\n- Whenever you detect that a project requires an environment variable (such as an API key or secret), always check if a .env file exists in the project root. If it does not exist, automatically create a .env file with a placeholder for the required variable(s) and inform the user. Do this proactively, without waiting for the user to request it.\\n\\n## 7. Debugging\\n- Make code changes only if you have high confidence they can solve the problem\\n- When debugging, try to determine the root cause rather than addressing symptoms\\n- Debug for as long as needed to identify the root cause and identify a fix\\n- Use print statements, logs, or temporary code to inspect program state, including descriptive statements or error messages to understand what's happening\\n- To test hypotheses, you can also add test statements or functions\\n- Revisit your assumptions if unexpected behavior occurs.\\n\\n\\n# Communication Guidelines\\nAlways communicate clearly and concisely in a casual, friendly yet professional tone. \\n\\n\\\"Let me fetch the URL you provided to gather more information.\\\"\\n\\\"Ok, I've got all of the information I need on the LIFX API and I know how to use it.\\\"\\n\\\"Now, I will search the codebase for the function that handles the LIFX API requests.\\\"\\n\\\"I need to update several files here - stand by\\\"\\n\\\"OK! Now let's run the tests to make sure everything is working correctly.\\\"\\n\\\"Whelp - I see we have some problems. Let's fix those up.\\\"\\n\\n\\n- Respond with clear, direct answers. Use bullet points and code blocks for structure. - Avoid unnecessary explanations, repetition, and filler. \\n- Always write code directly to the correct files.\\n- Do not display code to the user unless they specifically ask for it.\\n- Only elaborate when clarification is essential for accuracy or user understanding.\\n\\n# Memory\\nYou have a memory that stores information about the user and their preferences. This memory is used to provide a more personalized experience. You can access and update this memory as needed. The memory is stored in a file called `.github/instructions/memory.instruction.md`. If the file is empty, you'll need to create it. \\n\\nWhen creating a new memory file, you MUST include the following front matter at the top of the file:\\n```yaml\\n---\\napplyTo: '**'\\n---\\n```\\n\\nIf the user asks you to remember something or add something to your memory, you can do so by updating the memory file.\\n\\n# Reading Files and Folders\\n\\n**Always check if you have already read a file, folder, or workspace structure before reading it again.**\\n\\n- If you have already read the content and it has not changed, do NOT re-read it.\\n- Only re-read files or folders if:\\n - You suspect the content has changed since your last read.\\n - You have made edits to the file or folder.\\n - You encounter an error that suggests the context may be stale or incomplete.\\n- Use your internal memory and previous context to avoid redundant reads.\\n- This will save time, reduce unnecessary operations, and make your workflow more efficient.\\n\\n# Writing Prompts\\nIf you are asked to write a prompt, you should always generate the prompt in markdown format.\\n\\nIf you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat.\\n\\n# Git \\nIf the user tells you to stage and commit, you may do so. \\n\\nYou are NEVER allowed to stage and commit files automatically.\\n\"},{\"role\":\"user\",\"content\":\"Say hello in one short sentence.\"}],\"stream\":true,\"stream_options\":{\"include_usage\":true},\"max_tokens\":20,\"temperature\":0}" }, "response": { "status": 200, diff --git a/packages/core/test/location-layer.test.ts b/packages/core/test/location-layer.test.ts index 60e788f7b1..34288c042c 100644 --- a/packages/core/test/location-layer.test.ts +++ b/packages/core/test/location-layer.test.ts @@ -526,7 +526,6 @@ describe("LocationServiceMap", () => { "shell", "skill", "subagent", - "todowrite", "webfetch", "websearch", "write", @@ -559,7 +558,6 @@ describe("LocationServiceMap", () => { "shell", "skill", "subagent", - "todowrite", "webfetch", "websearch", "write", @@ -577,7 +575,6 @@ describe("LocationServiceMap", () => { "shell", "skill", "subagent", - "todowrite", "webfetch", "websearch", "write", diff --git a/packages/core/test/permission.test.ts b/packages/core/test/permission.test.ts index 9bc0453298..669fb4d969 100644 --- a/packages/core/test/permission.test.ts +++ b/packages/core/test/permission.test.ts @@ -182,12 +182,12 @@ describe("PermissionV2", () => { const agents = yield* AgentV2.Service yield* agents.transform((editor) => editor.update(AgentV2.ID.make("build"), (agent) => { - agent.permissions = [{ action: "todowrite", resource: "*", effect: "allow" }] + agent.permissions = [{ action: "custom", resource: "*", effect: "allow" }] }), ) const service = yield* PermissionV2.Service - expect(yield* service.ask(assertion({ action: "todowrite", resources: ["*"] }))).toEqual({ + expect(yield* service.ask(assertion({ action: "custom", resources: ["*"] }))).toEqual({ id: PermissionV2.ID.create("per_test"), effect: "allow", }) diff --git a/packages/core/test/session-todo.test.ts b/packages/core/test/session-todo.test.ts deleted file mode 100644 index 9b848f8270..0000000000 --- a/packages/core/test/session-todo.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { describe, expect } from "bun:test" -import { asc } from "drizzle-orm" -import { Effect } from "effect" -import { Database } from "@opencode-ai/core/database/database" -import { LayerNode } from "@opencode-ai/core/effect/layer-node" -import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" -import { EventV2 } from "@opencode-ai/core/event" -import { Project } from "@opencode-ai/core/project" -import { ProjectTable } from "@opencode-ai/core/project/sql" -import { AbsolutePath } from "@opencode-ai/core/schema" -import { SessionV2 } from "@opencode-ai/core/session" -import { SessionTable, TodoTable } from "@opencode-ai/core/session/sql" -import { SessionTodo } from "@opencode-ai/core/session/todo" -import { testEffect } from "./lib/effect" - -const it = testEffect(AppNodeBuilder.build(LayerNode.group([Database.node, EventV2.node, SessionTodo.node]))) -const sessionID = SessionV2.ID.make("ses_todo_test") - -const setup = Effect.gen(function* () { - const { db } = yield* Database.Service - yield* db - .insert(ProjectTable) - .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] }) - .run() - .pipe(Effect.orDie) - yield* db - .insert(SessionTable) - .values({ - id: sessionID, - project_id: Project.ID.global, - slug: "todo", - directory: "/project", - title: "todo", - version: "test", - }) - .run() - .pipe(Effect.orDie) -}) - -describe("SessionTodo", () => { - it.effect("replaces persisted todos in order and publishes updates", () => - Effect.gen(function* () { - yield* setup - const { db } = yield* Database.Service - const events = yield* EventV2.Service - const todos = yield* SessionTodo.Service - const published = new Array() - const unsubscribe = yield* events.listen((event) => - Effect.sync(() => { - if (event.type === SessionTodo.Event.Updated.type) published.push(event) - }), - ) - yield* Effect.addFinalizer(() => unsubscribe) - - yield* todos.update({ - sessionID, - todos: [ - { content: "second", status: "pending", priority: "low" }, - { content: "first", status: "in_progress", priority: "high" }, - ], - }) - expect(yield* todos.get(sessionID)).toEqual([ - { content: "second", status: "pending", priority: "low" }, - { content: "first", status: "in_progress", priority: "high" }, - ]) - expect( - (yield* db.select().from(TodoTable).orderBy(asc(TodoTable.position)).all().pipe(Effect.orDie)).map((row) => ({ - content: row.content, - position: row.position, - })), - ).toEqual([ - { content: "second", position: 0 }, - { content: "first", position: 1 }, - ]) - - yield* todos.update({ sessionID, todos: [{ content: "replacement", status: "completed", priority: "medium" }] }) - expect(yield* todos.get(sessionID)).toEqual([{ content: "replacement", status: "completed", priority: "medium" }]) - - yield* todos.update({ sessionID, todos: [] }) - expect(yield* todos.get(sessionID)).toEqual([]) - expect(published.map((event) => event.data)).toEqual([ - { - sessionID, - todos: [ - { content: "second", status: "pending", priority: "low" }, - { content: "first", status: "in_progress", priority: "high" }, - ], - }, - { sessionID, todos: [{ content: "replacement", status: "completed", priority: "medium" }] }, - { sessionID, todos: [] }, - ]) - }), - ) -}) diff --git a/packages/core/test/shared-schema.test.ts b/packages/core/test/shared-schema.test.ts index 61b03b7484..8cbe9f9e2f 100644 --- a/packages/core/test/shared-schema.test.ts +++ b/packages/core/test/shared-schema.test.ts @@ -24,7 +24,6 @@ import { LLM } from "@opencode-ai/schema/llm" import { Permission } from "@opencode-ai/schema/permission" import { Pty } from "@opencode-ai/schema/pty" import { Reference } from "@opencode-ai/schema/reference" -import { SessionTodo } from "@opencode-ai/schema/session-todo" import { Skill } from "@opencode-ai/schema/skill" import { AbsolutePath, DateTimeUtcFromMillis, optional, statics } from "@opencode-ai/schema/schema" import { ProviderV2 } from "@opencode-ai/core/provider" @@ -46,7 +45,6 @@ test("Core reuses the canonical shared schemas", async () => { coreReference, coreSessionInput, coreSessionMessage, - coreSessionTodo, coreSkill, coreV2Schema, coreSchema, @@ -67,7 +65,6 @@ test("Core reuses the canonical shared schemas", async () => { import("@opencode-ai/core/reference"), import("@opencode-ai/core/session/input"), import("@opencode-ai/core/session/message"), - import("@opencode-ai/core/session/todo"), import("@opencode-ai/core/skill"), import("@opencode-ai/core/v2-schema"), import("@opencode-ai/core/schema"), @@ -160,8 +157,6 @@ test("Core reuses the canonical shared schemas", async () => { [coreSessionMessage.Assistant, SessionMessage.Assistant], [coreSessionMessage.Compaction, SessionMessage.Compaction], [coreSessionMessage.Info, SessionMessage.Info], - [coreSessionTodo.Info, SessionTodo.Info], - [coreSessionTodo.Event, SessionTodo.Event], [coreSkill.DirectorySource, Skill.DirectorySource], [coreSkill.UrlSource, Skill.UrlSource], [coreSkill.EmbeddedSource, Skill.EmbeddedSource], diff --git a/packages/core/test/tool-todowrite.test.ts b/packages/core/test/tool-todowrite.test.ts deleted file mode 100644 index 055df2fbc7..0000000000 --- a/packages/core/test/tool-todowrite.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { describe, expect } from "bun:test" -import { Effect, Layer } from "effect" -import { Database } from "@opencode-ai/core/database/database" -import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder" -import { LayerNode } from "@opencode-ai/core/effect/layer-node" -import { EventV2 } from "@opencode-ai/core/event" -import { PermissionV2 } from "@opencode-ai/core/permission" -import { Project } from "@opencode-ai/core/project" -import { ProjectTable } from "@opencode-ai/core/project/sql" -import { AbsolutePath } from "@opencode-ai/core/schema" -import { SessionV2 } from "@opencode-ai/core/session" -import { SessionTable } from "@opencode-ai/core/session/sql" -import { SessionTodo } from "@opencode-ai/core/session/todo" -import { TodoWriteTool } from "@opencode-ai/core/tool/todowrite" -import { ToolRegistry } from "@opencode-ai/core/tool/registry" -import { ToolOutputStore } from "@opencode-ai/core/tool-output-store" -import { testEffect } from "./lib/effect" -import { makeLocationNode } from "@opencode-ai/core/effect/app-node" -import { toolIdentity, executeTool, registerToolPlugin, settleTool, toolDefinitions } from "./lib/tool" - -const todoWriteToolNode = makeLocationNode({ - name: "test/todowrite-tool-plugin", - layer: Layer.effectDiscard(registerToolPlugin(TodoWriteTool.Plugin)), - deps: [ToolRegistry.toolsNode, PermissionV2.node, SessionTodo.node], -}) - -const sessionID = SessionV2.ID.make("ses_todowrite_tool_test") -const assertions: PermissionV2.AssertInput[] = [] -let deny = false - -const permission = Layer.succeed( - PermissionV2.Service, - PermissionV2.Service.of({ - assert: (input) => - Effect.sync(() => assertions.push(input)).pipe( - Effect.andThen( - deny - ? Effect.fail( - new PermissionV2.BlockedError({ - rules: [], - permission: input.action, - resources: input.resources, - }), - ) - : Effect.void, - ), - ), - ask: () => Effect.die("unused"), - reply: () => Effect.die("unused"), - get: () => Effect.die("unused"), - forSession: () => Effect.die("unused"), - list: () => Effect.die("unused"), - }), -) -const it = testEffect( - AppNodeBuilder.build( - LayerNode.group([ - Database.node, - EventV2.node, - SessionTodo.node, - ToolRegistry.node, - ToolRegistry.toolsNode, - todoWriteToolNode, - ]), - [ - [PermissionV2.node, permission], - [ToolOutputStore.node, ToolOutputStore.nodeWithoutConfig], - ], - ), -) - -const setup = Effect.gen(function* () { - assertions.length = 0 - deny = false - const { db } = yield* Database.Service - yield* db - .insert(ProjectTable) - .values({ id: Project.ID.global, worktree: AbsolutePath.make("/project"), sandboxes: [] }) - .run() - .pipe(Effect.orDie) - yield* db - .insert(SessionTable) - .values({ - id: sessionID, - project_id: Project.ID.global, - slug: "todowrite", - directory: "/project", - title: "todowrite", - version: "test", - }) - .run() - .pipe(Effect.orDie) -}) - -const call = (todos: ReadonlyArray, id = "call-todowrite") => ({ - sessionID, - ...toolIdentity, - call: { type: "tool-call" as const, id, name: TodoWriteTool.name, input: { todos } }, -}) - -describe("TodoWriteTool", () => { - it.effect("registers, approves the wildcard resource, persists todos, and returns typed output", () => - Effect.gen(function* () { - yield* setup - const registry = yield* ToolRegistry.Service - const service = yield* SessionTodo.Service - const todoList: ReadonlyArray = [ - { content: "Implement slice", status: "in_progress", priority: "high" }, - ] - - expect((yield* toolDefinitions(registry)).map((tool) => tool.name)).toEqual([TodoWriteTool.name]) - expect(yield* settleTool(registry, call(todoList))).toEqual({ - result: { type: "text", value: JSON.stringify(todoList, null, 2) }, - output: { - structured: { todos: todoList }, - content: [{ type: "text", text: JSON.stringify(todoList, null, 2) }], - }, - }) - expect(assertions).toMatchObject([{ sessionID, action: "todowrite", resources: ["*"], save: ["*"] }]) - expect(yield* service.get(sessionID)).toEqual(todoList) - }), - ) - - it.effect("does not update persisted todos when permission is denied", () => - Effect.gen(function* () { - yield* setup - const registry = yield* ToolRegistry.Service - const service = yield* SessionTodo.Service - yield* service.update({ sessionID, todos: [{ content: "keep", status: "pending", priority: "low" }] }) - deny = true - - expect( - yield* executeTool(registry, call([{ content: "blocked", status: "completed", priority: "high" }])), - ).toEqual({ - type: "error", - value: "Unable to update todos", - }) - expect(yield* service.get(sessionID)).toEqual([{ content: "keep", status: "pending", priority: "low" }]) - expect(assertions).toMatchObject([{ sessionID, action: "todowrite", resources: ["*"], save: ["*"] }]) - }), - ) -}) diff --git a/packages/docs/openapi.json b/packages/docs/openapi.json index c2cd5a1d21..543a418173 100644 --- a/packages/docs/openapi.json +++ b/packages/docs/openapi.json @@ -75,6 +75,62 @@ "summary": "Check server health" } }, + "/api/server": { + "get": { + "tags": [ + "server" + ], + "operationId": "v2.server.get", + "parameters": [], + "security": [], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "urls": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "urls" + ], + "additionalProperties": false + } + } + } + }, + "400": { + "description": "InvalidRequestError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InvalidRequestError" + } + } + } + }, + "401": { + "description": "UnauthorizedError", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UnauthorizedError" + } + } + } + } + }, + "description": "Return the URLs that can be used to connect to this server.", + "summary": "Get server information" + } + }, "/api/location": { "get": { "tags": [ @@ -18676,6 +18732,7 @@ "required": [ "id", "sessionID", + "title", "mode", "fields" ], @@ -18714,6 +18771,7 @@ "required": [ "id", "sessionID", + "title", "mode", "url" ], @@ -18791,6 +18849,7 @@ } }, "required": [ + "title", "mode" ], "additionalProperties": false @@ -24584,6 +24643,7 @@ "required": [ "id", "sessionID", + "title", "mode", "fields" ], @@ -24622,6 +24682,7 @@ "required": [ "id", "sessionID", + "title", "mode", "url" ], @@ -24844,88 +24905,6 @@ ], "additionalProperties": false }, - "Todo": { - "type": "object", - "properties": { - "content": { - "type": "string", - "description": "Brief description of the task" - }, - "status": { - "type": "string", - "description": "Current status of the task: pending, in_progress, completed, cancelled" - }, - "priority": { - "type": "string", - "description": "Priority level of the task: high, medium, low" - } - }, - "required": [ - "content", - "status", - "priority" - ], - "additionalProperties": false - }, - "todo.updated": { - "type": "object", - "properties": { - "id": { - "type": "string", - "allOf": [ - { - "pattern": "^evt_" - } - ] - }, - "created": { - "type": "number" - }, - "metadata": { - "type": "object" - }, - "type": { - "type": "string", - "enum": [ - "todo.updated" - ] - }, - "location": { - "$ref": "#/components/schemas/Location.Ref" - }, - "data": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "allOf": [ - { - "pattern": "^ses" - } - ] - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": [ - "sessionID", - "todos" - ], - "additionalProperties": false - } - }, - "required": [ - "id", - "created", - "type", - "data" - ], - "additionalProperties": false - }, "SessionStatus": { "anyOf": [ { @@ -26475,9 +26454,6 @@ { "$ref": "#/components/schemas/form.cancelled" }, - { - "$ref": "#/components/schemas/todo.updated" - }, { "$ref": "#/components/schemas/session.status" }, @@ -27072,6 +27048,9 @@ { "name": "health" }, + { + "name": "server" + }, { "name": "location" }, diff --git a/packages/opencode/specs/effect/tools.md b/packages/opencode/specs/effect/tools.md index 61b8aa40dd..862b582701 100644 --- a/packages/opencode/specs/effect/tools.md +++ b/packages/opencode/specs/effect/tools.md @@ -50,7 +50,6 @@ These exported tool definitions currently use `Tool.define(...)` in `src/tool`: - [x] `read.ts` - [x] `skill.ts` - [x] `task.ts` -- [x] `todo.ts` - [x] `webfetch.ts` - [x] `websearch.ts` - [x] `write.ts` diff --git a/packages/opencode/specs/tui-plugins.md b/packages/opencode/specs/tui-plugins.md index 06f7757d51..9dd5932420 100644 --- a/packages/opencode/specs/tui-plugins.md +++ b/packages/opencode/specs/tui-plugins.md @@ -381,7 +381,6 @@ Mode pushes are automatically tracked by the plugin runtime. If a plugin is disa - `vcs?.branch` - `session.count()` - `session.diff(sessionID)` - - `session.todo(sessionID)` - `session.messages(sessionID)` - `session.status(sessionID)` - `session.permission(sessionID)` @@ -511,12 +510,11 @@ Metadata is persisted by plugin id. - `internal:sidebar-context` - `internal:sidebar-mcp` - `internal:sidebar-lsp` -- `internal:sidebar-todo` - `internal:sidebar-files` - `internal:sidebar-footer` - `internal:plugin-manager` -Sidebar content order is currently: context `100`, mcp `200`, lsp `300`, todo `400`, files `500`. +Sidebar content order is currently: context `100`, mcp `200`, lsp `300`, files `500`. The plugin manager is exposed as a command with title `Plugins` and value `plugins.list`. diff --git a/packages/opencode/src/agent/agent.ts b/packages/opencode/src/agent/agent.ts index 5c819e521d..6d4a7599d9 100644 --- a/packages/opencode/src/agent/agent.ts +++ b/packages/opencode/src/agent/agent.ts @@ -182,13 +182,7 @@ const layer = Layer.effect( general: { name: "general", description: `General-purpose agent for researching complex questions and executing multi-step tasks. Use this agent to execute multiple units of work in parallel.`, - permission: Permission.merge( - defaults, - Permission.fromConfig({ - todowrite: "deny", - }), - user, - ), + permission: Permission.merge(defaults, user), options: {}, mode: "subagent", native: true, diff --git a/packages/opencode/src/agent/subagent-permissions.ts b/packages/opencode/src/agent/subagent-permissions.ts index b1b99b484e..596b30a175 100644 --- a/packages/opencode/src/agent/subagent-permissions.ts +++ b/packages/opencode/src/agent/subagent-permissions.ts @@ -8,20 +8,18 @@ import type { Agent } from "./agent" * 1. The parent session's deny rules and external_directory rules. * Parent agent restrictions only govern that agent; the subagent's own * permissions determine its capabilities. - * 2. Default `todowrite` and `task` denies if the subagent's own ruleset - * doesn't already permit them. + * 2. A default `task` deny if the subagent's own ruleset doesn't already + * permit it. */ export function deriveSubagentSessionPermission(input: { parentSessionPermission: PermissionV1.Ruleset subagent: Agent.Info }): PermissionV1.Ruleset { const canTask = input.subagent.permission.some((rule) => rule.permission === "task") - const canTodo = input.subagent.permission.some((rule) => rule.permission === "todowrite") return [ ...input.parentSessionPermission.filter( (rule) => rule.permission === "external_directory" || rule.action === "deny", ), - ...(canTodo ? [] : [{ permission: "todowrite" as const, pattern: "*" as const, action: "deny" as const }]), ...(canTask ? [] : [{ permission: "task" as const, pattern: "*" as const, action: "deny" as const }]), ] } diff --git a/packages/opencode/src/cli/cmd/agent.ts b/packages/opencode/src/cli/cmd/agent.ts index c9c1d2c167..076160b41f 100644 --- a/packages/opencode/src/cli/cmd/agent.ts +++ b/packages/opencode/src/cli/cmd/agent.ts @@ -16,19 +16,7 @@ type AgentMode = "all" | "primary" | "subagent" // Permission keys (not raw tool names). Multiple tools can map to a single // permission — e.g. write/edit/apply_patch all gate on `edit` — so we configure // agents at the permission level to match how the runtime actually enforces it. -const AVAILABLE_PERMISSIONS = [ - "bash", - "read", - "edit", - "glob", - "grep", - "webfetch", - "task", - "todowrite", - "websearch", - "lsp", - "skill", -] +const AVAILABLE_PERMISSIONS = ["bash", "read", "edit", "glob", "grep", "webfetch", "task", "websearch", "lsp", "skill"] const AgentCreateCommand = effectCmd({ command: "create", diff --git a/packages/opencode/src/cli/cmd/github.handler.ts b/packages/opencode/src/cli/cmd/github.handler.ts index d55c0bf3fb..edaecb7b52 100644 --- a/packages/opencode/src/cli/cmd/github.handler.ts +++ b/packages/opencode/src/cli/cmd/github.handler.ts @@ -820,7 +820,6 @@ export const githubRun = Effect.fn("Cli.github.run")(function* (args: { event?: async function subscribeSessionEvents() { const TOOL: Record = { - todowrite: ["Todo", UI.Style.TEXT_WARNING_BOLD], bash: ["Shell", UI.Style.TEXT_DANGER_BOLD], edit: ["Edit", UI.Style.TEXT_SUCCESS_BOLD], glob: ["Glob", UI.Style.TEXT_INFO_BOLD], diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index 19328e73cb..1ebed3b472 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -20,7 +20,6 @@ import { Skill } from "@/skill" import { Discovery } from "@/skill/discovery" import { Question } from "@/question" import { Permission } from "@/permission" -import { Todo } from "@/session/todo" import { Session } from "@/session/session" import { SessionStatus } from "@/session/status" import { SessionRunState } from "@/session/run-state" @@ -75,7 +74,6 @@ export const AppLayer = AppNodeBuilderV1.build( Discovery.node, Question.node, Permission.node, - Todo.node, Session.node, SessionProjector.node, SessionStatus.node, diff --git a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts index 959a303dc9..4fb08281ca 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/groups/session.ts @@ -8,7 +8,6 @@ import { SessionPrompt } from "@/session/prompt" import { SessionRevert } from "@/session/revert" import { SessionStatus } from "@/session/status" import { SessionSummary } from "@/session/summary" -import { Todo } from "@/session/todo" import { MessageID, PartID, SessionID } from "@/session/schema" import { Snapshot } from "@/snapshot" import { Schema, Struct } from "effect" @@ -80,7 +79,6 @@ export const SessionPaths = { status: `${root}/status`, get: `${root}/:sessionID`, children: `${root}/:sessionID/children`, - todo: `${root}/:sessionID/todo`, diff: `${root}/:sessionID/diff`, messages: `${root}/:sessionID/message`, message: `${root}/:sessionID/message/:messageID`, @@ -153,18 +151,6 @@ export const SessionApi = HttpApi.make("session") description: "Retrieve all child sessions that were forked from the specified parent session.", }), ), - HttpApiEndpoint.get("todo", SessionPaths.todo, { - params: { sessionID: SessionID }, - query: WorkspaceRoutingQuery, - success: described(Schema.Array(Todo.Info), "Todo list"), - error: [HttpApiError.BadRequest, ApiNotFoundError], - }).annotateMerge( - OpenApi.annotations({ - identifier: "session.todo", - summary: "Get session todos", - description: "Retrieve the todo list associated with a specific session, showing tasks and action items.", - }), - ), HttpApiEndpoint.get("diff", SessionPaths.diff, { params: { sessionID: SessionID }, query: DiffQuery, diff --git a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts index 662585020a..f0478b6fbb 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts @@ -13,7 +13,6 @@ import { SessionRevert } from "@/session/revert" import { SessionRunState } from "@/session/run-state" import { SessionStatus } from "@/session/status" import { SessionSummary } from "@/session/summary" -import { Todo } from "@/session/todo" import { MessageID, PartID, SessionID } from "@/session/schema" import { NamedError } from "@opencode-ai/core/util/error" import { Cause, Effect, Option, Schema, Scope } from "effect" @@ -56,7 +55,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", const agentSvc = yield* Agent.Service const permissionSvc = yield* Permission.Service const statusSvc = yield* SessionStatus.Service - const todoSvc = yield* Todo.Service const summary = yield* SessionSummary.Service const events = yield* EventV2Bridge.Service const scope = yield* Scope.Scope @@ -91,11 +89,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", return yield* session.children(ctx.params.sessionID) }) - const todo = Effect.fn("SessionHttpApi.todo")(function* (ctx: { params: { sessionID: SessionID } }) { - yield* requireSession(ctx.params.sessionID) - return yield* todoSvc.get(ctx.params.sessionID) - }) - const diff = Effect.fn("SessionHttpApi.diff")(function* (ctx: { params: { sessionID: SessionID } query: typeof DiffQuery.Type @@ -415,7 +408,6 @@ export const sessionHandlers = HttpApiBuilder.group(InstanceHttpApi, "session", .handle("status", status) .handle("get", get) .handle("children", children) - .handle("todo", todo) .handle("diff", diff) .handle("messages", messages) .handle("message", message) diff --git a/packages/opencode/src/server/routes/instance/httpapi/server.ts b/packages/opencode/src/server/routes/instance/httpapi/server.ts index 108888d4f6..471d9aa376 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/server.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/server.ts @@ -38,7 +38,6 @@ import { SessionRunState } from "@/session/run-state" import { Session } from "@/session/session" import { SessionStatus } from "@/session/status" import { SessionSummary } from "@/session/summary" -import { Todo } from "@/session/todo" import { SessionShare } from "@/share/session" import { ShareNext } from "@/share/share-next" import { Skill } from "@/skill" @@ -233,7 +232,6 @@ const app = LayerNode.group([ Question.node, Permission.node, PermissionSaved.node, - Todo.node, Session.node, SessionProjector.node, SessionStatus.node, diff --git a/packages/opencode/src/session/prompt/anthropic.txt b/packages/opencode/src/session/prompt/anthropic.txt index 21d9c0e9f2..a816861b26 100644 --- a/packages/opencode/src/session/prompt/anthropic.txt +++ b/packages/opencode/src/session/prompt/anthropic.txt @@ -20,58 +20,7 @@ When the user directly asks about OpenCode (eg. "can OpenCode do...", "does Open # Professional objectivity Prioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical info without any unnecessary superlatives, praise, or emotional validation. It is best for the user if OpenCode honestly applies the same rigorous standards to all ideas and disagrees when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, it's best to investigate to find the truth first rather than instinctively confirming the user's beliefs. -# Task Management -You have access to the TodoWrite tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress. -These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable. - -It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed. - -Examples: - - -user: Run the build and fix any type errors -assistant: I'm going to use the TodoWrite tool to write the following items to the todo list: -- Run the build -- Fix any type errors - -I'm now going to run the build using Bash. - -Looks like I found 10 type errors. I'm going to use the TodoWrite tool to write 10 items to the todo list. - -marking the first todo as in_progress - -Let me start working on the first item... - -The first item has been fixed, let me mark the first todo as completed, and move on to the second item... -.. -.. - -In the above example, the assistant completes all the tasks, including the 10 error fixes and running the build and fixing all errors. - - -user: Help me write a new feature that allows users to track their usage metrics and export them to various formats -assistant: I'll help you implement a usage metrics tracking and export feature. Let me first use the TodoWrite tool to plan this task. -Adding the following todos to the todo list: -1. Research existing metrics tracking in the codebase -2. Design the metrics collection system -3. Implement core metrics tracking functionality -4. Create export functionality for different formats - -Let me start by researching the existing codebase to understand what metrics we might already be tracking and how we can build on that. - -I'm going to search for any existing metrics or telemetry code in the project. - -I've found some existing telemetry code. Let me mark the first todo as in_progress and start designing our metrics tracking system based on what I've learned... - -[Assistant continues implementing the feature step by step, marking todos as in_progress and completed as they go] - - - # Doing tasks -The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended: -- -- Use the TodoWrite tool to plan the task if required - - Tool results and user messages may include tags. tags contain useful information and reminders. They are automatically added by the system, and bear no direct relation to the specific tool results or user messages in which they appear. @@ -93,8 +42,6 @@ user: What is the codebase structure? assistant: [Uses the Task tool] -IMPORTANT: Always use the TodoWrite tool to plan and track tasks throughout the conversation. - # Code References When referencing specific functions or pieces of code include the pattern `file_path:line_number` to allow the user to easily navigate to the source code location. diff --git a/packages/opencode/src/session/prompt/beast.txt b/packages/opencode/src/session/prompt/beast.txt index e92e4d020f..193bd05c52 100644 --- a/packages/opencode/src/session/prompt/beast.txt +++ b/packages/opencode/src/session/prompt/beast.txt @@ -6,7 +6,7 @@ You MUST iterate and keep going until the problem is solved. You have everything you need to resolve this problem. I want you to fully solve this autonomously before coming back to me. -Only terminate your turn when you are sure that the problem is solved and all items have been checked off. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn. +Only terminate your turn when you are sure that the problem is solved. Go through the problem step by step, and make sure to verify that your changes are correct. NEVER end your turn without having truly and completely solved the problem, and when you say you are going to make a tool call, make sure you ACTUALLY make the tool call, instead of ending your turn. THE PROBLEM CAN NOT BE SOLVED WITHOUT EXTENSIVE INTERNET RESEARCH. @@ -19,13 +19,13 @@ understanding of third party packages and dependencies is up to date. You must u Always tell the user what you are going to do before making a tool call with a single concise sentence. This will help them understand what you are doing and why. -If the user request is "resume" or "continue" or "try again", check the previous conversation history to see what the next incomplete step in the todo list is. Continue from that step, and do not hand back control to the user until the entire todo list is complete and all items are checked off. Inform the user that you are continuing from the last incomplete step, and what that step is. +If the user request is "resume" or "continue" or "try again", check the previous conversation history to identify the next incomplete step. Continue from that step, and do not hand back control to the user until the problem is solved. Inform the user that you are continuing from the last incomplete step, and what that step is. Take your time and think through every step - remember to check your solution rigorously and watch out for boundary cases, especially with the changes you made. Use the sequential thinking tool if available. Your solution must be perfect. If not, continue working on it. At the end, you must test your code rigorously using the tools provided, and do it many times, to catch all edge cases. If it is not robust, iterate more and make it perfect. Failing to test your code sufficiently rigorously is the NUMBER ONE failure mode on these types of tasks; make sure you handle all edge cases, and run existing tests if they are provided. You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully. -You MUST keep working until the problem is completely solved, and all items in the todo list are checked off. Do not end your turn until you have completed all steps in the todo list and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. +You MUST keep working until the problem is completely solved. Do not end your turn until you have completed all necessary steps and verified that everything is working correctly. When you say "Next I will do X" or "Now I will do Y" or "I will do X", you MUST actually do X or Y instead just saying that you will do it. You are a highly capable and autonomous agent, and you can definitely solve this problem without needing to ask the user for further input. @@ -39,7 +39,7 @@ You are a highly capable and autonomous agent, and you can definitely solve this - What are the dependencies and interactions with other parts of the code? 3. Investigate the codebase. Explore relevant files, search for key functions, and gather context. 4. Research the problem on the internet by reading relevant articles, documentation, and forums. -5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. Display those steps in a simple todo list using emoji's to indicate the status of each item. +5. Develop a clear, step-by-step plan. Break down the fix into manageable, incremental steps. 6. Implement the fix incrementally. Make small, testable code changes. 7. Debug as needed. Use debugging techniques to isolate and resolve issues. 8. Test frequently. Run tests after each change to verify correctness. @@ -73,9 +73,6 @@ Carefully read the issue and think hard about a plan to solve it before coding. ## 5. Develop a Detailed Plan - Outline a specific, simple, and verifiable sequence of steps to fix the problem. -- Create a todo list in markdown format to track your progress. -- Each time you complete a step, check it off using `[x]` syntax. -- Each time you check off a step, display the updated todo list to the user. - Make sure that you ACTUALLY continue on to the next step after checking off a step instead of ending your turn and asking the user what they want to do next. ## 6. Making Code Changes @@ -139,7 +136,6 @@ If you are asked to write a prompt, you should always generate the prompt in ma If you are not writing the prompt in a file, you should always wrap the prompt in triple backticks so that it is formatted correctly and can be easily copied from the chat. -Remember that todo lists must always be written in markdown format and must always be wrapped in triple backticks. # Git If the user tells you to stage and commit, you may do so. diff --git a/packages/opencode/src/session/prompt/copilot-gpt-5.txt b/packages/opencode/src/session/prompt/copilot-gpt-5.txt index d8da6d2017..d7a7776789 100644 --- a/packages/opencode/src/session/prompt/copilot-gpt-5.txt +++ b/packages/opencode/src/session/prompt/copilot-gpt-5.txt @@ -23,14 +23,14 @@ You must use webfetch tool to recursively gather all information from URL's prov 1. Understand the problem deeply. Carefully read the issue and think critically about what is required. 2. Investigate the codebase. Explore relevant files, search for key functions, and gather context. 3. Develop a clear, step-by-step plan. Break down the fix into manageable, -incremental steps - use the todo tool to track your progress. +incremental steps and track your progress. 4. Implement the fix incrementally. Make small, testable code changes. 5. Debug as needed. Use debugging techniques to isolate and resolve issues. 6. Test frequently. Run tests after each change to verify correctness. 7. Iterate until the root cause is fixed and all tests pass. 8. Reflect and validate comprehensively. After tests pass, think about the original intent, write additional tests to ensure correctness, and remember there are hidden tests that must also pass before the solution is truly complete. **CRITICAL - Before ending your turn:** -- Review and update the todo list, marking completed, skipped (with explanations), or blocked items. +- Review the plan, noting completed, skipped (with explanations), or blocked items. ## 1. Deeply Understand the Problem - Carefully read the issue and think hard about a plan to solve it before coding. @@ -50,8 +50,8 @@ incremental steps - use the todo tool to track your progress. ## 3. Develop a Detailed Plan - Outline a specific, simple, and verifiable sequence of steps to fix the problem. -- Create a todo list to track your progress. -- Each time you check off a step, update the todo list. +- Create a plan to track your progress. +- Keep the plan current as you complete each step. - Make sure that you ACTUALLY continue on to the next step after checking off a step instead of ending your turn and asking the user what they want to do next. ## 4. Making Code Changes diff --git a/packages/opencode/src/session/todo.ts b/packages/opencode/src/session/todo.ts deleted file mode 100644 index cd80828de6..0000000000 --- a/packages/opencode/src/session/todo.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { LayerNode } from "@opencode-ai/core/effect/layer-node" -import { SessionID } from "./schema" -import { Effect, Layer, Context } from "effect" -import { Database } from "@opencode-ai/core/database/database" -import { eq } from "drizzle-orm" -import { asc } from "drizzle-orm" -import { TodoTable } from "@opencode-ai/core/session/sql" -import { EventV2Bridge } from "@/event-v2-bridge" -import { SessionTodo } from "@opencode-ai/schema/session-todo" - -export const Info = SessionTodo.Info -export type Info = SessionTodo.Info - -export const Event = SessionTodo.Event - -export interface Interface { - readonly update: (input: { sessionID: SessionID; todos: ReadonlyArray }) => Effect.Effect - readonly get: (sessionID: SessionID) => Effect.Effect -} - -export class Service extends Context.Service()("@opencode/SessionTodo") {} - -const layer = Layer.effect( - Service, - Effect.gen(function* () { - const events = yield* EventV2Bridge.Service - const { db } = yield* Database.Service - - const update = Effect.fn("Todo.update")(function* (input: { sessionID: SessionID; todos: ReadonlyArray }) { - yield* db - .transaction((tx) => - Effect.gen(function* () { - yield* tx.delete(TodoTable).where(eq(TodoTable.session_id, input.sessionID)).run() - if (input.todos.length === 0) return - yield* tx - .insert(TodoTable) - .values( - input.todos.map((todo, position) => ({ - session_id: input.sessionID, - content: todo.content, - status: todo.status, - priority: todo.priority, - position, - })), - ) - .run() - }), - ) - .pipe(Effect.orDie) - yield* events.publish(Event.Updated, input) - }) - - const get = Effect.fn("Todo.get")(function* (sessionID: SessionID) { - const rows = yield* db - .select() - .from(TodoTable) - .where(eq(TodoTable.session_id, sessionID)) - .orderBy(asc(TodoTable.position)) - .all() - .pipe(Effect.orDie) - return rows.map((row) => ({ - content: row.content, - status: row.status, - priority: row.priority, - })) - }) - - return Service.of({ update, get }) - }), -) - -export const node = LayerNode.make({ service: Service, layer: layer, deps: [EventV2Bridge.node, Database.node] }) - -export * as Todo from "./todo" diff --git a/packages/opencode/src/storage/schema.ts b/packages/opencode/src/storage/schema.ts index 06d095f06d..450ccb43d1 100644 --- a/packages/opencode/src/storage/schema.ts +++ b/packages/opencode/src/storage/schema.ts @@ -1,5 +1,5 @@ export { AccountTable, AccountStateTable, ControlAccountTable } from "@opencode-ai/core/account/sql" export { ProjectTable } from "@opencode-ai/core/project/sql" -export { SessionTable, MessageTable, PartTable, TodoTable } from "@opencode-ai/core/session/sql" +export { SessionTable, MessageTable, PartTable } from "@opencode-ai/core/session/sql" export { SessionShareTable } from "@opencode-ai/core/share/sql" export { WorkspaceTable } from "@opencode-ai/core/control-plane/workspace.sql" diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index 037cf236dc..4576bd7a88 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -11,7 +11,6 @@ import { GrepTool } from "./grep" import { ReadTool } from "./read" import { TaskTool } from "./task" import { Database } from "@opencode-ai/core/database/database" -import { TodoWriteTool } from "./todo" import { WebFetchTool } from "./webfetch" import { WriteTool } from "./write" import { InvalidTool } from "./invalid" @@ -39,7 +38,6 @@ import { Format } from "../format" import { InstanceState } from "@/effect/instance-state" import { EffectBridge } from "@/effect/bridge" import { Question } from "../question" -import { Todo } from "../session/todo" import { LSP } from "@/lsp/lsp" import { Instruction } from "../session/instruction" import { FSUtil } from "@opencode-ai/core/fs-util" @@ -97,7 +95,6 @@ const layer = Layer.effect( const task = yield* TaskTool const read = yield* ReadTool const question = yield* QuestionTool - const todo = yield* TodoWriteTool const lsptool = yield* LspTool const plan = yield* PlanExitTool const webfetch = yield* WebFetchTool @@ -211,7 +208,6 @@ const layer = Layer.effect( write: Tool.init(writetool), task: Tool.init(task), fetch: Tool.init(webfetch), - todo: Tool.init(todo), search: Tool.init(websearch), skill: Tool.init(skilltool), patch: Tool.init(patchtool), @@ -234,7 +230,6 @@ const layer = Layer.effect( tool.write, tool.task, tool.fetch, - tool.todo, tool.search, tool.skill, tool.patch, @@ -426,7 +421,6 @@ export const node = LayerNode.make({ Config.node, Plugin.node, Question.node, - Todo.node, Agent.node, Skill.node, Session.node, diff --git a/packages/opencode/src/tool/task.ts b/packages/opencode/src/tool/task.ts index 4039fd36fa..c753d17715 100644 --- a/packages/opencode/src/tool/task.ts +++ b/packages/opencode/src/tool/task.ts @@ -117,9 +117,6 @@ export const TaskTool = Tool.define( subagent: next, }) const childToolDenies = [ - ...(next.permission.some((rule) => rule.permission === "todowrite") - ? [] - : [{ permission: "todowrite" as const, pattern: "*" as const, action: "deny" as const }]), ...(next.permission.some((rule) => rule.permission === id) ? [] : [{ permission: id, pattern: "*" as const, action: "deny" as const }]), diff --git a/packages/opencode/src/tool/todo.ts b/packages/opencode/src/tool/todo.ts deleted file mode 100644 index 69fb0550e8..0000000000 --- a/packages/opencode/src/tool/todo.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Effect, Schema } from "effect" -import * as Tool from "./tool" -import DESCRIPTION_WRITE from "./todowrite.txt" -import { Todo } from "../session/todo" - -export const Parameters = Schema.Struct({ - todos: Schema.mutable(Schema.Array(Todo.Info)).annotate({ description: "The updated todo list" }), -}) - -type Metadata = { - todos: Todo.Info[] -} - -export const TodoWriteTool = Tool.define( - "todowrite", - Effect.gen(function* () { - const todo = yield* Todo.Service - - return { - description: DESCRIPTION_WRITE, - parameters: Parameters, - execute: (params: Schema.Schema.Type, ctx: Tool.Context) => - Effect.gen(function* () { - yield* ctx.ask({ - permission: "todowrite", - patterns: ["*"], - always: ["*"], - metadata: {}, - }) - - yield* todo.update({ - sessionID: ctx.sessionID, - todos: params.todos, - }) - - return { - title: `${params.todos.filter((x) => x.status !== "completed").length} todos`, - output: JSON.stringify(params.todos, null, 2), - metadata: { - todos: params.todos, - }, - } - }), - } satisfies Tool.DefWithoutID - }), -) diff --git a/packages/opencode/src/tool/todowrite.txt b/packages/opencode/src/tool/todowrite.txt deleted file mode 100644 index a21630c158..0000000000 --- a/packages/opencode/src/tool/todowrite.txt +++ /dev/null @@ -1,44 +0,0 @@ -Create and maintain a structured task list for the current coding session. Tracks progress, organizes multi-step work, and surfaces status to the user. - -## When to use -Use proactively when: -- The task requires 3+ distinct steps or actions (not just 3 tool calls for a single conceptual step) -- The work is non-trivial and benefits from planning -- The user provides multiple tasks (numbered or comma-separated) or explicitly asks for a todo list -- New instructions arrive - capture them as todos -- You start a task - mark it `in_progress` (only one at a time) before working -- You finish a task - mark it `completed` and add any follow-ups discovered during the work - -## When NOT to use -Skip when: -- The work is a single, straightforward task (or <3 trivial steps) -- The request is purely informational or conversational -- Tracking adds no organizational value - -## States -- `pending` - not started -- `in_progress` - actively working (exactly ONE at a time) -- `completed` - finished successfully -- `cancelled` - no longer needed - -## Rules -- Update status in real time; don't batch completions -- Mark `completed` only after the required work is actually done, including any required verification. Never based on intent. -- Keep exactly one `in_progress` while work remains -- If blocked or partial, keep it `in_progress` and add a follow-up todo describing the blocker -- Preserve user-provided commands verbatim (flags, args, order) -- Items should be specific and actionable; break large work into smaller steps - -## Examples - -Use it: -- "Add a dark mode toggle and run the tests" -> multi-step feature + explicit verification -- "Rename getCwd -> getCurrentWorkingDirectory across the repo" -> grep reveals 15 occurrences in 8 files -- "Implement registration, catalog, cart, checkout" -> multiple complex features - -Skip it: -- "How do I print Hello World in Python?" -> informational -- "Add a comment to calculateTotal" -> single edit -- "Run npm install and tell me what happened" -> one command - -When in doubt, use it. diff --git a/packages/opencode/test/agent/agent.test.ts b/packages/opencode/test/agent/agent.test.ts index efeaf408a2..2e13e26a95 100644 --- a/packages/opencode/test/agent/agent.test.ts +++ b/packages/opencode/test/agent/agent.test.ts @@ -116,7 +116,6 @@ it.instance("explore agent denies edit and write", () => expect(explore?.mode).toBe("subagent") expect(evalPerm(explore, "edit")).toBe("deny") expect(evalPerm(explore, "write")).toBe("deny") - expect(evalPerm(explore, "todowrite")).toBe("deny") }), ) @@ -160,16 +159,6 @@ it.instance( }, ) -it.instance("general agent denies todo tools", () => - Effect.gen(function* () { - const general = yield* load((svc) => svc.get("general")) - expect(general).toBeDefined() - expect(general?.mode).toBe("subagent") - expect(general?.hidden).toBeUndefined() - expect(evalPerm(general, "todowrite")).toBe("deny") - }), -) - it.instance("compaction agent denies all permissions", () => Effect.gen(function* () { const compaction = yield* load((svc) => svc.get("compaction")) diff --git a/packages/opencode/test/cli/github-action.test.ts b/packages/opencode/test/cli/github-action.test.ts index 57567d8c9b..2cf914ed78 100644 --- a/packages/opencode/test/cli/github-action.test.ts +++ b/packages/opencode/test/cli/github-action.test.ts @@ -93,7 +93,7 @@ describe("extractResponseText", () => { }) test("returns text even when tool parts follow", () => { - const parts = [createTextPart("I'll help with that."), createToolPart("todowrite", "3 todos")] + const parts = [createTextPart("I'll help with that."), createToolPart("read", "src/index.ts")] expect(extractResponseText(parts)).toBe("I'll help with that.") }) @@ -103,8 +103,7 @@ describe("extractResponseText", () => { }) test("returns null for tool-only response (signals summary needed)", () => { - // This is the exact scenario from the bug report - todowrite with no text - const parts = [createToolPart("todowrite", "8 todos")] + const parts = [createToolPart("read", "src/index.ts")] expect(extractResponseText(parts)).toBeNull() }) diff --git a/packages/opencode/test/cli/help/__snapshots__/help-snapshots.test.ts.snap b/packages/opencode/test/cli/help/__snapshots__/help-snapshots.test.ts.snap index 5c84f0d389..90da1632d5 100644 --- a/packages/opencode/test/cli/help/__snapshots__/help-snapshots.test.ts.snap +++ b/packages/opencode/test/cli/help/__snapshots__/help-snapshots.test.ts.snap @@ -519,8 +519,8 @@ Options: --description what the agent should do [string] --mode agent mode [string] [choices: "all", "primary", "subagent"] --permissions, --tools comma-separated list of permissions to allow (default: all). - Available: "bash, read, edit, glob, grep, webfetch, task, todowrite, - websearch, lsp, skill" [string] + Available: "bash, read, edit, glob, grep, webfetch, task, websearch, + lsp, skill" [string] -m, --model model to use in the format of provider/model [string]" `; diff --git a/packages/opencode/test/cli/run/scrollback.surface.test.ts b/packages/opencode/test/cli/run/scrollback.surface.test.ts index abe40559ed..039ab156fd 100644 --- a/packages/opencode/test/cli/run/scrollback.surface.test.ts +++ b/packages/opencode/test/cli/run/scrollback.surface.test.ts @@ -321,50 +321,8 @@ test("holds markdown code blocks until final commit and keeps newline ownership" } }) -test("renders todo and question summaries without boilerplate footer copy", async () => { +test("renders question summaries without boilerplate footer copy", async () => { const cases = [ - { - title: "# Todos", - include: [ - "[✓] List files under `run/`", - "[•] Count functions in each `run/` file", - "[ ] Mark each tracking item complete", - ], - exclude: ["Updating", "todos completed"], - start: toolCommit({ - tool: "todowrite", - phase: "start", - toolState: "running", - state: { - status: "running", - input: { - todos: [ - { status: "completed", content: "List files under `run/`" }, - { status: "in_progress", content: "Count functions in each `run/` file" }, - { status: "pending", content: "Mark each tracking item complete" }, - ], - }, - time: { start: 1 }, - }, - }), - final: toolCommit({ - tool: "todowrite", - phase: "final", - toolState: "completed", - state: { - status: "completed", - input: { - todos: [ - { status: "completed", content: "List files under `run/`" }, - { status: "in_progress", content: "Count functions in each `run/` file" }, - { status: "pending", content: "Mark each tracking item complete" }, - ], - }, - metadata: {}, - time: { start: 1, end: 4 }, - }, - }), - }, { title: "# Questions", include: ["What should I work on in the codebase next?", "Bug fix"], diff --git a/packages/opencode/test/cli/tui/plugin-loader.test.ts b/packages/opencode/test/cli/tui/plugin-loader.test.ts index 49ea06affc..c542914cad 100644 --- a/packages/opencode/test/cli/tui/plugin-loader.test.ts +++ b/packages/opencode/test/cli/tui/plugin-loader.test.ts @@ -220,7 +220,6 @@ export default { api.kv.set(options.kv_key, "stored") const kv_after = api.kv.get(options.kv_key, "missing") const diff = api.state.session.diff(options.session_id) - const todo = api.state.session.todo(options.session_id) const lsp = api.state.lsp() const mcp = api.state.mcp() const depth_before = api.ui.dialog.depth @@ -263,8 +262,6 @@ export default { kv_ready: api.kv.ready, diff_count: diff.length, diff_file: diff[0]?.file, - todo_count: todo.length, - todo_first: todo[0]?.content, lsp_count: lsp.length, mcp_count: mcp.length, mcp_first: mcp[0]?.name, @@ -513,10 +510,6 @@ export default { if (sessionID !== "ses_test") return [] return [{ file: "src/app.ts", additions: 3, deletions: 1 }] }, - todo(sessionID) { - if (sessionID !== "ses_test") return [] - return [{ content: "ship it", status: "pending" }] - }, }, lsp() { return [{ id: "ts", root: "/tmp/project", status: "connected" }] @@ -867,8 +860,6 @@ describe("tui.plugin.loader", () => { expect(data.local.kv_ready).toBe(true) expect(data.local.diff_count).toBe(1) expect(data.local.diff_file).toBe("src/app.ts") - expect(data.local.todo_count).toBe(1) - expect(data.local.todo_first).toBe("ship it") expect(data.local.lsp_count).toBe(1) expect(data.local.mcp_count).toBe(1) expect(data.local.mcp_first).toBe("github") diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index e281831ddf..ac408ea812 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -1307,7 +1307,6 @@ it.instance("permission config preserves user key order", () => write: "ask", external_directory: "ask", read: "allow", - todowrite: "allow", "thoughts_*": "allow", "reasoning_model_*": "allow", "tools_*": "allow", @@ -1322,7 +1321,6 @@ it.instance("permission config preserves user key order", () => "write", "external_directory", "read", - "todowrite", "thoughts_*", "reasoning_model_*", "tools_*", diff --git a/packages/opencode/test/event-manifest.test.ts b/packages/opencode/test/event-manifest.test.ts index 64755ad44f..a54a0c6ac8 100644 --- a/packages/opencode/test/event-manifest.test.ts +++ b/packages/opencode/test/event-manifest.test.ts @@ -2,7 +2,6 @@ import { describe, expect, test } from "bun:test" import { SessionEvent } from "@opencode-ai/core/session/event" import { Agent } from "@opencode-ai/schema" import { EventManifest as SchemaEventManifest } from "@opencode-ai/schema/event-manifest" -import { Todo } from "@/session/todo" import { EventManifest } from "@/event-manifest" describe("public event manifest", () => { @@ -10,10 +9,9 @@ describe("public event manifest", () => { expect(EventManifest.Definitions).toBe(SchemaEventManifest.Definitions) expect(EventManifest.Latest).toBe(SchemaEventManifest.Latest) expect(EventManifest.Durable).toBe(SchemaEventManifest.Durable) - expect(Array.from(EventManifest.Latest.keys()).filter((type) => type !== "agent.updated").length).toBe(101) + expect(Array.from(EventManifest.Latest.keys()).filter((type) => type !== "agent.updated").length).toBe(108) expect(EventManifest.Latest.get("session.next.step.ended")).toBe(SessionEvent.Step.Ended) expect(EventManifest.Latest.get("agent.updated")).toBe(Agent.Event.Updated) - expect(EventManifest.Latest.get("todo.updated")).toBe(Todo.Event.Updated) expect(EventManifest.Latest.has("ide.installed")).toBe(false) expect(EventManifest.Latest.has("server.connected")).toBe(true) expect(EventManifest.Latest.has("global.disposed")).toBe(true) diff --git a/packages/opencode/test/fixture/tui-plugin.ts b/packages/opencode/test/fixture/tui-plugin.ts index 5d93139f00..d94b02e7ca 100644 --- a/packages/opencode/test/fixture/tui-plugin.ts +++ b/packages/opencode/test/fixture/tui-plugin.ts @@ -316,7 +316,6 @@ export function createTuiPluginApi(opts: Opts = {}): HostPluginApi { count: opts.state?.session?.count ?? (() => 0), get: opts.state?.session?.get ?? (() => undefined), diff: opts.state?.session?.diff ?? (() => []), - todo: opts.state?.session?.todo ?? (() => []), messages: opts.state?.session?.messages ?? (() => []), status: opts.state?.session?.status ?? (() => undefined), permission: opts.state?.session?.permission ?? (() => []), diff --git a/packages/opencode/test/server/httpapi-exercise/index.ts b/packages/opencode/test/server/httpapi-exercise/index.ts index 195699f9c9..b815f5f7da 100644 --- a/packages/opencode/test/server/httpapi-exercise/index.ts +++ b/packages/opencode/test/server/httpapi-exercise/index.ts @@ -1326,23 +1326,6 @@ const scenarios: Scenario[] = [ "children should include seeded child", ) }), - http.protected - .get("/session/{sessionID}/todo", "session.todo") - .seeded((ctx) => - Effect.gen(function* () { - const session = yield* ctx.session({ title: "Todo session" }) - const todos = [{ content: "cover session todo", status: "pending" as const, priority: "high" as const }] - yield* ctx.todos(session.id, todos) - return { session, todos } - }), - ) - .at((ctx) => ({ - path: route("/session/{sessionID}/todo", { sessionID: ctx.state.session.id }), - headers: ctx.headers(), - })) - .json(200, (body, ctx) => { - check(stable(body) === stable(ctx.state.todos), "todos should match seeded state") - }), http.protected .get("/session/{sessionID}/diff", "session.diff") .seeded((ctx) => ctx.session({ title: "Diff session" })) diff --git a/packages/opencode/test/server/httpapi-exercise/runner.ts b/packages/opencode/test/server/httpapi-exercise/runner.ts index b7ad6d6208..37e24b790b 100644 --- a/packages/opencode/test/server/httpapi-exercise/runner.ts +++ b/packages/opencode/test/server/httpapi-exercise/runner.ts @@ -176,7 +176,6 @@ function withContext( }), messages: (sessionID) => run(modules.Session.Service.use((svc) => svc.messages({ sessionID }).pipe(Effect.orDie))), - todos: (sessionID, todos) => run(modules.Todo.Service.use((svc) => svc.update({ sessionID, todos }))), worktree: (input) => run(modules.Worktree.Service.use((svc) => svc.create(input).pipe(Effect.orDie))), worktreeRemove: (directory) => run(modules.Worktree.Service.use((svc) => svc.remove({ directory })).pipe(Effect.ignore)), diff --git a/packages/opencode/test/server/httpapi-exercise/runtime.ts b/packages/opencode/test/server/httpapi-exercise/runtime.ts index 81bd302a1a..b7a3952bde 100644 --- a/packages/opencode/test/server/httpapi-exercise/runtime.ts +++ b/packages/opencode/test/server/httpapi-exercise/runtime.ts @@ -6,7 +6,6 @@ export type Runtime = { InstanceRef: (typeof import("../../../src/effect/instance-ref"))["InstanceRef"] InstanceStore: (typeof import("../../../src/project/instance-store"))["InstanceStore"] Session: (typeof import("../../../src/session/session"))["Session"] - Todo: (typeof import("../../../src/session/todo"))["Todo"] Worktree: (typeof import("../../../src/worktree"))["Worktree"] Project: (typeof import("../../../src/project/project"))["Project"] Tui: typeof import("../../../src/server/shared/tui-control") @@ -26,7 +25,6 @@ export function runtime() { const instanceRef = await import("../../../src/effect/instance-ref") const instanceStore = await import("../../../src/project/instance-store") const session = await import("../../../src/session/session") - const todo = await import("../../../src/session/todo") const worktree = await import("../../../src/worktree") const project = await import("../../../src/project/project") const tui = await import("../../../src/server/shared/tui-control") @@ -40,7 +38,6 @@ export function runtime() { InstanceRef: instanceRef.InstanceRef, InstanceStore: instanceStore.InstanceStore, Session: session.Session, - Todo: todo.Todo, Worktree: worktree.Worktree, Project: project.Project, Tui: tui, diff --git a/packages/opencode/test/server/httpapi-exercise/types.ts b/packages/opencode/test/server/httpapi-exercise/types.ts index acc1898e32..0895216505 100644 --- a/packages/opencode/test/server/httpapi-exercise/types.ts +++ b/packages/opencode/test/server/httpapi-exercise/types.ts @@ -60,7 +60,6 @@ export type ScenarioContext = { project: () => Effect.Effect message: (sessionID: SessionID, input?: { text?: string }) => Effect.Effect messages: (sessionID: SessionID) => Effect.Effect - todos: (sessionID: SessionID, todos: TodoInfo[]) => Effect.Effect worktree: (input?: { name?: string }) => Effect.Effect worktreeRemove: (directory: string) => Effect.Effect llmText: (value: string) => Effect.Effect @@ -119,9 +118,4 @@ export type Result = | { status: "skip"; scenario: TodoScenario } export type SessionInfo = { id: SessionID; title: string; parentID?: SessionID } -export type TodoInfo = { - content: string - status: "pending" | "in_progress" | "completed" | "cancelled" - priority: "high" | "medium" | "low" -} export type MessageSeed = { info: SessionV1.User; part: SessionV1.TextPart } diff --git a/packages/opencode/test/server/httpapi-sdk.test.ts b/packages/opencode/test/server/httpapi-sdk.test.ts index 0af92ae382..a6f308f032 100644 --- a/packages/opencode/test/server/httpapi-sdk.test.ts +++ b/packages/opencode/test/server/httpapi-sdk.test.ts @@ -577,7 +577,6 @@ describe("HttpApi SDK", () => { const roots = yield* capture(() => sdk.session.list({ roots: true, limit: 10 })) const all = yield* capture(() => sdk.session.list({ roots: false, limit: 10 })) const children = yield* capture(() => sdk.session.children({ sessionID: parentID })) - const todo = yield* capture(() => sdk.session.todo({ sessionID: parentID })) const status = yield* capture(() => sdk.session.status()) const messages = yield* capture(() => sdk.session.messages({ sessionID: parentID })) const missingGet = yield* capture(() => sdk.session.get({ sessionID: "ses_missing" })) @@ -597,7 +596,6 @@ describe("HttpApi SDK", () => { roots, all, children, - todo, status, messages, missingGet, @@ -611,7 +609,6 @@ describe("HttpApi SDK", () => { rootTitles: sessionTitles(roots.data), allTitles: sessionTitles(all.data), childCount: array(children.data).length, - todoCount: array(todo.data).length, messageCount: array(messages.data).length, } }), diff --git a/packages/opencode/test/server/httpapi-session.test.ts b/packages/opencode/test/server/httpapi-session.test.ts index a5677d5274..4b3e7e3f92 100644 --- a/packages/opencode/test/server/httpapi-session.test.ts +++ b/packages/opencode/test/server/httpapi-session.test.ts @@ -272,10 +272,6 @@ describe("session HttpApi", () => { expect(children.status).toBe(404) expect(yield* responseJson(children)).toEqual(missingSessionBody) - const todo = yield* request(pathFor(SessionPaths.todo, { sessionID: missingSession }), { headers }) - expect(todo.status).toBe(404) - expect(yield* responseJson(todo)).toEqual(missingSessionBody) - const messages = yield* request(pathFor(SessionPaths.messages, { sessionID: missingSession }), { headers }) expect(messages.status).toBe(404) expect(yield* responseJson(messages)).toEqual(missingSessionBody) @@ -344,10 +340,6 @@ describe("session HttpApi", () => { })).map((item) => item.id), ).toEqual([child.id]) - expect( - yield* requestJson(pathFor(SessionPaths.todo, { sessionID: parent.id }), { headers }), - ).toEqual([]) - expect( yield* requestJson(pathFor(SessionPaths.diff, { sessionID: parent.id }), { headers }), ).toEqual([]) diff --git a/packages/opencode/test/session/prompt.test.ts b/packages/opencode/test/session/prompt.test.ts index 9ca8669e84..420bd49324 100644 --- a/packages/opencode/test/session/prompt.test.ts +++ b/packages/opencode/test/session/prompt.test.ts @@ -24,7 +24,6 @@ import { Git } from "../../src/git" import { Image } from "../../src/image/image" import { Question } from "../../src/question" -import { Todo } from "../../src/session/todo" import { Session } from "@/session/session" import { SessionMessageTable } from "@opencode-ai/core/session/sql" import { LLM } from "../../src/session/llm" @@ -191,7 +190,6 @@ const promptRoot = LayerNode.group([ Database.node, EventV2Bridge.node, Question.node, - Todo.node, ToolRegistry.node, Skill.node, Git.node, diff --git a/packages/opencode/test/session/schema-decoding.test.ts b/packages/opencode/test/session/schema-decoding.test.ts index 3bcbd55d4b..379494822a 100644 --- a/packages/opencode/test/session/schema-decoding.test.ts +++ b/packages/opencode/test/session/schema-decoding.test.ts @@ -6,7 +6,6 @@ import { SessionPrompt } from "../../src/session/prompt" import { SessionRevert } from "../../src/session/revert" import { SessionStatus } from "../../src/session/status" import { SessionSummary } from "../../src/session/summary" -import { Todo } from "../../src/session/todo" import { SessionID, MessageID, PartID } from "../../src/session/schema" import { ProjectV2 } from "@opencode-ai/core/project" import { WorkspaceV2 } from "@opencode-ai/core/workspace" @@ -252,15 +251,6 @@ describe("SessionStatus.Info", () => { }) }) -describe("Todo.Info", () => { - const decode = decodeUnknown(Todo.Info) - - test("three-field round-trip", () => { - const input = Todo.Info.make({ content: "do a thing", status: "pending", priority: "high" }) - expect(decode(input)).toEqual(input) - }) -}) - describe("SessionPrompt input schemas", () => { test("LoopInput is just sessionID", () => { const decode = decodeUnknown(SessionPrompt.LoopInput) diff --git a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap index 51ff867ea4..48c6b55585 100644 --- a/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap +++ b/packages/opencode/test/tool/__snapshots__/parameters.test.ts.snap @@ -335,44 +335,6 @@ exports[`tool parameters JSON Schema (wire shape) task 1`] = ` } `; -exports[`tool parameters JSON Schema (wire shape) todo 1`] = ` -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "todos": { - "description": "The updated todo list", - "items": { - "properties": { - "content": { - "description": "Brief description of the task", - "type": "string", - }, - "priority": { - "description": "Priority level of the task: high, medium, low", - "type": "string", - }, - "status": { - "description": "Current status of the task: pending, in_progress, completed, cancelled", - "type": "string", - }, - }, - "required": [ - "content", - "status", - "priority", - ], - "type": "object", - }, - "type": "array", - }, - }, - "required": [ - "todos", - ], - "type": "object", -} -`; - exports[`tool parameters JSON Schema (wire shape) webfetch 1`] = ` { "$schema": "https://json-schema.org/draft/2020-12/schema", diff --git a/packages/opencode/test/tool/parameters.test.ts b/packages/opencode/test/tool/parameters.test.ts index 9c540daad0..11db271b92 100644 --- a/packages/opencode/test/tool/parameters.test.ts +++ b/packages/opencode/test/tool/parameters.test.ts @@ -21,7 +21,6 @@ import { Parameters as Read } from "../../src/tool/read" import { Parameters as Shell } from "../../src/tool/shell" import { Parameters as Skill } from "../../src/tool/skill" import { Parameters as Task } from "../../src/tool/task" -import { Parameters as Todo } from "../../src/tool/todo" import { Parameters as WebFetch } from "../../src/tool/webfetch" import { Parameters as WebSearch } from "../../src/tool/websearch" import { Parameters as Write } from "../../src/tool/write" @@ -48,7 +47,6 @@ describe("tool parameters", () => { test("read", () => expect(toJsonSchema(Read)).toMatchSnapshot()) test("skill", () => expect(toJsonSchema(Skill)).toMatchSnapshot()) test("task", () => expect(toJsonSchema(Task)).toMatchSnapshot()) - test("todo", () => expect(toJsonSchema(Todo)).toMatchSnapshot()) test("webfetch", () => expect(toJsonSchema(WebFetch)).toMatchSnapshot()) test("websearch", () => expect(toJsonSchema(WebSearch)).toMatchSnapshot()) test("write", () => expect(toJsonSchema(Write)).toMatchSnapshot()) @@ -248,18 +246,6 @@ describe("tool parameters", () => { }) }) - describe("todo", () => { - test("accepts todos array", () => { - const parsed = parse(Todo, { - todos: [{ id: "t1", content: "do x", status: "pending", priority: "medium" }], - }) - expect(parsed.todos.length).toBe(1) - }) - test("rejects missing todos", () => { - expect(accepts(Todo, {})).toBe(false) - }) - }) - describe("webfetch", () => { test("defaults omitted format to markdown", () => { expect(parse(WebFetch, { url: "https://example.com" })).toEqual({ diff --git a/packages/opencode/test/tool/task.test.ts b/packages/opencode/test/tool/task.test.ts index 32171789c8..fc75c3d72f 100644 --- a/packages/opencode/test/tool/task.test.ts +++ b/packages/opencode/test/tool/task.test.ts @@ -388,7 +388,7 @@ describe("tool.task", () => { ) it.instance( - "execute shapes child permissions for task, todowrite, and primary tools", + "execute shapes child permissions for task and primary tools", () => Effect.gen(function* () { const sessions = yield* Session.Service @@ -420,11 +420,6 @@ describe("tool.task", () => { expect(child.parentID).toBe(chat.id) expect(child.agent).toBe("reviewer") expect(child.permission).toEqual([ - { - permission: "todowrite", - pattern: "*", - action: "deny", - }, { permission: "bash", pattern: "*", diff --git a/packages/plugin/src/tui.ts b/packages/plugin/src/tui.ts index 8e2fee5908..7c1d321edb 100644 --- a/packages/plugin/src/tui.ts +++ b/packages/plugin/src/tui.ts @@ -3,7 +3,6 @@ import type { V2Event, LspStatus, McpStatus, - Todo, Message, Part, Provider, @@ -380,7 +379,6 @@ export type TuiState = { count: () => number get: (sessionID: string) => Session | undefined diff: (sessionID: string) => ReadonlyArray - todo: (sessionID: string) => ReadonlyArray messages: (sessionID: string) => ReadonlyArray status: (sessionID: string) => SessionStatus | undefined permission: (sessionID: string) => ReadonlyArray @@ -437,8 +435,6 @@ export type TuiSidebarMcpItem = { export type TuiSidebarLspItem = Pick -export type TuiSidebarTodoItem = Pick - export type TuiSidebarFileItem = { file: string additions: number diff --git a/packages/schema/AGENTS.md b/packages/schema/AGENTS.md index 400b4b312b..f079b42a26 100644 --- a/packages/schema/AGENTS.md +++ b/packages/schema/AGENTS.md @@ -28,8 +28,8 @@ ## Module Shape -- Use one canonical exported value for each contract. Avoid bridge aliases such as `PluginID`, `PluginEvent`, `PtyInfo`, `PtyEvent`, and `SessionTodoInfo`. -- Prefer importing the schema module namespace and reading canonical members, for example `Plugin.ID` or `SessionTodo.Info`. +- Use one canonical exported value for each contract. Avoid bridge aliases such as `PluginID`, `PluginEvent`, `PtyInfo`, and `PtyEvent`. +- Prefer importing the schema module namespace and reading canonical members, for example `Plugin.ID` or `Question.Info`. - Core may compose Schema contracts with runtime behavior into a deliberate domain facade, but the facade must re-export the exact canonical Schema value. Do not create a second schema identity. - Use flat top-level exports plus the package's existing namespace projection pattern, for example `export * as SessionMessage from "./session-message"`. - Keep standalone ID modules only when they prevent real cycles or heavy dependency edges. Inline one-off IDs into their owning contract module when no cycle exists. diff --git a/packages/schema/src/event-manifest.ts b/packages/schema/src/event-manifest.ts index 035f72568e..386d750340 100644 --- a/packages/schema/src/event-manifest.ts +++ b/packages/schema/src/event-manifest.ts @@ -31,7 +31,6 @@ import { Skill } from "./skill.js" import { SessionCompactionEvent } from "./session-compaction-event.js" import { SessionEvent } from "./session-event.js" import { SessionStatusEvent } from "./session-status-event.js" -import { SessionTodo } from "./session-todo.js" import { SessionV1 } from "./session-v1.js" import { TuiEvent } from "./tui-event.js" import { VcsEvent } from "./vcs-event.js" @@ -73,7 +72,6 @@ const featureDefinitions = Event.inventory( export const ServerDefinitions = Event.inventory( ...foundationDefinitions, ...featureDefinitions, - ...SessionTodo.Event.Definitions, // Current events the TUI consumes from the public stream. ...SessionStatusEvent.Definitions, ...TuiEvent.Definitions, @@ -97,7 +95,6 @@ export const Definitions = Event.inventory( ...sessionV1LiveDefinitions, ...InstallationEvent.Definitions, ...featureDefinitions, - ...SessionTodo.Event.Definitions, ...LspEvent.Definitions, ...PermissionV1.Event.Definitions, ...TuiEvent.Definitions, diff --git a/packages/schema/src/session-todo.ts b/packages/schema/src/session-todo.ts deleted file mode 100644 index f4d68268ff..0000000000 --- a/packages/schema/src/session-todo.ts +++ /dev/null @@ -1,25 +0,0 @@ -export * as SessionTodo from "./session-todo.js" - -import { Schema } from "effect" -import { ephemeral, inventory } from "./event.js" -import { SessionID } from "./session-id.js" - -export const Info = Schema.Struct({ - content: Schema.String.annotate({ description: "Brief description of the task" }), - status: Schema.String.annotate({ - description: "Current status of the task: pending, in_progress, completed, cancelled", - }), - priority: Schema.String.annotate({ - description: "Priority level of the task: high, medium, low", - }), -}).annotate({ identifier: "Todo" }) -export interface Info extends Schema.Schema.Type {} - -const Updated = ephemeral({ - type: "todo.updated", - schema: { - sessionID: SessionID, - todos: Schema.Array(Info), - }, -}) -export const Event = { Updated, Definitions: inventory(Updated) } diff --git a/packages/schema/test/contract-hygiene.test.ts b/packages/schema/test/contract-hygiene.test.ts index 23f6521da5..140be20cba 100644 --- a/packages/schema/test/contract-hygiene.test.ts +++ b/packages/schema/test/contract-hygiene.test.ts @@ -16,7 +16,6 @@ import { Money } from "../src/money.js" import { Skill } from "../src/skill.js" import { Shell } from "../src/shell.js" import { PersistedRevert } from "../src/session-revert.js" -import { SessionTodo } from "../src/session-todo.js" import { optional } from "../src/schema.js" describe("contract hygiene", () => { @@ -61,15 +60,6 @@ describe("contract hygiene", () => { ).toThrow() }) - test("todo status and priority preserve arbitrary strings", () => { - const decode = Schema.decodeUnknownSync(SessionTodo.Info) - expect(decode({ content: "ship", status: "waiting", priority: "urgent" })).toEqual({ - content: "ship", - status: "waiting", - priority: "urgent", - }) - }) - test("current ID constructors expose create", () => { expect(Question.ID.create()).toStartWith("que_") expect(Pty.ID.create()).toStartWith("pty_") diff --git a/packages/schema/test/event-manifest.test.ts b/packages/schema/test/event-manifest.test.ts index 3c31d09c2b..80d179ae25 100644 --- a/packages/schema/test/event-manifest.test.ts +++ b/packages/schema/test/event-manifest.test.ts @@ -19,7 +19,6 @@ import { Plugin } from "../src/plugin.js" import { SessionEvent } from "../src/session-event.js" import { SessionID } from "../src/session-id.js" import { SessionMessage } from "../src/session-message.js" -import { SessionTodo } from "../src/session-todo.js" import { SessionV1 } from "../src/session-v1.js" import { WorkspaceEvent } from "../src/workspace-event.js" @@ -64,7 +63,6 @@ describe("public event manifest", () => { expect(Workspace.Event).toBe(WorkspaceEvent) expect(Workspace.Event.Definitions).toBe(WorkspaceEvent.Definitions) expect(EventManifest.Latest.get("session.step.ended")).toBe(SessionEvent.Step.Ended) - expect(EventManifest.Latest.get("todo.updated")).toBe(SessionTodo.Event.Updated) expect(EventManifest.Latest.get("agent.updated")).toBe(Agent.Event.Updated) expect(EventManifest.Latest.get("project.updated")).toBe(Project.Event.Updated) expect(Agent.Event.Definitions).toEqual([Agent.Event.Updated]) diff --git a/packages/sdk/js/src/gen/sdk.gen.ts b/packages/sdk/js/src/gen/sdk.gen.ts index 5e3e67e1c0..4b5d9284c6 100644 --- a/packages/sdk/js/src/gen/sdk.gen.ts +++ b/packages/sdk/js/src/gen/sdk.gen.ts @@ -62,9 +62,6 @@ import type { SessionChildrenData, SessionChildrenResponses, SessionChildrenErrors, - SessionTodoData, - SessionTodoResponses, - SessionTodoErrors, SessionInitData, SessionInitResponses, SessionInitErrors, @@ -507,16 +504,6 @@ class Session extends _HeyApiClient { }) } - /** - * Get the todo list for a session - */ - public todo(options: Options) { - return (options.client ?? this._client).get({ - url: "/session/{id}/todo", - ...options, - }) - } - /** * Analyze the app and create an AGENTS.md file */ diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts index 1055d82ce2..e9b704b468 100644 --- a/packages/sdk/js/src/gen/types.gen.ts +++ b/packages/sdk/js/src/gen/types.gen.ts @@ -493,33 +493,6 @@ export type EventFileEdited = { } } -export type Todo = { - /** - * Brief description of the task - */ - content: string - /** - * Current status of the task: pending, in_progress, completed, cancelled - */ - status: string - /** - * Priority level of the task: high, medium, low - */ - priority: string - /** - * Unique identifier for the todo item - */ - id: string -} - -export type EventTodoUpdated = { - type: "todo.updated" - properties: { - sessionID: string - todos: Array - } -} - export type EventCommandExecuted = { type: "command.executed" properties: { @@ -717,7 +690,6 @@ export type Event = | EventSessionIdle | EventSessionCompacted | EventFileEdited - | EventTodoUpdated | EventCommandExecuted | EventSessionCreated | EventSessionUpdated @@ -2272,42 +2244,6 @@ export type SessionChildrenResponses = { export type SessionChildrenResponse = SessionChildrenResponses[keyof SessionChildrenResponses] -export type SessionTodoData = { - body?: never - path: { - /** - * Session ID - */ - id: string - } - query?: { - directory?: string - } - url: "/session/{id}/todo" -} - -export type SessionTodoErrors = { - /** - * Bad request - */ - 400: BadRequestError - /** - * Not found - */ - 404: NotFoundError -} - -export type SessionTodoError = SessionTodoErrors[keyof SessionTodoErrors] - -export type SessionTodoResponses = { - /** - * Todo list - */ - 200: Array -} - -export type SessionTodoResponse = SessionTodoResponses[keyof SessionTodoResponses] - export type SessionInitData = { body?: { modelID: string diff --git a/packages/sdk/js/src/v2/gen/sdk.gen.ts b/packages/sdk/js/src/v2/gen/sdk.gen.ts index d26e05ef23..c1ecda15ea 100644 --- a/packages/sdk/js/src/v2/gen/sdk.gen.ts +++ b/packages/sdk/js/src/v2/gen/sdk.gen.ts @@ -219,8 +219,6 @@ import type { SessionStatusResponses, SessionSummarizeErrors, SessionSummarizeResponses, - SessionTodoErrors, - SessionTodoResponses, SessionUnrevertErrors, SessionUnrevertResponses, SessionUnshareErrors, @@ -3711,38 +3709,6 @@ export class Session2 extends HeyApiClient { }) } - /** - * Get session todos - * - * Retrieve the todo list associated with a specific session, showing tasks and action items. - */ - public todo( - parameters: { - sessionID: string - directory?: string - workspace?: string - }, - options?: Options, - ) { - const params = buildClientParams( - [parameters], - [ - { - args: [ - { in: "path", key: "sessionID" }, - { in: "query", key: "directory" }, - { in: "query", key: "workspace" }, - ], - }, - ], - ) - return (options?.client ?? this.client).get({ - url: "/session/{sessionID}/todo", - ...options, - ...params, - }) - } - /** * Get message diff * diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index efa4f18d35..92b9514db5 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -87,7 +87,6 @@ export type Event = | EventFormCreated | EventFormReplied | EventFormCancelled - | EventTodoUpdated | EventLspUpdated | EventPermissionAsked | EventPermissionReplied @@ -628,21 +627,6 @@ export type Pty = { exitCode?: number } -export type Todo = { - /** - * Brief description of the task - */ - content: string - /** - * Current status of the task: pending, in_progress, completed, cancelled - */ - status: string - /** - * Priority level of the task: high, medium, low - */ - priority: string -} - export type SessionStatus = | { type: "idle" @@ -1444,14 +1428,6 @@ export type GlobalEvent = { sessionID: string } } - | { - id: string - type: "todo.updated" - properties: { - sessionID: string - todos: Array - } - } | { id: string type: "lsp.updated" @@ -1782,7 +1758,6 @@ export type PermissionConfig = bash?: PermissionRuleConfig task?: PermissionRuleConfig external_directory?: PermissionRuleConfig - todowrite?: PermissionActionConfig question?: PermissionActionConfig webfetch?: PermissionActionConfig websearch?: PermissionActionConfig @@ -3109,7 +3084,6 @@ export type V2Event = | FormCreated | FormReplied | FormCancelled - | TodoUpdated | LspUpdated | PermissionAsked | PermissionReplied @@ -6620,20 +6594,6 @@ export type FormCancelled = { } } -export type TodoUpdated = { - id: string - created: number - metadata?: { - [key: string]: unknown - } - type: "todo.updated" - location?: LocationRef - data: { - sessionID: string - todos: Array - } -} - export type LspUpdated = { id: string created: number @@ -7894,15 +7854,6 @@ export type EventFormCancelled = { } } -export type EventTodoUpdated = { - id: string - type: "todo.updated" - properties: { - sessionID: string - todos: Array - } -} - export type EventLspUpdated = { id: string type: "lsp.updated" @@ -8730,7 +8681,6 @@ export type V2EventV2 = | FormCreatedV2 | FormRepliedV2 | FormCancelledV2 - | TodoUpdatedV2 | SessionStatusV22 | SessionIdleV2 | TuiPromptAppendV2 @@ -10741,20 +10691,6 @@ export type FormCancelledV2 = { } } -export type TodoUpdatedV2 = { - id: string - created: number - metadata?: { - [key: string]: unknown - } - type: "todo.updated" - location?: LocationRefV2 - data: { - sessionID: string - todos: Array - } -} - export type SessionIdleV2 = { id: string created: number @@ -13648,40 +13584,6 @@ export type SessionChildrenResponses = { export type SessionChildrenResponse = SessionChildrenResponses[keyof SessionChildrenResponses] -export type SessionTodoData = { - body?: never - path: { - sessionID: string - } - query?: { - directory?: string - workspace?: string - } - url: "/session/{sessionID}/todo" -} - -export type SessionTodoErrors = { - /** - * BadRequest | InvalidRequestError - */ - 400: EffectHttpApiErrorBadRequest | InvalidRequestError - /** - * NotFoundError - */ - 404: NotFoundError -} - -export type SessionTodoError = SessionTodoErrors[keyof SessionTodoErrors] - -export type SessionTodoResponses = { - /** - * Todo list - */ - 200: Array -} - -export type SessionTodoResponse = SessionTodoResponses[keyof SessionTodoResponses] - export type SessionDiffData = { body?: never path: { diff --git a/packages/sdk/openapi.json b/packages/sdk/openapi.json index a3886cc0c9..d5a273edea 100644 --- a/packages/sdk/openapi.json +++ b/packages/sdk/openapi.json @@ -5925,90 +5925,6 @@ ] } }, - "/session/{sessionID}/todo": { - "get": { - "tags": ["session"], - "operationId": "session.todo", - "parameters": [ - { - "name": "sessionID", - "in": "path", - "schema": { - "type": "string", - "pattern": "^ses" - }, - "required": true - }, - { - "name": "directory", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - }, - { - "name": "workspace", - "in": "query", - "schema": { - "type": "string" - }, - "required": false - } - ], - "responses": { - "200": { - "description": "Todo list", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - }, - "description": "Todo list" - } - } - } - }, - "400": { - "description": "BadRequest | InvalidRequestError", - "content": { - "application/json": { - "schema": { - "anyOf": [ - { - "$ref": "#/components/schemas/effect_HttpApiError_BadRequest" - }, - { - "$ref": "#/components/schemas/InvalidRequestError" - } - ] - } - } - } - }, - "404": { - "description": "NotFoundError", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/NotFoundError" - } - } - } - } - }, - "description": "Retrieve the todo list associated with a specific session, showing tasks and action items.", - "summary": "Get session todos", - "x-codeSamples": [ - { - "lang": "js", - "source": "import { createOpencodeClient } from \"@opencode-ai/sdk\n\nconst client = createOpencodeClient()\nawait client.session.todo({\n ...\n})" - } - ] - } - }, "/session/{sessionID}/diff": { "get": { "tags": ["session"], @@ -15445,9 +15361,6 @@ { "$ref": "#/components/schemas/EventQuestionV2Rejected" }, - { - "$ref": "#/components/schemas/EventTodoUpdated" - }, { "$ref": "#/components/schemas/EventLspUpdated" }, @@ -17244,25 +17157,6 @@ "required": ["id", "title", "command", "args", "cwd", "status", "pid"], "additionalProperties": false }, - "Todo": { - "type": "object", - "properties": { - "content": { - "type": "string", - "description": "Brief description of the task" - }, - "status": { - "type": "string", - "description": "Current status of the task: pending, in_progress, completed, cancelled" - }, - "priority": { - "type": "string", - "description": "Priority level of the task: high, medium, low" - } - }, - "required": ["content", "status", "priority"], - "additionalProperties": false - }, "SessionStatus": { "anyOf": [ { @@ -19611,38 +19505,6 @@ "required": ["id", "type", "properties"], "additionalProperties": false }, - { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^evt_" - }, - "type": { - "type": "string", - "enum": ["todo.updated"] - }, - "properties": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": ["sessionID", "todos"], - "additionalProperties": false - } - }, - "required": ["id", "type", "properties"], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -20612,9 +20474,6 @@ "external_directory": { "$ref": "#/components/schemas/PermissionRuleConfig" }, - "todowrite": { - "$ref": "#/components/schemas/PermissionActionConfig" - }, "question": { "$ref": "#/components/schemas/PermissionActionConfig" }, @@ -24164,9 +24023,6 @@ { "$ref": "#/components/schemas/QuestionV2Rejected" }, - { - "$ref": "#/components/schemas/TodoUpdated" - }, { "$ref": "#/components/schemas/LspUpdated" }, @@ -32461,60 +32317,6 @@ "required": ["id", "type", "data"], "additionalProperties": false }, - "TodoUpdated": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^evt_" - }, - "metadata": { - "type": "object" - }, - "type": { - "type": "string", - "enum": ["todo.updated"] - }, - "durable": { - "type": "object", - "properties": { - "aggregateID": { - "type": "string" - }, - "seq": { - "type": "integer" - }, - "version": { - "type": "integer" - } - }, - "required": ["aggregateID", "seq", "version"], - "additionalProperties": false - }, - "location": { - "$ref": "#/components/schemas/LocationRef" - }, - "data": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": ["sessionID", "todos"], - "additionalProperties": false - } - }, - "required": ["id", "type", "data"], - "additionalProperties": false - }, "LspUpdated": { "type": "object", "properties": { @@ -35990,38 +35792,6 @@ "required": ["id", "type", "properties"], "additionalProperties": false }, - "EventTodoUpdated": { - "type": "object", - "properties": { - "id": { - "type": "string", - "pattern": "^evt_" - }, - "type": { - "type": "string", - "enum": ["todo.updated"] - }, - "properties": { - "type": "object", - "properties": { - "sessionID": { - "type": "string", - "pattern": "^ses" - }, - "todos": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Todo" - } - } - }, - "required": ["sessionID", "todos"], - "additionalProperties": false - } - }, - "required": ["id", "type", "properties"], - "additionalProperties": false - }, "EventLspUpdated": { "type": "object", "properties": { diff --git a/packages/session-ui/src/components/message-part.css b/packages/session-ui/src/components/message-part.css index 88779a3c6c..b50f0902d0 100644 --- a/packages/session-ui/src/components/message-part.css +++ b/packages/session-ui/src/components/message-part.css @@ -590,27 +590,6 @@ } } -[data-component="todos"] { - padding: 10px 0 24px 0; - display: flex; - flex-direction: column; - gap: 8px; - - [data-component="checkbox"] { - --checkbox-align: flex-start; - --checkbox-offset: 0.5px; - } - - [data-slot="message-part-todo-content"] { - line-height: var(--line-height-normal); - - &[data-completed="completed"] { - text-decoration: line-through; - color: var(--v2-text-text-faint); - } - } -} - [data-component="context-tool-group-trigger"] { width: 100%; min-height: 24px; @@ -694,7 +673,6 @@ [data-component="bash-output"], [data-component="edit-content"], [data-component="write-content"], -[data-component="todos"], [data-component="diagnostics"], .error-card { -webkit-user-select: text; @@ -1389,10 +1367,6 @@ body:not([data-new-layout]) { color: var(--text-interactive-base); } - [data-slot="message-part-todo-content"][data-completed="completed"] { - color: var(--text-weaker); - } - [data-component="diagnostics"] { background-color: var(--surface-critical-weak); border-top: 1px solid var(--border-critical-base); diff --git a/packages/session-ui/src/components/message-part.tsx b/packages/session-ui/src/components/message-part.tsx index f147cd7388..f78ba5f30a 100644 --- a/packages/session-ui/src/components/message-part.tsx +++ b/packages/session-ui/src/components/message-part.tsx @@ -27,7 +27,6 @@ import { TextPart, ToolPart, UserMessage, - Todo, QuestionAnswer, QuestionInfo, } from "@opencode-ai/sdk/v2" @@ -42,7 +41,6 @@ import { Collapsible } from "@opencode-ai/ui/collapsible" import { FileIcon } from "@opencode-ai/ui/file-icon" import { Icon } from "@opencode-ai/ui/icon" import { ToolErrorCard } from "./tool-error-card" -import { Checkbox } from "@opencode-ai/ui/checkbox" import { DiffChanges } from "@opencode-ai/ui/diff-changes" import { Markdown } from "./markdown" import { ImagePreview } from "@opencode-ai/ui/image-preview" @@ -545,11 +543,6 @@ export function getToolInfo( ? `${input.files.length} ${i18n.t(input.files.length > 1 ? "ui.common.file.other" : "ui.common.file.one")}` : undefined, } - case "todowrite": - return { - icon: "checklist", - title: i18n.t("ui.tool.todos"), - } case "question": return { icon: "bubble-5", @@ -613,8 +606,6 @@ function taskSession( } const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"]) -const HIDDEN_TOOLS = new Set(["todowrite"]) - function list(value: T[] | undefined | null, fallback: T[]) { if (Array.isArray(value)) return value return fallback @@ -718,7 +709,6 @@ function index(items: readonly T[]) { export function renderable(part: PartType, showReasoningSummaries = true) { if (part.type === "tool") { - if (HIDDEN_TOOLS.has(part.tool)) return false if (part.tool === "question") return part.state.status !== "pending" && part.state.status !== "running" return true } @@ -1498,8 +1488,6 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) { const data = useData() const i18n = useI18n() const part = () => props.part as ToolPart - if (part().tool === "todowrite") return null - const hideQuestion = createMemo( () => part().tool === "question" && (part().state.status === "pending" || part().state.status === "running"), ) @@ -2476,57 +2464,6 @@ ToolRegistry.register({ }, }) -ToolRegistry.register({ - name: "todowrite", - render(props) { - const i18n = useI18n() - const todos = createMemo(() => { - const meta = props.metadata?.todos - if (Array.isArray(meta)) return meta - - const input = props.input.todos - if (Array.isArray(input)) return input - - return [] - }) - - const subtitle = createMemo(() => { - const list = todos() - if (list.length === 0) return "" - return `${list.filter((t: Todo) => t.status === "completed").length}/${list.length}` - }) - - return ( - - -
- - {(todo: Todo) => ( - - - {todo.content} - - - )} - -
-
-
- ) - }, -}) - ToolRegistry.register({ name: "question", render(props) { diff --git a/packages/session-ui/src/components/session-turn.tsx b/packages/session-ui/src/components/session-turn.tsx index 21884c42b1..a6d0f11efb 100644 --- a/packages/session-ui/src/components/session-turn.tsx +++ b/packages/session-ui/src/components/session-turn.tsx @@ -104,11 +104,8 @@ function summaryDiff(value: SummaryDiffInput): value is SummaryDiff { ) } -const hidden = new Set(["todowrite"]) - function partState(part: PartType, showReasoningSummaries: boolean) { if (part.type === "tool") { - if (hidden.has(part.tool)) return if (part.tool === "question" && (part.state.status === "pending" || part.state.status === "running")) return return "visible" as const } diff --git a/packages/session-ui/src/components/timeline-playground.stories.tsx b/packages/session-ui/src/components/timeline-playground.stories.tsx index 53699094ac..091e4f655e 100644 --- a/packages/session-ui/src/components/timeline-playground.stories.tsx +++ b/packages/session-ui/src/components/timeline-playground.stories.tsx @@ -399,25 +399,6 @@ const TOOL_SAMPLES = { title: "playwriter", metadata: {}, }, - todowrite: { - tool: "todowrite", - input: { - todos: [ - { content: "Create data generators", status: "completed", priority: "high" }, - { content: "Build UI controls", status: "in_progress", priority: "high" }, - { content: "Add CSS export", status: "pending", priority: "medium" }, - ], - }, - output: "", - title: "Todos", - metadata: { - todos: [ - { content: "Create data generators", status: "completed", priority: "high" }, - { content: "Build UI controls", status: "in_progress", priority: "high" }, - { content: "Add CSS export", status: "pending", priority: "medium" }, - ], - }, - }, } // --------------------------------------------------------------------------- diff --git a/packages/storybook/.storybook/mocks/app/context/file.ts b/packages/storybook/.storybook/mocks/app/context/file.ts index db2158a5cd..550d32f5b8 100644 --- a/packages/storybook/.storybook/mocks/app/context/file.ts +++ b/packages/storybook/.storybook/mocks/app/context/file.ts @@ -20,13 +20,7 @@ export function selectionFromLines(selection?: SelectedLineRange): FileSelection } } -const pool = [ - "src/session/timeline.tsx", - "src/session/composer.tsx", - "src/components/prompt-input.tsx", - "src/components/session-todo-dock.tsx", - "README.md", -] +const pool = ["src/session/timeline.tsx", "src/session/composer.tsx", "src/components/prompt-input.tsx", "README.md"] export function useFile() { return { diff --git a/packages/storybook/.storybook/mocks/app/context/global-sync.ts b/packages/storybook/.storybook/mocks/app/context/global-sync.ts index c538168bed..2d7b990ec7 100644 --- a/packages/storybook/.storybook/mocks/app/context/global-sync.ts +++ b/packages/storybook/.storybook/mocks/app/context/global-sync.ts @@ -18,7 +18,6 @@ const provider = { } const [store, setStore] = createStore({ - todo: {} as Record, provider, session: [] as any[], config: { permission: {} }, @@ -28,16 +27,10 @@ export function useServerSync() { return { data: { provider, - session_todo: store.todo, }, child() { return [store, setStore] as const }, - todo: { - set(sessionID: string, todos: any[]) { - setStore("todo", sessionID, todos) - }, - }, } } diff --git a/packages/storybook/.storybook/mocks/app/context/language.ts b/packages/storybook/.storybook/mocks/app/context/language.ts index df28d79fbd..731e3f931b 100644 --- a/packages/storybook/.storybook/mocks/app/context/language.ts +++ b/packages/storybook/.storybook/mocks/app/context/language.ts @@ -1,7 +1,4 @@ const dict: Record = { - "session.todo.title": "Todos", - "session.todo.collapse": "Collapse todos", - "session.todo.expand": "Expand todos", "prompt.loading": "Loading prompt...", "prompt.placeholder.normal": "Ask anything...", "prompt.placeholder.simple": "Ask anything...", diff --git a/packages/tui/src/component/todo-item.tsx b/packages/tui/src/component/todo-item.tsx deleted file mode 100644 index b54cc46334..0000000000 --- a/packages/tui/src/component/todo-item.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useTheme } from "../context/theme" - -export interface TodoItemProps { - status: string - content: string -} - -export function TodoItem(props: TodoItemProps) { - const { theme } = useTheme() - - return ( - - - [{props.status === "completed" ? "✓" : props.status === "in_progress" ? "•" : " "}]{" "} - - - {props.content} - - - ) -} diff --git a/packages/tui/src/context/sync.tsx b/packages/tui/src/context/sync.tsx index 40eac011ae..c35927d6f0 100644 --- a/packages/tui/src/context/sync.tsx +++ b/packages/tui/src/context/sync.tsx @@ -16,7 +16,6 @@ import type { QuestionRequest, Session, FileDiffInfo, - Todo, VcsInfo, } from "@opencode-ai/sdk/v2" import { createStore } from "solid-js/store" @@ -50,7 +49,6 @@ export const { config: Config session: Session[] session_diff: Record - todo: Record message: Record part: Record lsp: LspStatus[] @@ -76,7 +74,6 @@ export const { config: {}, session: [], session_diff: {}, - todo: {}, message: {}, part: {}, lsp: [], diff --git a/packages/tui/src/feature-plugins/builtins.ts b/packages/tui/src/feature-plugins/builtins.ts index 569f3db020..0069d56937 100644 --- a/packages/tui/src/feature-plugins/builtins.ts +++ b/packages/tui/src/feature-plugins/builtins.ts @@ -7,7 +7,6 @@ import SidebarFiles from "./sidebar/files" import SidebarFooter from "./sidebar/footer" import SidebarLsp from "./sidebar/lsp" import SidebarMcp from "./sidebar/mcp" -import SidebarTodo from "./sidebar/todo" import DiffViewer from "./system/diff-viewer" import Notifications from "./system/notifications" import PluginManager from "./system/plugins" @@ -27,7 +26,6 @@ export function createBuiltinPlugins(): BuiltinTuiPlugin[] { SidebarContext, SidebarMcp, SidebarLsp, - SidebarTodo, SidebarFiles, SidebarFooter, Notifications, diff --git a/packages/tui/src/feature-plugins/sidebar/todo.tsx b/packages/tui/src/feature-plugins/sidebar/todo.tsx deleted file mode 100644 index 15a78b0ebb..0000000000 --- a/packages/tui/src/feature-plugins/sidebar/todo.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import type { TuiPlugin, TuiPluginApi } from "@opencode-ai/plugin/tui" -import type { BuiltinTuiPlugin } from "../builtins" -import { createMemo, For, Show, createSignal } from "solid-js" -import { TodoItem } from "../../component/todo-item" - -const id = "internal:sidebar-todo" - -function View(props: { api: TuiPluginApi; session_id: string }) { - const [open, setOpen] = createSignal(true) - const theme = () => props.api.theme.current - const list = createMemo(() => props.api.state.session.todo(props.session_id)) - const show = createMemo(() => list().length > 0 && list().some((item) => item.status !== "completed")) - - return ( - - - list().length > 2 && setOpen((x) => !x)}> - 2}> - {open() ? "▼" : "▶"} - - - Todo - - - - {(item) => } - - - - ) -} - -const tui: TuiPlugin = async (api) => { - api.slots.register({ - order: 400, - slots: { - sidebar_content(_ctx, props) { - return - }, - }, - }) -} - -const plugin: BuiltinTuiPlugin = { - id, - tui, -} - -export default plugin diff --git a/packages/tui/src/plugin/adapters.tsx b/packages/tui/src/plugin/adapters.tsx index 068b51c732..7da68b8e86 100644 --- a/packages/tui/src/plugin/adapters.tsx +++ b/packages/tui/src/plugin/adapters.tsx @@ -130,9 +130,6 @@ function stateApi(sync: ReturnType, data: ReturnType
- - - @@ -2636,32 +2632,6 @@ function ApplyPatch(props: ToolProps) { ) } -function TodoWrite(props: ToolProps) { - const todos = createMemo(() => parseTodos(props.input.todos)) - return ( - - - - - {(todo) => } - - - - - - Updating todos... - - - - ) -} - function Question(props: ToolProps) { const { theme } = useTheme() const questions = createMemo(() => parseQuestions(props.input.questions)) @@ -2762,7 +2732,6 @@ const toolDisplays = new Set([ "subagent", "execute", "patch", - "todowrite", "question", "skill", ]) @@ -2844,16 +2813,6 @@ export function parseApplyPatchFiles(value: unknown) { }) } -export function parseTodos(value: unknown) { - if (!Array.isArray(value)) return [] - return value.flatMap((item) => { - const todo = recordValue(item) - const status = stringValue(todo?.status) - const content = stringValue(todo?.content) - return status && content ? [{ status, content }] : [] - }) -} - export function parseQuestions(value: unknown) { if (!Array.isArray(value)) return [] return value.flatMap((item) => { diff --git a/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx b/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx index c95e3834d2..8f07f81847 100644 --- a/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx +++ b/packages/tui/test/cli/tui/inline-tool-wrap-snapshot.test.tsx @@ -11,7 +11,6 @@ import { parseDiagnostics, parseQuestionAnswers, parseQuestions, - parseTodos, toolDisplay, } from "../../../src/routes/session" @@ -163,9 +162,6 @@ describe("TUI inline tool wrapping", () => { movePath: undefined, }, ]) - expect(parseTodos([null, { status: "pending" }, { status: "pending", content: "Safe" }])).toEqual([ - { status: "pending", content: "Safe" }, - ]) expect(parseQuestions([{}, { question: 1 }, { question: "Continue?" }])).toEqual([{ question: "Continue?" }]) expect(parseQuestionAnswers([null, ["yes", 1], "no"])).toEqual([[], ["yes"], []]) expect(parseQuestionAnswers({})).toBeUndefined() diff --git a/packages/ui/src/i18n/ar.ts b/packages/ui/src/i18n/ar.ts index 8e112e4d19..875de8c91c 100644 --- a/packages/ui/src/i18n/ar.ts +++ b/packages/ui/src/i18n/ar.ts @@ -130,8 +130,6 @@ export const dict = { "ui.tool.websearch": "بحث الويب", "ui.tool.shell": "Shell", "ui.tool.patch": "تصحيح", - "ui.tool.todos": "المهام", - "ui.tool.todos.read": "قراءة المهام", "ui.tool.questions": "أسئلة", "ui.tool.agent": "وكيل {{type}}", "ui.tool.agent.default": "وكيل", diff --git a/packages/ui/src/i18n/br.ts b/packages/ui/src/i18n/br.ts index 4661ece487..140b247626 100644 --- a/packages/ui/src/i18n/br.ts +++ b/packages/ui/src/i18n/br.ts @@ -130,8 +130,6 @@ export const dict = { "ui.tool.websearch": "Pesquisa na Web", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Tarefas", - "ui.tool.todos.read": "Ler tarefas", "ui.tool.questions": "Perguntas", "ui.tool.agent": "Agente {{type}}", "ui.tool.agent.default": "Agente", diff --git a/packages/ui/src/i18n/bs.ts b/packages/ui/src/i18n/bs.ts index eac44effd4..e59b68aa4a 100644 --- a/packages/ui/src/i18n/bs.ts +++ b/packages/ui/src/i18n/bs.ts @@ -134,8 +134,6 @@ export const dict = { "ui.tool.websearch": "Pretraga weba", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Lista zadataka", - "ui.tool.todos.read": "Čitanje liste zadataka", "ui.tool.questions": "Pitanja", "ui.tool.agent": "{{type}} agent", "ui.tool.agent.default": "agent", diff --git a/packages/ui/src/i18n/da.ts b/packages/ui/src/i18n/da.ts index 0057691b2c..92cff0007d 100644 --- a/packages/ui/src/i18n/da.ts +++ b/packages/ui/src/i18n/da.ts @@ -129,8 +129,6 @@ export const dict = { "ui.tool.websearch": "Websøgning", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Opgaver", - "ui.tool.todos.read": "Læs opgaver", "ui.tool.questions": "Spørgsmål", "ui.tool.agent": "{{type}} Agent", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/de.ts b/packages/ui/src/i18n/de.ts index 4926527428..a3835c3b46 100644 --- a/packages/ui/src/i18n/de.ts +++ b/packages/ui/src/i18n/de.ts @@ -136,8 +136,6 @@ export const dict = { "ui.tool.websearch": "Websuche", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Aufgaben", - "ui.tool.todos.read": "Aufgaben lesen", "ui.tool.questions": "Fragen", "ui.tool.agent": "{{type}} Agent", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts index f982766d13..aa2471d52b 100644 --- a/packages/ui/src/i18n/en.ts +++ b/packages/ui/src/i18n/en.ts @@ -138,8 +138,6 @@ export const dict: Record = { "ui.tool.websearch": "Web Search", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "To-dos", - "ui.tool.todos.read": "Read to-dos", "ui.tool.questions": "Questions", "ui.tool.agent": "{{type}} Agent", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index 59502b8421..53813885d7 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -130,8 +130,6 @@ export const dict = { "ui.tool.websearch": "Búsqueda web", "ui.tool.shell": "Shell", "ui.tool.patch": "Parche", - "ui.tool.todos": "Tareas", - "ui.tool.todos.read": "Leer tareas", "ui.tool.questions": "Preguntas", "ui.tool.agent": "Agente {{type}}", "ui.tool.agent.default": "Agente", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index ccf681cc84..4610b607f3 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -130,8 +130,6 @@ export const dict = { "ui.tool.websearch": "Recherche Web", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Tâches", - "ui.tool.todos.read": "Lire les tâches", "ui.tool.questions": "Questions", "ui.tool.agent": "Agent {{type}}", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index f22c0f6d5f..f25521155c 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -129,8 +129,6 @@ export const dict = { "ui.tool.websearch": "Web検索", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Todo", - "ui.tool.todos.read": "Todo読み込み", "ui.tool.questions": "質問", "ui.tool.agent": "{{type}}エージェント", "ui.tool.agent.default": "エージェント", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index f358810fd2..0391842e3b 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -106,8 +106,6 @@ export const dict = { "ui.tool.websearch": "웹 검색", "ui.tool.shell": "셸", "ui.tool.patch": "패치", - "ui.tool.todos": "할 일", - "ui.tool.todos.read": "할 일 읽기", "ui.tool.questions": "질문", "ui.tool.agent": "{{type}} 에이전트", "ui.tool.agent.default": "에이전트", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index 0ee729adcb..21ed01ad7a 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -109,8 +109,6 @@ export const dict: Record = { "ui.tool.websearch": "Nettsøk", "ui.tool.shell": "Shell", "ui.tool.patch": "Patch", - "ui.tool.todos": "Gjøremål", - "ui.tool.todos.read": "Les gjøremål", "ui.tool.questions": "Spørsmål", "ui.tool.agent": "{{type}}-agent", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index 4dbbe03add..7350210a1e 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -129,8 +129,6 @@ export const dict = { "ui.tool.websearch": "Wyszukiwanie w sieci", "ui.tool.shell": "Terminal", "ui.tool.patch": "Patch", - "ui.tool.todos": "Zadania", - "ui.tool.todos.read": "Czytaj zadania", "ui.tool.questions": "Pytania", "ui.tool.agent": "Agent {{type}}", "ui.tool.agent.default": "Agent", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 80694cdbe0..481d6202c7 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -129,8 +129,6 @@ export const dict = { "ui.tool.websearch": "Веб-поиск", "ui.tool.shell": "Оболочка", "ui.tool.patch": "Патч", - "ui.tool.todos": "Задачи", - "ui.tool.todos.read": "Читать задачи", "ui.tool.questions": "Вопросы", "ui.tool.agent": "Агент {{type}}", "ui.tool.agent.default": "Агент", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index 10675a28d4..c80e7461ed 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -131,8 +131,6 @@ export const dict = { "ui.tool.websearch": "ค้นหาเว็บ", "ui.tool.shell": "เชลล์", "ui.tool.patch": "แพตช์", - "ui.tool.todos": "รายการงาน", - "ui.tool.todos.read": "อ่านรายการงาน", "ui.tool.questions": "คำถาม", "ui.tool.agent": "เอเจนต์ {{type}}", "ui.tool.agent.default": "เอเจนต์", diff --git a/packages/ui/src/i18n/tr.ts b/packages/ui/src/i18n/tr.ts index 5cdebfd6f4..e795a03d70 100644 --- a/packages/ui/src/i18n/tr.ts +++ b/packages/ui/src/i18n/tr.ts @@ -136,8 +136,6 @@ export const dict = { "ui.tool.websearch": "Web Araması", "ui.tool.shell": "Kabuk", "ui.tool.patch": "Yama", - "ui.tool.todos": "Görevler", - "ui.tool.todos.read": "Görevleri oku", "ui.tool.questions": "Sorular", "ui.tool.agent": "{{type}} Ajan", "ui.tool.agent.default": "Ajan", diff --git a/packages/ui/src/i18n/uk.ts b/packages/ui/src/i18n/uk.ts index abb35c79f5..80558833fd 100644 --- a/packages/ui/src/i18n/uk.ts +++ b/packages/ui/src/i18n/uk.ts @@ -138,8 +138,6 @@ export const dict: Record = { "ui.tool.websearch": "Веб-пошук", "ui.tool.shell": "Оболонка", "ui.tool.patch": "Патч", - "ui.tool.todos": "Завдання", - "ui.tool.todos.read": "Читати завдання", "ui.tool.questions": "Питання", "ui.tool.agent": "Агент {{type}}", "ui.tool.agent.default": "Агент", diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index 8a9e18aeea..7462eceee3 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -133,8 +133,6 @@ export const dict = { "ui.tool.websearch": "网络搜索", "ui.tool.shell": "Shell", "ui.tool.patch": "补丁", - "ui.tool.todos": "待办", - "ui.tool.todos.read": "读取待办", "ui.tool.questions": "问题", "ui.tool.agent": "{{type}} 智能体", "ui.tool.agent.default": "智能体", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index 19ba8e4106..7b8cc1b6e4 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -133,8 +133,6 @@ export const dict = { "ui.tool.websearch": "網頁搜尋", "ui.tool.shell": "Shell", "ui.tool.patch": "修補", - "ui.tool.todos": "待辦", - "ui.tool.todos.read": "讀取待辦", "ui.tool.questions": "問題", "ui.tool.agent": "{{type}} 代理程式", "ui.tool.agent.default": "代理程式", diff --git a/packages/web/src/components/share.module.css b/packages/web/src/components/share.module.css index 9930e6b57c..1af9b53892 100644 --- a/packages/web/src/components/share.module.css +++ b/packages/web/src/components/share.module.css @@ -719,88 +719,6 @@ } } -.todos { - list-style-type: none; - padding: 0; - margin: 0; - width: 100%; - max-width: var(--sm-tool-width); - border: 1px solid var(--sl-color-divider); - border-radius: 0.25rem; - - li { - margin: 0; - position: relative; - padding-left: 1.5rem; - font-size: 0.75rem; - padding: 0.375rem 0.625rem 0.375rem 1.75rem; - border-bottom: 1px solid var(--sl-color-divider); - line-height: 1.5; - word-break: break-word; - - &:last-child { - border-bottom: none; - } - - & > span { - position: absolute; - display: inline-block; - left: 0.5rem; - top: calc(0.5rem + 1px); - width: 0.75rem; - height: 0.75rem; - border: 1px solid var(--sl-color-divider); - border-radius: 0.15rem; - - &::before { - } - } - - &[data-status="pending"] { - color: var(--sl-color-text); - } - - &[data-status="in_progress"] { - color: var(--sl-color-text); - - & > span { - border-color: var(--sl-color-orange); - } - - & > span::before { - content: ""; - position: absolute; - top: 2px; - left: 2px; - width: calc(0.75rem - 2px - 4px); - height: calc(0.75rem - 2px - 4px); - box-shadow: inset 1rem 1rem var(--sl-color-orange-low); - } - } - - &[data-status="completed"] { - color: var(--sl-color-text-secondary); - - & > span { - border-color: var(--sl-color-green-low); - } - - & > span::before { - content: ""; - position: absolute; - top: 2px; - left: 2px; - width: calc(0.75rem - 2px - 4px); - height: calc(0.75rem - 2px - 4px); - box-shadow: inset 1rem 1rem var(--sl-color-green); - - transform-origin: bottom left; - clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); - } - } - } -} - .scroll-button { position: fixed; bottom: 2rem; diff --git a/packages/web/src/components/share/part.module.css b/packages/web/src/components/share/part.module.css index b1269445f6..2cbb20c2d3 100644 --- a/packages/web/src/components/share/part.module.css +++ b/packages/web/src/components/share/part.module.css @@ -317,88 +317,6 @@ gap: 0.5rem; } - [data-component="todos"] { - list-style-type: none; - padding: 0; - margin: 0; - width: 100%; - max-width: var(--sm-tool-width); - border: 1px solid var(--sl-color-divider); - border-radius: 0.25rem; - - [data-slot="item"] { - margin: 0; - position: relative; - padding-left: 1.5rem; - font-size: 0.75rem; - padding: 0.375rem 0.625rem 0.375rem 1.75rem; - border-bottom: 1px solid var(--sl-color-divider); - line-height: 1.5; - word-break: break-word; - - &:last-child { - border-bottom: none; - } - - & > span { - position: absolute; - display: inline-block; - left: 0.5rem; - top: calc(0.5rem + 1px); - width: 0.75rem; - height: 0.75rem; - border: 1px solid var(--sl-color-divider); - border-radius: 0.15rem; - - &::before { - } - } - - &[data-status="pending"] { - color: var(--sl-color-text); - } - - &[data-status="in_progress"] { - color: var(--sl-color-text); - - & > span { - border-color: var(--sl-color-orange); - } - - & > span::before { - content: ""; - position: absolute; - top: 2px; - left: 2px; - width: calc(0.75rem - 2px - 4px); - height: calc(0.75rem - 2px - 4px); - box-shadow: inset 1rem 1rem var(--sl-color-orange-low); - } - } - - &[data-status="completed"] { - color: var(--sl-color-text-secondary); - - & > span { - border-color: var(--sl-color-green-low); - } - - & > span::before { - content: ""; - position: absolute; - top: 2px; - left: 2px; - width: calc(0.75rem - 2px - 4px); - height: calc(0.75rem - 2px - 4px); - box-shadow: inset 1rem 1rem var(--sl-color-green); - - transform-origin: bottom left; - clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); - } - } - } - } - [data-component="tool-args"] { display: inline-grid; align-items: center; diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx index 67099196a0..b314afc0d6 100644 --- a/packages/web/src/components/share/part.tsx +++ b/packages/web/src/components/share/part.tsx @@ -7,7 +7,6 @@ import { IconGlobeAlt, IconDocument, IconPaperClip, - IconQueueList, IconUserCircle, IconCommandLine, IconCheckCircle, @@ -87,9 +86,6 @@ export function Part(props: PartProps) { - - - @@ -248,14 +244,6 @@ export function Part(props: PartProps) { message={props.message} /> - - - = { - in_progress: 0, - pending: 1, - completed: 2, - } - const todos = createMemo(() => - ((props.state.input?.todos ?? []) as Todo[]).slice().sort((a, b) => priority[a.status] - priority[b.status]), - ) - const starting = () => todos().every((t: Todo) => t.status === "pending") - const finished = () => todos().every((t: Todo) => t.status === "completed") - - return ( - <> -
- - - {messages.creating_plan} - {messages.completing_plan} - - -
- 0}> -
    - - {(todo) => ( -
  • - - {todo.content} -
  • - )} -
    -
-
- - ) -} - export function GrepTool(props: ToolProps) { const messages = useShareMessages() diff --git a/packages/web/src/content/docs/agents.mdx b/packages/web/src/content/docs/agents.mdx index 53048b7927..0c0a5e2284 100644 --- a/packages/web/src/content/docs/agents.mdx +++ b/packages/web/src/content/docs/agents.mdx @@ -72,7 +72,7 @@ This agent is useful when you want the LLM to analyze code, suggest changes, or _Mode_: `subagent` -A general-purpose agent for researching complex questions and executing multi-step tasks. Has full tool access (except todo), so it can make file changes when needed. Use this to run multiple units of work in parallel. +A general-purpose agent for researching complex questions and executing multi-step tasks. Has full tool access, so it can make file changes when needed. Use this to run multiple units of work in parallel. --- @@ -439,7 +439,6 @@ The available permission keys are: | `bash` | `bash` | | `task` | `task` | | `external_directory` | Any tool that reads or writes files outside the project worktree | -| `todowrite` | `todowrite`, `todoread` | | `webfetch` | `webfetch` | | `websearch` | `websearch` | | `lsp` | `lsp` | diff --git a/packages/web/src/content/docs/ar/agents.mdx b/packages/web/src/content/docs/ar/agents.mdx index af12a67691..4dde97d7d7 100644 --- a/packages/web/src/content/docs/ar/agents.mdx +++ b/packages/web/src/content/docs/ar/agents.mdx @@ -71,7 +71,7 @@ _الوضع_: `primary` _الوضع_: `subagent` -وكيل عام الغرض للبحث في أسئلة معقدة وتنفيذ مهام متعددة الخطوات. لديه وصول كامل للأدوات (باستثناء todo)، لذا يمكنه إجراء تغييرات على الملفات عند الحاجة. استخدمه لتشغيل عدة وحدات عمل بالتوازي. +وكيل عام الغرض للبحث في أسئلة معقدة وتنفيذ مهام متعددة الخطوات. لديه وصول كامل للأدوات، لذا يمكنه إجراء تغييرات على الملفات عند الحاجة. استخدمه لتشغيل عدة وحدات عمل بالتوازي. --- diff --git a/packages/web/src/content/docs/ar/plugins.mdx b/packages/web/src/content/docs/ar/plugins.mdx index d7c025bbc3..031171db8d 100644 --- a/packages/web/src/content/docs/ar/plugins.mdx +++ b/packages/web/src/content/docs/ar/plugins.mdx @@ -188,10 +188,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### أحداث Todo - -- `todo.updated` - #### أحداث shell - `shell.env` diff --git a/packages/web/src/content/docs/ar/server.mdx b/packages/web/src/content/docs/ar/server.mdx index 017a81eafa..8b679909b7 100644 --- a/packages/web/src/content/docs/ar/server.mdx +++ b/packages/web/src/content/docs/ar/server.mdx @@ -145,26 +145,25 @@ http://:/doc ### الجلسات -| الطريقة | المسار | الوصف | الملاحظات | -| -------- | ---------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------------- | -| `GET` | `/session` | سرد جميع الجلسات | يعيد Session[] | -| `POST` | `/session` | إنشاء جلسة جديدة | المتن: `{ parentID?, title? }`، يعيد Session | -| `GET` | `/session/status` | الحصول على حالة الجلسات جميعها | يعيد `{ [sessionID: string]: `SessionStatus` }` | -| `GET` | `/session/:id` | الحصول على تفاصيل الجلسة | يعيد Session | -| `DELETE` | `/session/:id` | حذف جلسة وجميع بياناتها | يعيد `boolean` | -| `PATCH` | `/session/:id` | تحديث خصائص الجلسة | المتن: `{ title? }`، يعيد Session | -| `GET` | `/session/:id/children` | الحصول على الجلسات الفرعية لجلسة | يعيد Session[] | -| `GET` | `/session/:id/todo` | الحصول على قائمة المهام (todo) للجلسة | يعيد Todo[] | -| `POST` | `/session/:id/init` | تحليل التطبيق وإنشاء `AGENTS.md` | المتن: `{ messageID, providerID, modelID }`، يعيد `boolean` | -| `POST` | `/session/:id/fork` | تفريع جلسة موجودة عند رسالة | المتن: `{ messageID? }`، يعيد Session | -| `POST` | `/session/:id/abort` | إلغاء جلسة قيد التشغيل | يعيد `boolean` | -| `POST` | `/session/:id/share` | مشاركة جلسة | يعيد Session | -| `DELETE` | `/session/:id/share` | إلغاء مشاركة جلسة | يعيد Session | -| `GET` | `/session/:id/diff` | الحصول على diff لهذه الجلسة | الاستعلام: `messageID?`، يعيد FileDiff[] | -| `POST` | `/session/:id/summarize` | تلخيص الجلسة | المتن: `{ providerID, modelID }`، يعيد `boolean` | -| `POST` | `/session/:id/revert` | التراجع عن رسالة | المتن: `{ messageID, partID? }`، يعيد `boolean` | -| `POST` | `/session/:id/unrevert` | استعادة جميع الرسائل المتراجع عنها | يعيد `boolean` | -| `POST` | `/session/:id/permissions/:permissionID` | الرد على طلب إذن | المتن: `{ response, remember? }`، يعيد `boolean` | +| الطريقة | المسار | الوصف | الملاحظات | +| -------- | ---------------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------- | +| `GET` | `/session` | سرد جميع الجلسات | يعيد Session[] | +| `POST` | `/session` | إنشاء جلسة جديدة | المتن: `{ parentID?, title? }`، يعيد Session | +| `GET` | `/session/status` | الحصول على حالة الجلسات جميعها | يعيد `{ [sessionID: string]: `SessionStatus` }` | +| `GET` | `/session/:id` | الحصول على تفاصيل الجلسة | يعيد Session | +| `DELETE` | `/session/:id` | حذف جلسة وجميع بياناتها | يعيد `boolean` | +| `PATCH` | `/session/:id` | تحديث خصائص الجلسة | المتن: `{ title? }`، يعيد Session | +| `GET` | `/session/:id/children` | الحصول على الجلسات الفرعية لجلسة | يعيد Session[] | +| `POST` | `/session/:id/init` | تحليل التطبيق وإنشاء `AGENTS.md` | المتن: `{ messageID, providerID, modelID }`، يعيد `boolean` | +| `POST` | `/session/:id/fork` | تفريع جلسة موجودة عند رسالة | المتن: `{ messageID? }`، يعيد Session | +| `POST` | `/session/:id/abort` | إلغاء جلسة قيد التشغيل | يعيد `boolean` | +| `POST` | `/session/:id/share` | مشاركة جلسة | يعيد Session | +| `DELETE` | `/session/:id/share` | إلغاء مشاركة جلسة | يعيد Session | +| `GET` | `/session/:id/diff` | الحصول على diff لهذه الجلسة | الاستعلام: `messageID?`، يعيد FileDiff[] | +| `POST` | `/session/:id/summarize` | تلخيص الجلسة | المتن: `{ providerID, modelID }`، يعيد `boolean` | +| `POST` | `/session/:id/revert` | التراجع عن رسالة | المتن: `{ messageID, partID? }`، يعيد `boolean` | +| `POST` | `/session/:id/unrevert` | استعادة جميع الرسائل المتراجع عنها | يعيد `boolean` | +| `POST` | `/session/:id/permissions/:permissionID` | الرد على طلب إذن | المتن: `{ response, remember? }`، يعيد `boolean` | --- diff --git a/packages/web/src/content/docs/ar/tools.mdx b/packages/web/src/content/docs/ar/tools.mdx index 0323e8d8ec..687854388e 100644 --- a/packages/web/src/content/docs/ar/tools.mdx +++ b/packages/web/src/content/docs/ar/tools.mdx @@ -210,27 +210,6 @@ description: إدارة الأدوات التي يمكن لـ LLM استخدام --- -### todowrite - -أدِر قوائم المهام أثناء جلسات البرمجة. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -تنشئ هذه الأداة قوائم المهام وتحدّثها لتتبع التقدم أثناء العمليات المعقدة. يستخدمها LLM لتنظيم المهام متعددة الخطوات. - -:::note -هذه الأداة معطلة للوكلاء الفرعيين افتراضيا، لكن يمكنك تفعيلها يدويا. [اعرف المزيد](/docs/agents/#permissions) -::: - ---- - ### webfetch اجلب محتوى الويب. diff --git a/packages/web/src/content/docs/bs/agents.mdx b/packages/web/src/content/docs/bs/agents.mdx index a2e211b19a..87af54e497 100644 --- a/packages/web/src/content/docs/bs/agents.mdx +++ b/packages/web/src/content/docs/bs/agents.mdx @@ -71,7 +71,7 @@ Ovaj agent je koristan kada želite da LLM analizira kod, predloži promjene ili _Režim_: `subagent` -Agent opće namjene za istraživanje složenih pitanja i izvršavanje zadataka u više koraka. Ima potpuni pristup alatima (osim todo), tako da može mijenjati fajlove kada je to potrebno. Koristite ovo za paralelno pokretanje više jedinica rada. +Agent opće namjene za istraživanje složenih pitanja i izvršavanje zadataka u više koraka. Ima potpuni pristup alatima, tako da može mijenjati fajlove kada je to potrebno. Koristite ovo za paralelno pokretanje više jedinica rada. --- diff --git a/packages/web/src/content/docs/bs/plugins.mdx b/packages/web/src/content/docs/bs/plugins.mdx index 7e046cb83d..c7d709da31 100644 --- a/packages/web/src/content/docs/bs/plugins.mdx +++ b/packages/web/src/content/docs/bs/plugins.mdx @@ -181,10 +181,6 @@ Dodaci se mogu pretplatiti na događaje kao što je prikazano ispod u odjeljku P - `session.status` - `session.updated` -#### Todo događaji - -- `todo.updated` - #### Shell događaji - `shell.env` diff --git a/packages/web/src/content/docs/bs/server.mdx b/packages/web/src/content/docs/bs/server.mdx index 5237873d5f..54ba859c39 100644 --- a/packages/web/src/content/docs/bs/server.mdx +++ b/packages/web/src/content/docs/bs/server.mdx @@ -151,7 +151,6 @@ opencode server izlaže sljedece API-je. | `DELETE` | `/session/:id` | Obriši sesiju i sve njene podatke | Returns `boolean` | | `PATCH` | `/session/:id` | Ažuriraj svojstva sesije | body: `{ title? }`, returns Session | | `GET` | `/session/:id/children` | Dohvati pod-sesije sesije | Returns Session[] | -| `GET` | `/session/:id/todo` | Dohvati listu zadataka za sesiju | Returns Todo[] | | `POST` | `/session/:id/init` | Analiziraj aplikaciju i kreiraj `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | | `POST` | `/session/:id/fork` | Granaj postojeću sesiju na poruci | body: `{ messageID? }`, returns Session | | `POST` | `/session/:id/abort` | Prekini sesiju u toku | Returns `boolean` | diff --git a/packages/web/src/content/docs/bs/tools.mdx b/packages/web/src/content/docs/bs/tools.mdx index c2d5aa2dd2..555343bf22 100644 --- a/packages/web/src/content/docs/bs/tools.mdx +++ b/packages/web/src/content/docs/bs/tools.mdx @@ -210,27 +210,6 @@ Ucitajte [skill](/docs/skills) (`SKILL.md` datoteku) i vratite njegov sadrzaj u --- -### todowrite - -Upravlja todo listama tokom coding sesija. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Kreira i azurira liste zadataka za pracenje napretka tokom slozenih operacija. LLM ovo koristi za organizaciju zadataka u vise koraka. - -:::note -Ovaj alat je po defaultu iskljucen za subagente, ali ga mozete rucno ukljuciti. [Saznajte vise](/docs/agents/#permissions) -::: - ---- - ### webfetch Preuzima web sadrzaj. diff --git a/packages/web/src/content/docs/cli.mdx b/packages/web/src/content/docs/cli.mdx index 7484521364..7c3b1e3d76 100644 --- a/packages/web/src/content/docs/cli.mdx +++ b/packages/web/src/content/docs/cli.mdx @@ -74,13 +74,13 @@ This command will guide you through creating a new agent with a custom system pr #### Flags -| Flag | Short | Description | -| ------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| {"--path"} | | Directory to write the agent file to (defaults to global or `.opencode/agent` based on the prompt) | -| {"--description"} | | What the agent should do | -| {"--mode"} | | Agent mode: `all`, `primary`, or `subagent` | -| {"--permissions"} | | Comma-separated list of permissions to allow (default: all). Available: `bash`, `read`, `edit`, `glob`, `grep`, `webfetch`, `task`, `todowrite`, `websearch`, `lsp`, `skill`. Anything omitted is denied. Alias: `--tools` | -| {"--model"} | `-m` | Model to use, in `provider/model` format | +| Flag | Short | Description | +| ------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| {"--path"} | | Directory to write the agent file to (defaults to global or `.opencode/agent` based on the prompt) | +| {"--description"} | | What the agent should do | +| {"--mode"} | | Agent mode: `all`, `primary`, or `subagent` | +| {"--permissions"} | | Comma-separated list of permissions to allow (default: all). Available: `bash`, `read`, `edit`, `glob`, `grep`, `webfetch`, `task`, `websearch`, `lsp`, `skill`. Anything omitted is denied. Alias: `--tools` | +| {"--model"} | `-m` | Model to use, in `provider/model` format | Passing all of `--path`, `--description`, `--mode`, and `--permissions` runs the command non-interactively. diff --git a/packages/web/src/content/docs/da/agents.mdx b/packages/web/src/content/docs/da/agents.mdx index 058f9eec6e..7e773c681e 100644 --- a/packages/web/src/content/docs/da/agents.mdx +++ b/packages/web/src/content/docs/da/agents.mdx @@ -72,7 +72,7 @@ Denne agent er nyttig, når du vil have LLM til at analysere kode, foreslå ænd _Tilstand_: `subagent` -En agent til generelt formål at undersøge komplekse spørgsmål og udføre opgaver i flere trin. Har fuld værktøjsadgang (undtagen todo), så den kan foretage filændringer, når det er nødvendigt. Brug dette til at køre flere arbejdsenheder parallelt. +En agent til generelt formål at undersøge komplekse spørgsmål og udføre opgaver i flere trin. Har fuld værktøjsadgang, så den kan foretage filændringer, når det er nødvendigt. Brug dette til at køre flere arbejdsenheder parallelt. --- diff --git a/packages/web/src/content/docs/da/plugins.mdx b/packages/web/src/content/docs/da/plugins.mdx index 908c6e1111..2b78dd113f 100644 --- a/packages/web/src/content/docs/da/plugins.mdx +++ b/packages/web/src/content/docs/da/plugins.mdx @@ -188,10 +188,6 @@ Plugins kan abonnere på begivenheder som vist nedenfor i afsnittet Eksempler. H - `session.status` - `session.updated` -#### Todo-hændelser - -- `todo.updated` - #### Shell-hændelser - `shell.env` diff --git a/packages/web/src/content/docs/da/server.mdx b/packages/web/src/content/docs/da/server.mdx index 6eb74d946d..51060112f3 100644 --- a/packages/web/src/content/docs/da/server.mdx +++ b/packages/web/src/content/docs/da/server.mdx @@ -154,7 +154,6 @@ OpenCode-serveren viser følgende API'er. | `DELETE` | `/session/:id` | Slet en session og alle dens data | Returnerer `boolean` | | `PATCH` | `/session/:id` | Opdater sessionegenskaber | body: `{ title? }`, returnerer Session | | `GET` | `/session/:id/children` | Få en sessions undersessioner | Returnerer Session[] | -| `GET` | `/session/:id/todo` | Få to-do-listen for en session | Returnerer Todo[] | | `POST` | `/session/:id/init` | Analyser appen og lav `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returnerer `boolean` | | `POST` | `/session/:id/fork` | Fork en eksisterende session ved en besked | body: `{ messageID? }`, returnerer Session | | `POST` | `/session/:id/abort` | Afbryd en kørende session | Returnerer `boolean` | diff --git a/packages/web/src/content/docs/da/tools.mdx b/packages/web/src/content/docs/da/tools.mdx index 31c980082e..d6d1b5d9f1 100644 --- a/packages/web/src/content/docs/da/tools.mdx +++ b/packages/web/src/content/docs/da/tools.mdx @@ -210,27 +210,6 @@ Last inn en [ferdighet](/docs/skills) (en `SKILL.md` fil) og returner innholdet --- -### todowrite - -Administrer to-doslister under kodingssessioner. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Opreter og opdaterer oppgavelister for at spore fremdrift under komplekse operasjoner. LLM bruger dette til at organisere flertrinnsoppgaver. - -:::note -Dette verktøyet er deaktivert for subagenter som standard, men du kan aktivere det manuelt. [Finn ut mer](/docs/agents/#permissions) -::: - ---- - ### webfetch Hent nettinnhold. diff --git a/packages/web/src/content/docs/de/agents.mdx b/packages/web/src/content/docs/de/agents.mdx index 6bca53488d..ee715bb889 100644 --- a/packages/web/src/content/docs/de/agents.mdx +++ b/packages/web/src/content/docs/de/agents.mdx @@ -58,7 +58,7 @@ Dieser Agent ist nützlich, wenn Sie möchten, dass LLM Code analysiert, Änderu _Modus_: `subagent` -Ein Allzweckagent zur Recherche komplexerer Fragen und zur Ausführung mehrstufiger Aufgaben. Verfügt über vollständigen Zugriff auf das Tool (außer Todo), sodass bei Bedarf Dateiänderungen vorgenommen werden können. Verwenden Sie Matrizen, um mehrere Arbeitseinheiten parallel auszuführen. +Ein Allzweckagent zur Recherche komplexerer Fragen und zur Ausführung mehrstufiger Aufgaben. Verfügt über vollständigen Zugriff auf das Tool, sodass bei Bedarf Dateiänderungen vorgenommen werden können. Verwenden Sie Matrizen, um mehrere Arbeitseinheiten parallel auszuführen. --- diff --git a/packages/web/src/content/docs/de/plugins.mdx b/packages/web/src/content/docs/de/plugins.mdx index 57fcdbba6e..6b83f116fe 100644 --- a/packages/web/src/content/docs/de/plugins.mdx +++ b/packages/web/src/content/docs/de/plugins.mdx @@ -187,10 +187,6 @@ Plugins können Ereignisse abonnieren, wie unten im Abschnitt „Beispiele“ ge - `session.status` - `session.updated` -#### Todo-Ereignisse - -- `todo.updated` - #### Shell-Ereignisse - `shell.env` diff --git a/packages/web/src/content/docs/de/server.mdx b/packages/web/src/content/docs/de/server.mdx index 64322bda85..8a86043903 100644 --- a/packages/web/src/content/docs/de/server.mdx +++ b/packages/web/src/content/docs/de/server.mdx @@ -158,7 +158,6 @@ Der opencode-Server stellt folgende APIs bereit. | `DELETE` | `/session/:id` | Loescht eine Sitzung und alle Daten | Gibt `boolean` zurueck | | `PATCH` | `/session/:id` | Aktualisiert Sitzungseigenschaften | body: `{ title? }`, returns Session | | `GET` | `/session/:id/children` | Ruft Kind-Sitzungen einer Sitzung ab | Gibt Session[] zurueck | -| `GET` | `/session/:id/todo` | Ruft die Todo-Liste einer Sitzung ab | Gibt Todo[] zurueck | | `POST` | `/session/:id/init` | Analysiert App und erstellt `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | | `POST` | `/session/:id/fork` | Forkt eine bestehende Sitzung an einer Nachricht | body: `{ messageID? }`, returns Session | | `POST` | `/session/:id/abort` | Bricht eine laufende Sitzung ab | Gibt `boolean` zurueck | diff --git a/packages/web/src/content/docs/de/tools.mdx b/packages/web/src/content/docs/de/tools.mdx index 8f5e7c0715..29d934df2b 100644 --- a/packages/web/src/content/docs/de/tools.mdx +++ b/packages/web/src/content/docs/de/tools.mdx @@ -217,27 +217,6 @@ Laedt einen [Skill](/docs/skills) (eine `SKILL.md`-Datei) und gibt dessen Inhalt --- -### todowrite - -Verwaltet Todo-Listen waehrend Coding-Sessions. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Erstellt und aktualisiert Aufgabenlisten, um den Fortschritt bei komplexen Operationen zu verfolgen. Das LLM nutzt dies, um mehrstufige Aufgaben zu organisieren. - -:::note -Dieses Tool ist fuer Sub-Agenten standardmaessig deaktiviert, kann aber manuell aktiviert werden. [Mehr dazu](/docs/agents/#permissions) -::: - ---- - ### webfetch Ruft Webinhalte ab. diff --git a/packages/web/src/content/docs/es/plugins.mdx b/packages/web/src/content/docs/es/plugins.mdx index dc44180725..22f69de578 100644 --- a/packages/web/src/content/docs/es/plugins.mdx +++ b/packages/web/src/content/docs/es/plugins.mdx @@ -188,10 +188,6 @@ Los complementos pueden suscribirse a eventos como se ve a continuación en la s - `session.status` - `session.updated` -#### Eventos de Todo - -- `todo.updated` - #### Eventos de Shell - `shell.env` diff --git a/packages/web/src/content/docs/es/server.mdx b/packages/web/src/content/docs/es/server.mdx index c3ce97421e..ca6c0656fb 100644 --- a/packages/web/src/content/docs/es/server.mdx +++ b/packages/web/src/content/docs/es/server.mdx @@ -154,7 +154,6 @@ El servidor opencode expone las siguientes API. | `DELETE` | `/session/:id` | Eliminar una sesión y todos sus datos | Devuelve `boolean` | | `PATCH` | `/session/:id` | Actualizar propiedades de sesión | cuerpo: `{ title? }`, devuelve Session | | `GET` | `/session/:id/children` | Obtener las sesiones secundarias de una sesión | Devuelve Session[] | -| `GET` | `/session/:id/todo` | Obtener la lista de tareas pendientes para una sesión | Devuelve Todo[] | | `POST` | `/session/:id/init` | Analizar aplicación y crear `AGENTS.md` | cuerpo: `{ messageID, providerID, modelID }`, devuelve `boolean` | | `POST` | `/session/:id/fork` | Bifurca una sesión existente en un mensaje | cuerpo: `{ messageID? }`, devuelve Session | | `POST` | `/session/:id/abort` | Cancelar una sesión en ejecución | Devuelve `boolean` | diff --git a/packages/web/src/content/docs/es/tools.mdx b/packages/web/src/content/docs/es/tools.mdx index 5a0cca969b..34dfa85150 100644 --- a/packages/web/src/content/docs/es/tools.mdx +++ b/packages/web/src/content/docs/es/tools.mdx @@ -210,27 +210,6 @@ Cargue una [habilidad](/docs/skills) (un archivo `SKILL.md`) y devuelva su conte --- -### todowrite - -Administre listas de tareas pendientes durante las sesiones de codificación. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Crea y actualiza listas de tareas para realizar un seguimiento del progreso durante operaciones complejas. El LLM usa esto para organizar tareas de varios pasos. - -:::note -Esta herramienta está deshabilitada para los subagentes de forma predeterminada, pero puede habilitarla manualmente. [Más información](/docs/agents/#permissions) -::: - ---- - ### webfetch Obtener contenido web. diff --git a/packages/web/src/content/docs/fr/agents.mdx b/packages/web/src/content/docs/fr/agents.mdx index a6b323dfc8..c989d8f092 100644 --- a/packages/web/src/content/docs/fr/agents.mdx +++ b/packages/web/src/content/docs/fr/agents.mdx @@ -72,7 +72,7 @@ Cet agent est utile lorsque vous souhaitez que le LLM analyse le code, suggère _Mode_ : `subagent` -Un agent polyvalent pour traiter des questions complexes et exécuter des tâches en plusieurs étapes. Dispose d'un accès complet aux outils (sauf todo), il peut donc apporter des modifications aux fichiers en cas de besoin. Utilisez-le pour exécuter plusieurs unités de travail en parallèle. +Un agent polyvalent pour traiter des questions complexes et exécuter des tâches en plusieurs étapes. Dispose d'un accès complet aux outils, il peut donc apporter des modifications aux fichiers en cas de besoin. Utilisez-le pour exécuter plusieurs unités de travail en parallèle. --- diff --git a/packages/web/src/content/docs/fr/plugins.mdx b/packages/web/src/content/docs/fr/plugins.mdx index 48cdc4d116..30a1ff38bc 100644 --- a/packages/web/src/content/docs/fr/plugins.mdx +++ b/packages/web/src/content/docs/fr/plugins.mdx @@ -187,10 +187,6 @@ Les plugins peuvent s'abonner à des événements comme indiqué ci-dessous dans - `session.status` - `session.updated` -#### Événements à faire - -- `todo.updated` - #### Événements Shell - `shell.env` diff --git a/packages/web/src/content/docs/fr/server.mdx b/packages/web/src/content/docs/fr/server.mdx index a376f4a18c..f95a8f14e2 100644 --- a/packages/web/src/content/docs/fr/server.mdx +++ b/packages/web/src/content/docs/fr/server.mdx @@ -154,7 +154,6 @@ Le serveur opencode expose les API suivantes. | `DELETE` | `/session/:id` | Supprimer une session et toutes ses données | Renvoie `boolean` | | `PATCH` | `/session/:id` | Mettre à jour les propriétés de la session | corps : `{ title? }`, renvoie Session | | `GET` | `/session/:id/children` | Obtenir les sessions enfants d'une session | Renvoie Session[] | -| `GET` | `/session/:id/todo` | Obtenez la liste de tâches pour une session | Renvoie Todo[] | | `POST` | `/session/:id/init` | Analysez l'application et créez `AGENTS.md` | corps : `{ messageID, providerID, modelID }`, renvoie `boolean` | | `POST` | `/session/:id/fork` | Forkez une session existante à un message | corps : `{ messageID? }`, renvoie Session | | `POST` | `/session/:id/abort` | Abandonner une session en cours | Renvoie `boolean` | diff --git a/packages/web/src/content/docs/fr/tools.mdx b/packages/web/src/content/docs/fr/tools.mdx index 72edf98191..f462d0edc5 100644 --- a/packages/web/src/content/docs/fr/tools.mdx +++ b/packages/web/src/content/docs/fr/tools.mdx @@ -210,27 +210,6 @@ Chargez une [skill](/docs/skills) (un fichier `SKILL.md`) et renvoyez son conten --- -### à écrire - -Gérez les listes de tâches pendant les sessions de codage. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Crée et met à jour des listes de tâches pour suivre la progression lors d'opérations complexes. Le LLM l'utilise pour organiser des tâches en plusieurs étapes. - -:::note -Cet outil est désactivé par défaut pour les sous-agents, mais vous pouvez l'activer manuellement. [En savoir plus](/docs/agents/#permissions) -::: - ---- - ### récupération sur le Web Récupérer du contenu Web. diff --git a/packages/web/src/content/docs/it/agents.mdx b/packages/web/src/content/docs/it/agents.mdx index 70aea57533..6faa76a193 100644 --- a/packages/web/src/content/docs/it/agents.mdx +++ b/packages/web/src/content/docs/it/agents.mdx @@ -71,7 +71,7 @@ Questo agente è utile quando vuoi che l'LLM analizzi il codice, suggerisca modi _Mode_: `subagent` -Un agente general-purpose per ricercare domande complesse ed eseguire task multi-step. Ha accesso completo agli strumenti (tranne todo), quindi può modificare file quando serve. Usalo per eseguire più unità di lavoro in parallelo. +Un agente general-purpose per ricercare domande complesse ed eseguire task multi-step. Ha accesso completo agli strumenti, quindi può modificare file quando serve. Usalo per eseguire più unità di lavoro in parallelo. --- diff --git a/packages/web/src/content/docs/it/plugins.mdx b/packages/web/src/content/docs/it/plugins.mdx index 3fc22a78c5..3f1cbbe09a 100644 --- a/packages/web/src/content/docs/it/plugins.mdx +++ b/packages/web/src/content/docs/it/plugins.mdx @@ -187,10 +187,6 @@ I plugin possono sottoscrivere eventi come mostrato sotto nella sezione Esempi. - `session.status` - `session.updated` -#### Eventi della todo - -- `todo.updated` - #### Eventi della shell - `shell.env` diff --git a/packages/web/src/content/docs/it/server.mdx b/packages/web/src/content/docs/it/server.mdx index df66d39fdc..473bb8e7c5 100644 --- a/packages/web/src/content/docs/it/server.mdx +++ b/packages/web/src/content/docs/it/server.mdx @@ -151,7 +151,6 @@ Il server opencode espone le seguenti API. | `DELETE` | `/session/:id` | Elimina una sessione e i suoi dati | Returns `boolean` | | `PATCH` | `/session/:id` | Aggiorna proprieta sessione | body: `{ title? }`, returns Session | | `GET` | `/session/:id/children` | Sessioni figlie | Returns Session[] | -| `GET` | `/session/:id/todo` | Todo list della sessione | Returns Todo[] | | `POST` | `/session/:id/init` | Analizza app e crea `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | | `POST` | `/session/:id/fork` | Fork di sessione su un messaggio | body: `{ messageID? }`, returns Session | | `POST` | `/session/:id/abort` | Interrompe una sessione in esecuzione | Returns `boolean` | diff --git a/packages/web/src/content/docs/it/tools.mdx b/packages/web/src/content/docs/it/tools.mdx index e3f2f23ce9..402c86ef98 100644 --- a/packages/web/src/content/docs/it/tools.mdx +++ b/packages/web/src/content/docs/it/tools.mdx @@ -210,27 +210,6 @@ Carica una [skill](/docs/skills) (un file `SKILL.md`) e ne restituisce il conten --- -### todowrite - -Gestisci todo list durante le sessioni di coding. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Crea e aggiorna liste di task per tracciare i progressi durante operazioni complesse. L'LLM lo usa per organizzare attivita' multi-step. - -:::note -Questo strumento e' disabilitato per i subagenti di default, ma puoi abilitarlo manualmente. [Scopri di piu'](/docs/agents/#permissions) -::: - ---- - ### webfetch Recupera contenuti dal web. diff --git a/packages/web/src/content/docs/ja/agents.mdx b/packages/web/src/content/docs/ja/agents.mdx index 539d30faf8..64e57acf58 100644 --- a/packages/web/src/content/docs/ja/agents.mdx +++ b/packages/web/src/content/docs/ja/agents.mdx @@ -71,7 +71,7 @@ _モード_: `primary` _モード_: `subagent` -複雑な質問を調査し、複数ステップのタスクを実行するための汎用エージェント。完全なツールアクセス権 (todo を除く) があるため、必要に応じてファイルを変更できます。これを使用して、複数の作業単位を並行して実行します。 +複雑な質問を調査し、複数ステップのタスクを実行するための汎用エージェント。完全なツールアクセス権があるため、必要に応じてファイルを変更できます。これを使用して、複数の作業単位を並行して実行します。 --- diff --git a/packages/web/src/content/docs/ja/plugins.mdx b/packages/web/src/content/docs/ja/plugins.mdx index 06a0dca9ad..990d4690b5 100644 --- a/packages/web/src/content/docs/ja/plugins.mdx +++ b/packages/web/src/content/docs/ja/plugins.mdx @@ -188,10 +188,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### ToDo イベント - -- `todo.updated` - #### シェルイベント - `shell.env` diff --git a/packages/web/src/content/docs/ja/server.mdx b/packages/web/src/content/docs/ja/server.mdx index cbea87083e..8ca98f4d81 100644 --- a/packages/web/src/content/docs/ja/server.mdx +++ b/packages/web/src/content/docs/ja/server.mdx @@ -149,7 +149,6 @@ OpenCode サーバーは次の API を公開します。 | `DELETE` | `/session/:id` | セッションとそのすべてのデータを削除する | 戻り値 `boolean` | | `PATCH` | `/session/:id` | セッションのプロパティを更新する | 本文: `{ title? }`、Session を返します。 | | `GET` | `/session/:id/children` | セッションの子セッションを取得する | 戻り値 Session[] | -| `GET` | `/session/:id/todo` | セッションの ToDo リストを取得する | 戻り値 Todo[] | | `POST` | `/session/:id/init` | アプリを分析して `AGENTS.md` を作成する | 本文: `{ messageID, providerID, modelID }`、`boolean` を返します。 | | `POST` | `/session/:id/fork` | メッセージで既存のセッションをフォークする | 本文: `{ messageID? }`、Session を返します。 | | `POST` | `/session/:id/abort` | 実行中のセッションを中止する | 戻り値 `boolean` | diff --git a/packages/web/src/content/docs/ja/tools.mdx b/packages/web/src/content/docs/ja/tools.mdx index 1473a0b360..a755951280 100644 --- a/packages/web/src/content/docs/ja/tools.mdx +++ b/packages/web/src/content/docs/ja/tools.mdx @@ -210,27 +210,6 @@ OpenCode で利用可能なすべての組み込みツールを次に示しま --- -### todowrite - -コーディングセッション中に ToDo リストを管理します。 - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -タスクリストを作成および更新して、複雑な操作中の進行状況を追跡します。 LLM はこれを使用して、複数ステップのタスクを整理します。 - -:::note -このツールはデフォルトではサブエージェントに対して無効になっていますが、手動で有効にすることができます。 [詳細はこちら](/docs/agents/#permissions) -::: - ---- - ### webfetch Web コンテンツを取得します。 diff --git a/packages/web/src/content/docs/ko/agents.mdx b/packages/web/src/content/docs/ko/agents.mdx index 02f31c5b62..b9120d5c7c 100644 --- a/packages/web/src/content/docs/ko/agents.mdx +++ b/packages/web/src/content/docs/ko/agents.mdx @@ -71,7 +71,7 @@ Plan은 계획과 분석에 특화된 제한형 agent입니다. 더 높은 제 _Mode_: `subagent` -복잡한 질문을 조사하고 다단계 작업을 수행하기 위한 범용 agent입니다. todo를 제외한 모든 tool 접근이 가능하므로 필요하면 파일 수정도 할 수 있습니다. 여러 작업 단위를 병렬로 처리할 때 사용하세요. +복잡한 질문을 조사하고 다단계 작업을 수행하기 위한 범용 agent입니다. 모든 tool 접근이 가능하므로 필요하면 파일 수정도 할 수 있습니다. 여러 작업 단위를 병렬로 처리할 때 사용하세요. --- diff --git a/packages/web/src/content/docs/ko/plugins.mdx b/packages/web/src/content/docs/ko/plugins.mdx index f20eb90c46..27e20a5d53 100644 --- a/packages/web/src/content/docs/ko/plugins.mdx +++ b/packages/web/src/content/docs/ko/plugins.mdx @@ -187,10 +187,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### Todo 이벤트 - -- `todo.updated` - #### 셸 이벤트 - `shell.env` diff --git a/packages/web/src/content/docs/ko/server.mdx b/packages/web/src/content/docs/ko/server.mdx index a6914605a7..ffd1d947ac 100644 --- a/packages/web/src/content/docs/ko/server.mdx +++ b/packages/web/src/content/docs/ko/server.mdx @@ -154,7 +154,6 @@ opencode 서버는 다음과 같은 API를 노출합니다. | `DELETE` | `/session/:id` | 세션 삭제 및 모든 데이터 | `boolean` | | `PATCH` | `/session/:id` | 업데이트 세션 속성 | 본체: `{ title? }`, 반환 Session | | `GET` | `/session/:id/children` | 세션의 하위 세션 | 리턴 Session[] | -| `GET` | `/session/:id/todo` | 세션의 할 일(Todo) 목록 받기 | Todo[] | | `POST` | `/session/:id/init` | 앱 초기화 및 `AGENTS.md` 분석 | 몸: `{ messageID, providerID, modelID }`, 반환 `boolean` | | `POST` | `/session/:id/fork` | 메시지의 기존 세션 | 몸: `{ messageID? }`, 반환 Session | | `POST` | `/session/:id/abort` | 운영 중인 세션 | 반품 `boolean` | diff --git a/packages/web/src/content/docs/ko/tools.mdx b/packages/web/src/content/docs/ko/tools.mdx index 8fe5ab1d0a..7df5cb6cbb 100644 --- a/packages/web/src/content/docs/ko/tools.mdx +++ b/packages/web/src/content/docs/ko/tools.mdx @@ -210,27 +210,6 @@ LSP 서버가 프로젝트에 사용할 수 있는 구성하려면 [LSP Servers] --- -## todowrite - -코딩 세션 중에 todo 목록을 관리합니다. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -복잡한 작업 중에 진행 상황을 추적하기 위해 작업 목록을 만들고 업데이트합니다. LLM은 멀티 단계 작업을 구성하기 위해 이것을 사용합니다. - -:::note -이 도구는 기본으로 시약을 비활성화하지만 수동으로 활성화 할 수 있습니다. [더 알아보기](/docs/agents/#permissions) -::: - ---- - #### webfetch Fetch 웹 콘텐츠. diff --git a/packages/web/src/content/docs/nb/agents.mdx b/packages/web/src/content/docs/nb/agents.mdx index f9971758d5..f5cbf7bc39 100644 --- a/packages/web/src/content/docs/nb/agents.mdx +++ b/packages/web/src/content/docs/nb/agents.mdx @@ -71,7 +71,7 @@ Denne agenten er nyttig når du vil at LLM skal analysere kode, foreslå endring _Modus_: `subagent` -En generell agent for å undersøke komplekse spørsmål og utføre flertrinnsoppgaver. Har full verktøytilgang (unntatt todo), slik at den kan gjøre filendringer når det er nødvendig. Bruk denne til å kjøre flere arbeidsenheter parallelt. +En generell agent for å undersøke komplekse spørsmål og utføre flertrinnsoppgaver. Har full verktøytilgang, slik at den kan gjøre filendringer når det er nødvendig. Bruk denne til å kjøre flere arbeidsenheter parallelt. --- diff --git a/packages/web/src/content/docs/nb/plugins.mdx b/packages/web/src/content/docs/nb/plugins.mdx index 27d23ec63a..ccf8a933de 100644 --- a/packages/web/src/content/docs/nb/plugins.mdx +++ b/packages/web/src/content/docs/nb/plugins.mdx @@ -188,10 +188,6 @@ Plugins kan abonnere på hendelser som vist nedenfor i Eksempler-delen. Her er e - `session.status` - `session.updated` -#### Todo-hendelser - -- `todo.updated` - #### Shell-hendelser - `shell.env` diff --git a/packages/web/src/content/docs/nb/server.mdx b/packages/web/src/content/docs/nb/server.mdx index a6ad8c6dfb..07eb7f58c6 100644 --- a/packages/web/src/content/docs/nb/server.mdx +++ b/packages/web/src/content/docs/nb/server.mdx @@ -154,7 +154,6 @@ opencode-serveren viser følgende APIer. | `DELETE` | `/session/:id` | Slett en økt og alle dens data | Returnerer `boolean` | | `PATCH` | `/session/:id` | Oppdater øktegenskaper | body: `{ title? }`, returnerer Session | | `GET` | `/session/:id/children` | Hent en økts barneøkter | Returnerer Session[] | -| `GET` | `/session/:id/todo` | Hent gjøremålslisten for en økt | Returnerer Todo[] | | `POST` | `/session/:id/init` | Analyser appen og lag `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returnerer `boolean` | | `POST` | `/session/:id/fork` | Fork en eksisterende økt ved en melding | body: `{ messageID? }`, returnerer Session | | `POST` | `/session/:id/abort` | Avbryt en kjørende økt | Returnerer `boolean` | diff --git a/packages/web/src/content/docs/nb/tools.mdx b/packages/web/src/content/docs/nb/tools.mdx index 2e6f61ba07..d23a231d07 100644 --- a/packages/web/src/content/docs/nb/tools.mdx +++ b/packages/web/src/content/docs/nb/tools.mdx @@ -210,27 +210,6 @@ Last inn en [ferdighet](/docs/skills) (en `SKILL.md` fil) og returner innholdet --- -### todowrite - -Administrer gjøremålslister under kodingsøkter. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Oppretter og oppdaterer oppgavelister for å spore fremdrift under komplekse operasjoner. LLM bruker dette til å organisere flertrinnsoppgaver. - -:::note -Dette verktøyet er deaktivert for subagenter som standard, men du kan aktivere det manuelt. [Finn ut mer](/docs/agents/#permissions) -::: - ---- - ### webfetch Hent nettinnhold. diff --git a/packages/web/src/content/docs/pl/plugins.mdx b/packages/web/src/content/docs/pl/plugins.mdx index 510c8a22e4..75dfd052cb 100644 --- a/packages/web/src/content/docs/pl/plugins.mdx +++ b/packages/web/src/content/docs/pl/plugins.mdx @@ -188,10 +188,6 @@ Wtyczki mogą subskrybować zdarzenia, jak zastosować poniżej sekcji Przykład - `session.status` - `session.updated` -#### Wydarzenia do zrobienia - -- `todo.updated` - #### Wydarzenia shell - `shell.env` diff --git a/packages/web/src/content/docs/pl/server.mdx b/packages/web/src/content/docs/pl/server.mdx index 0efcf486f6..31195b6e83 100644 --- a/packages/web/src/content/docs/pl/server.mdx +++ b/packages/web/src/content/docs/pl/server.mdx @@ -154,7 +154,6 @@ Serwer opencode udostępnia następujące interfejsy API. | `DELETE` | `/session/:id` | Usuń sesję i wszystkie jej dane | Zwraca `boolean` | | `PATCH` | `/session/:id` | Aktualizuj właściwości sesji | treść: `{ title? }`, zwraca Session | | `GET` | `/session/:id/children` | Pobierz sesje podrzędne sesji | Zwraca Session[] | -| `GET` | `/session/:id/todo` | Pobierz listę rzeczy do zrobienia dla sesji | Zwraca Todo[] | | `POST` | `/session/:id/init` | Przeanalizuj aplikację i utwórz `AGENTS.md` | treść: `{ messageID, providerID, modelID }`, zwraca `boolean` | | `POST` | `/session/:id/fork` | Rozwiń istniejącą sesję w wiadomości | treść: `{ messageID? }`, zwraca Session | | `POST` | `/session/:id/abort` | Przerwij trwającą sesję | Zwraca `boolean` | diff --git a/packages/web/src/content/docs/pl/tools.mdx b/packages/web/src/content/docs/pl/tools.mdx index 6b8a5eeb49..3b30d3efe8 100644 --- a/packages/web/src/content/docs/pl/tools.mdx +++ b/packages/web/src/content/docs/pl/tools.mdx @@ -210,27 +210,6 @@ Załaduj [umiejętność](/docs/skills) (plik `SKILL.md`) i zwróć jej treść --- -### todowrite - -Zarządzaj listami zadań (todo) podczas sesji kodowania. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Tworzy i aktualizuje listy zadań w celu śledzenia postępu podczas złożonych operacji. LLM wykorzystuje to do organizowania zadań wieloetapowych. - -:::note -To narzędzie jest domyślnie wyłączone dla subagentów, ale można je włączyć ręcznie. [Dowiedz się więcej](/docs/agents/#permissions) -::: - ---- - ### webfetch Pobieraj treści z sieci. diff --git a/packages/web/src/content/docs/plugins.mdx b/packages/web/src/content/docs/plugins.mdx index a8be798217..b845af67fd 100644 --- a/packages/web/src/content/docs/plugins.mdx +++ b/packages/web/src/content/docs/plugins.mdx @@ -188,10 +188,6 @@ Plugins can subscribe to events as seen below in the Examples section. Here is a - `session.status` - `session.updated` -#### Todo Events - -- `todo.updated` - #### Shell Events - `shell.env` diff --git a/packages/web/src/content/docs/pt-br/agents.mdx b/packages/web/src/content/docs/pt-br/agents.mdx index 815264d840..d89addf7a0 100644 --- a/packages/web/src/content/docs/pt-br/agents.mdx +++ b/packages/web/src/content/docs/pt-br/agents.mdx @@ -72,7 +72,7 @@ Este agente é útil quando você deseja que o LLM analise código, sugira alter _Modo_: `subagent` -Um agente de propósito geral para pesquisar questões complexas e executar tarefas em múltiplas etapas. Tem acesso total às ferramentas (exceto todo), portanto, pode fazer alterações em arquivos quando necessário. Use isso para executar várias unidades de trabalho em paralelo. +Um agente de propósito geral para pesquisar questões complexas e executar tarefas em múltiplas etapas. Tem acesso total às ferramentas, portanto, pode fazer alterações em arquivos quando necessário. Use isso para executar várias unidades de trabalho em paralelo. --- diff --git a/packages/web/src/content/docs/pt-br/plugins.mdx b/packages/web/src/content/docs/pt-br/plugins.mdx index 54c5b1ffac..0d809d6203 100644 --- a/packages/web/src/content/docs/pt-br/plugins.mdx +++ b/packages/web/src/content/docs/pt-br/plugins.mdx @@ -187,10 +187,6 @@ Plugins podem se inscrever em eventos como visto abaixo na seção Exemplos. Aqu - `session.status` - `session.updated` -#### Eventos de Todo - -- `todo.updated` - #### Eventos de Shell - `shell.env` diff --git a/packages/web/src/content/docs/pt-br/server.mdx b/packages/web/src/content/docs/pt-br/server.mdx index 6d2e9eb386..1659c5cdc3 100644 --- a/packages/web/src/content/docs/pt-br/server.mdx +++ b/packages/web/src/content/docs/pt-br/server.mdx @@ -151,7 +151,6 @@ O servidor opencode expõe as seguintes APIs. | `DELETE` | `/session/:id` | Deletar uma sessão e todos os seus dados | Retorna `boolean` | | `PATCH` | `/session/:id` | Atualizar propriedades da sessão | corpo: `{ title? }`, retorna Session | | `GET` | `/session/:id/children` | Obter as sessões filhas de uma sessão | Retorna Session[] | -| `GET` | `/session/:id/todo` | Obter a lista de tarefas para uma sessão | Retorna Todo[] | | `POST` | `/session/:id/init` | Analisar o app e criar `AGENTS.md` | corpo: `{ messageID, providerID, modelID }`, retorna `boolean` | | `POST` | `/session/:id/fork` | Fazer um fork de uma sessão existente em uma mensagem | corpo: `{ messageID? }`, retorna Session | | `POST` | `/session/:id/abort` | Abortar uma sessão em execução | Retorna `boolean` | diff --git a/packages/web/src/content/docs/pt-br/tools.mdx b/packages/web/src/content/docs/pt-br/tools.mdx index 86fd714d32..4635cf06b0 100644 --- a/packages/web/src/content/docs/pt-br/tools.mdx +++ b/packages/web/src/content/docs/pt-br/tools.mdx @@ -210,27 +210,6 @@ Carregue uma [skill](/docs/skills) (um arquivo `SKILL.md`) e retorne seu conteú --- -### todowrite - -Gerencie listas de tarefas durante sessões de codificação. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Cria e atualiza listas de tarefas para acompanhar o progresso durante operações complexas. O LLM usa isso para organizar tarefas de múltiplas etapas. - -:::note -Esta ferramenta está desativada para subagentes por padrão, mas você pode ativá-la manualmente. [Saiba mais](/docs/agents/#permissions) -::: - ---- - ### webfetch Busque conteúdo da web. diff --git a/packages/web/src/content/docs/ru/plugins.mdx b/packages/web/src/content/docs/ru/plugins.mdx index 1d7ffb339b..7b2e9cdf9d 100644 --- a/packages/web/src/content/docs/ru/plugins.mdx +++ b/packages/web/src/content/docs/ru/plugins.mdx @@ -188,10 +188,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### События - -- `todo.updated` - #### События shell - `shell.env` diff --git a/packages/web/src/content/docs/ru/server.mdx b/packages/web/src/content/docs/ru/server.mdx index 2356543dff..d54e7bbdf6 100644 --- a/packages/web/src/content/docs/ru/server.mdx +++ b/packages/web/src/content/docs/ru/server.mdx @@ -154,7 +154,6 @@ For example, `http://localhost:4096/doc`. Use the spec to generate clients or in | `DELETE` | `/session/:id` | Удалить сессию и все её данные | Возвращает `boolean` | | `PATCH` | `/session/:id` | Обновить свойства сессии | body: `{ title? }`, возвращает Session | | `GET` | `/session/:id/children` | Получить дочерние сессии | Возвращает Session[] | -| `GET` | `/session/:id/todo` | Получить список задач для сессии | Возвращает Todo[] | | `POST` | `/session/:id/init` | Анализ приложения и создание `AGENTS.md` | body: `{ messageID, providerID, modelID }`, возвращает `boolean` | | `POST` | `/session/:id/fork` | Ответвление сессии от сообщения | body: `{ messageID? }`, возвращает Session | | `POST` | `/session/:id/abort` | Прервать запущенную сессию | Возвращает `boolean` | diff --git a/packages/web/src/content/docs/ru/tools.mdx b/packages/web/src/content/docs/ru/tools.mdx index b34d30465b..a84dd0e455 100644 --- a/packages/web/src/content/docs/ru/tools.mdx +++ b/packages/web/src/content/docs/ru/tools.mdx @@ -210,27 +210,6 @@ description: Управляйте инструментами, которые м --- -### todowrite - -Управляйте списками дел во время сеансов кодирования. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Создает и обновляет списки задач для отслеживания прогресса во время сложных операций. LLM использует это для организации многоэтапных задач. - -:::note -По умолчанию этот инструмент отключен для субагентов, но вы можете включить его вручную. [Подробнее](/docs/agents/#permissions) -::: - ---- - ### webfetch Получить веб-контент. diff --git a/packages/web/src/content/docs/server.mdx b/packages/web/src/content/docs/server.mdx index 4510bd4981..8abd2aa080 100644 --- a/packages/web/src/content/docs/server.mdx +++ b/packages/web/src/content/docs/server.mdx @@ -154,7 +154,6 @@ The opencode server exposes the following APIs. | `DELETE` | `/session/:id` | Delete a session and all its data | Returns `boolean` | | `PATCH` | `/session/:id` | Update session properties | body: `{ title? }`, returns Session | | `GET` | `/session/:id/children` | Get a session's child sessions | Returns Session[] | -| `GET` | `/session/:id/todo` | Get the todo list for a session | Returns Todo[] | | `POST` | `/session/:id/init` | Analyze app and create `AGENTS.md` | body: `{ messageID, providerID, modelID }`, returns `boolean` | | `POST` | `/session/:id/fork` | Fork an existing session at a message | body: `{ messageID? }`, returns Session | | `POST` | `/session/:id/abort` | Abort a running session | Returns `boolean` | diff --git a/packages/web/src/content/docs/th/plugins.mdx b/packages/web/src/content/docs/th/plugins.mdx index e672715a4e..2a913837c6 100644 --- a/packages/web/src/content/docs/th/plugins.mdx +++ b/packages/web/src/content/docs/th/plugins.mdx @@ -188,10 +188,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### เหตุการณ์ที่ต้องทำ - -- `todo.updated` - #### กิจกรรมของ shell - `shell.env` diff --git a/packages/web/src/content/docs/th/server.mdx b/packages/web/src/content/docs/th/server.mdx index 13302cf578..53dad053f2 100644 --- a/packages/web/src/content/docs/th/server.mdx +++ b/packages/web/src/content/docs/th/server.mdx @@ -154,7 +154,6 @@ http://:/doc | `DELETE` | `/session/:id` | ลบเซสชันและข้อมูลทั้งหมด | ส่งคืน `boolean` | | `PATCH` | `/session/:id` | อัปเดตคุณสมบัติเซสชัน | body: `{ title? }` ส่งคืน เซสชัน | | `GET` | `/session/:id/children` | รับเซสชันย่อยของเซสชัน | ส่งคืน เซสชัน[] | -| `GET` | `/session/:id/todo` | รับรายการสิ่งที่ต้องทำสำหรับเซสชัน | ส่งคืน สิ่งที่ต้องทำ[] | | `POST` | `/session/:id/init` | วิเคราะห์แอปและสร้าง `AGENTS.md` | เนื้อความ: `{ messageID, providerID, modelID }` ส่งคืน `boolean` | | `POST` | `/session/:id/fork` | แยกเซสชันที่มีอยู่ไปที่ข้อความ | body: `{ messageID? }` ส่งคืน เซสชัน | | `POST` | `/session/:id/abort` | ยกเลิกเซสชันที่ทำงานอยู่ | ส่งคืน `boolean` | diff --git a/packages/web/src/content/docs/th/tools.mdx b/packages/web/src/content/docs/th/tools.mdx index 5006b41de6..6be8ef7888 100644 --- a/packages/web/src/content/docs/th/tools.mdx +++ b/packages/web/src/content/docs/th/tools.mdx @@ -210,27 +210,6 @@ description: จัดการเครื่องมือที่ LLM ส --- -### todowrite - -จัดการรายการสิ่งที่ต้องทำระหว่างเซสชันการเขียนโค้ด - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -สร้างและอัปเดตรายการงานเพื่อติดตามความคืบหน้าระหว่างการดำเนินการที่ซับซ้อน LLM ใช้สิ่งนี้เพื่อจัดระเบียบงานที่มีหลายขั้นตอน - -:::note -เครื่องมือนี้ปิดใช้งานสำหรับตัวแทนย่อยตามค่าเริ่มต้น แต่คุณสามารถเปิดใช้งานได้ด้วยตนเอง [เรียนรู้เพิ่มเติม](/docs/agents/#สิทธิ์) -::: - ---- - ### webfetch ดึงเนื้อหาเว็บ diff --git a/packages/web/src/content/docs/tools.mdx b/packages/web/src/content/docs/tools.mdx index e8d5e0963a..e2ea6c258c 100644 --- a/packages/web/src/content/docs/tools.mdx +++ b/packages/web/src/content/docs/tools.mdx @@ -214,27 +214,6 @@ Load a [skill](/docs/skills) (a `SKILL.md` file) and return its content in the c --- -### todowrite - -Manage todo lists during coding sessions. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Creates and updates task lists to track progress during complex operations. The LLM uses this to organize multi-step tasks. - -:::note -This tool is disabled for subagents by default, but you can enable it manually. [Learn more](/docs/agents/#permissions) -::: - ---- - ### webfetch Fetch web content. diff --git a/packages/web/src/content/docs/tr/plugins.mdx b/packages/web/src/content/docs/tr/plugins.mdx index 4926f5f70e..9321eef36a 100644 --- a/packages/web/src/content/docs/tr/plugins.mdx +++ b/packages/web/src/content/docs/tr/plugins.mdx @@ -187,10 +187,6 @@ Eklentiler aşağıdaki Örnekler bölümünde görüldüğü gibi etkinliklere - `session.status` - `session.updated` -#### Yapılacaklar Olayları - -- `todo.updated` - #### Kabuk Olayları - `shell.env` diff --git a/packages/web/src/content/docs/tr/server.mdx b/packages/web/src/content/docs/tr/server.mdx index e9af6afd05..a51608c537 100644 --- a/packages/web/src/content/docs/tr/server.mdx +++ b/packages/web/src/content/docs/tr/server.mdx @@ -152,7 +152,6 @@ opencode sunucusu aşağıdaki API'leri sunar. | `DELETE` | `/session/:id` | Bir oturumu ve tüm verilerini sil | `boolean` döndürür | | `PATCH` | `/session/:id` | Oturum özelliklerini güncelle | gövde: `{ title? }`, Session döndürür | | `GET` | `/session/:id/children` | Bir oturumun alt oturumlarını al | Session[] döndürür | -| `GET` | `/session/:id/todo` | Bir oturum için yapılacaklar listesini al | Todo[] döndürür | | `POST` | `/session/:id/init` | Uygulamayı analiz et ve `AGENTS.md` oluştur | gövde: `{ messageID, providerID, modelID }`, `boolean` döndürür | | `POST` | `/session/:id/fork` | Mevcut bir oturumu bir mesajda çatalla | gövde: `{ messageID? }`, Session döndürür | | `POST` | `/session/:id/abort` | Çalışan bir oturumu iptal et | `boolean` döndürür | diff --git a/packages/web/src/content/docs/tr/tools.mdx b/packages/web/src/content/docs/tr/tools.mdx index 29c1e0054c..32c35eb66b 100644 --- a/packages/web/src/content/docs/tr/tools.mdx +++ b/packages/web/src/content/docs/tr/tools.mdx @@ -210,27 +210,6 @@ Bir [skill](/docs/skills) (`SKILL.md` dosyası) yükler ve içeriğini konuşmay --- -### todowrite - -Kodlama oturumlarında yapılacaklar listesini yönetir. - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -Karmaşık işlemlerde ilerlemeyi takip etmek için görev listeleri oluşturur ve günceller. LLM bunu çok adımlı görevleri düzenlemek için kullanır. - -:::note -Bu araç alt agent'lar için varsayılan olarak devre dışıdır, ama manuel etkinleştirebilirsiniz. [Daha fazla bilgi](/docs/agents/#permissions) -::: - ---- - ### webfetch Web içeriği getirir. diff --git a/packages/web/src/content/docs/zh-cn/agents.mdx b/packages/web/src/content/docs/zh-cn/agents.mdx index 6f821ff7f8..b87ce42a5a 100644 --- a/packages/web/src/content/docs/zh-cn/agents.mdx +++ b/packages/web/src/content/docs/zh-cn/agents.mdx @@ -71,7 +71,7 @@ _模式_:`primary` _模式_:`subagent` -一个用于研究复杂问题和执行多步骤任务的通用代理。拥有完整的工具访问权限(todo 除外),因此可以在需要时修改文件。可用于并行运行多个工作单元。 +一个用于研究复杂问题和执行多步骤任务的通用代理。拥有完整的工具访问权限,因此可以在需要时修改文件。可用于并行运行多个工作单元。 --- diff --git a/packages/web/src/content/docs/zh-cn/plugins.mdx b/packages/web/src/content/docs/zh-cn/plugins.mdx index e8a8bd70cb..bd15482637 100644 --- a/packages/web/src/content/docs/zh-cn/plugins.mdx +++ b/packages/web/src/content/docs/zh-cn/plugins.mdx @@ -187,10 +187,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### 待办事项事件 - -- `todo.updated` - #### Shell 事件 - `shell.env` diff --git a/packages/web/src/content/docs/zh-cn/server.mdx b/packages/web/src/content/docs/zh-cn/server.mdx index d28342ecc6..250f12a0ac 100644 --- a/packages/web/src/content/docs/zh-cn/server.mdx +++ b/packages/web/src/content/docs/zh-cn/server.mdx @@ -151,7 +151,6 @@ opencode 服务器暴露以下 API。 | `DELETE` | `/session/:id` | 删除会话及其所有数据 | 返回 `boolean` | | `PATCH` | `/session/:id` | 更新会话属性 | 请求体:`{ title? }`,返回 Session | | `GET` | `/session/:id/children` | 获取会话的子会话 | 返回 Session[] | -| `GET` | `/session/:id/todo` | 获取会话的待办事项列表 | 返回 Todo[] | | `POST` | `/session/:id/init` | 分析应用并创建 `AGENTS.md` | 请求体:`{ messageID, providerID, modelID }`,返回 `boolean` | | `POST` | `/session/:id/fork` | 在某条消息处分叉现有会话 | 请求体:`{ messageID? }`,返回 Session | | `POST` | `/session/:id/abort` | 中止正在运行的会话 | 返回 `boolean` | diff --git a/packages/web/src/content/docs/zh-cn/tools.mdx b/packages/web/src/content/docs/zh-cn/tools.mdx index 1a58eece5d..55607d4d9c 100644 --- a/packages/web/src/content/docs/zh-cn/tools.mdx +++ b/packages/web/src/content/docs/zh-cn/tools.mdx @@ -210,27 +210,6 @@ description: 管理 LLM 可以使用的工具。 --- -### todowrite - -在编码会话中管理待办事项列表。 - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -创建和更新任务列表以跟踪复杂操作的进度。LLM 使用此工具来组织多步骤任务。 - -:::note -该工具默认对子代理禁用,但您可以手动启用。[了解更多](/docs/agents/#permissions) -::: - ---- - ### webfetch 获取网页内容。 diff --git a/packages/web/src/content/docs/zh-tw/agents.mdx b/packages/web/src/content/docs/zh-tw/agents.mdx index a9c7bbadbf..e67cea395a 100644 --- a/packages/web/src/content/docs/zh-tw/agents.mdx +++ b/packages/web/src/content/docs/zh-tw/agents.mdx @@ -71,7 +71,7 @@ _模式_:`primary` _模式_:`subagent` -一個用於研究複雜問題和執行多步驟任務的通用代理。擁有完整的工具存取權限(todo 除外),因此可以在需要時修改檔案。可用於並行執行多個工作單元。 +一個用於研究複雜問題和執行多步驟任務的通用代理。擁有完整的工具存取權限,因此可以在需要時修改檔案。可用於並行執行多個工作單元。 --- diff --git a/packages/web/src/content/docs/zh-tw/plugins.mdx b/packages/web/src/content/docs/zh-tw/plugins.mdx index 8163c291e0..d2ffac5381 100644 --- a/packages/web/src/content/docs/zh-tw/plugins.mdx +++ b/packages/web/src/content/docs/zh-tw/plugins.mdx @@ -187,10 +187,6 @@ export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree - `session.status` - `session.updated` -#### 待辦事項事件 - -- `todo.updated` - #### Shell 事件 - `shell.env` diff --git a/packages/web/src/content/docs/zh-tw/server.mdx b/packages/web/src/content/docs/zh-tw/server.mdx index 411bc0eb72..1cbb04059e 100644 --- a/packages/web/src/content/docs/zh-tw/server.mdx +++ b/packages/web/src/content/docs/zh-tw/server.mdx @@ -151,7 +151,6 @@ opencode 伺服器暴露以下 API。 | `DELETE` | `/session/:id` | 刪除工作階段及其所有資料 | 回傳 `boolean` | | `PATCH` | `/session/:id` | 更新工作階段屬性 | 請求主體:`{ title? }`,回傳 Session | | `GET` | `/session/:id/children` | 取得工作階段的子工作階段 | 回傳 Session[] | -| `GET` | `/session/:id/todo` | 取得工作階段的待辦事項清單 | 回傳 Todo[] | | `POST` | `/session/:id/init` | 分析應用程式並建立 `AGENTS.md` | 請求主體:`{ messageID, providerID, modelID }`,回傳 `boolean` | | `POST` | `/session/:id/fork` | 在某條訊息處分岔現有工作階段 | 請求主體:`{ messageID? }`,回傳 Session | | `POST` | `/session/:id/abort` | 中止正在執行的工作階段 | 回傳 `boolean` | diff --git a/packages/web/src/content/docs/zh-tw/tools.mdx b/packages/web/src/content/docs/zh-tw/tools.mdx index 763d0ce9a7..1d5c3da848 100644 --- a/packages/web/src/content/docs/zh-tw/tools.mdx +++ b/packages/web/src/content/docs/zh-tw/tools.mdx @@ -210,27 +210,6 @@ description: 管理 LLM 可以使用的工具。 --- -### todowrite - -在編碼工作階段中管理待辦事項清單。 - -```json title="opencode.json" {4} -{ - "$schema": "https://opencode.ai/config.json", - "permission": { - "todowrite": "allow" - } -} -``` - -建立和更新任務清單以追蹤複雜操作的進度。LLM 使用此工具來組織多步驟任務。 - -:::note -該工具預設對子代理停用,但您可以手動啟用。[了解更多](/docs/agents/#permissions) -::: - ---- - ### webfetch 擷取網頁內容。 diff --git a/packages/web/src/content/i18n/ar.json b/packages/web/src/content/i18n/ar.json index d8029441fe..1f1b30ae7f 100644 --- a/packages/web/src/content/i18n/ar.json +++ b/packages/web/src/content/i18n/ar.json @@ -64,9 +64,6 @@ "share.attachment": "مرفق", "share.thinking": "تفكير", "share.thinking_pending": "جارٍ التفكير...", - "share.creating_plan": "جارٍ إنشاء الخطة", - "share.completing_plan": "جارٍ إكمال الخطة", - "share.updating_plan": "جارٍ تحديث الخطة", "share.match_one": "مطابقة", "share.match_other": "مطابقات", "share.result_one": "نتيجة", diff --git a/packages/web/src/content/i18n/bs.json b/packages/web/src/content/i18n/bs.json index 6dc96ce7f3..b393f4ebab 100644 --- a/packages/web/src/content/i18n/bs.json +++ b/packages/web/src/content/i18n/bs.json @@ -64,9 +64,6 @@ "share.attachment": "Prilog", "share.thinking": "Razmišljanje", "share.thinking_pending": "razmišlja...", - "share.creating_plan": "Kreiranje plana", - "share.completing_plan": "Završavanje plana", - "share.updating_plan": "Ažuriranje plana", "share.match_one": "podudaranje", "share.match_other": "podudaranja", "share.result_one": "rezultat", diff --git a/packages/web/src/content/i18n/da.json b/packages/web/src/content/i18n/da.json index a375c6713e..40a40180ca 100644 --- a/packages/web/src/content/i18n/da.json +++ b/packages/web/src/content/i18n/da.json @@ -64,9 +64,6 @@ "share.attachment": "Vedhæftet fil", "share.thinking": "Tænker", "share.thinking_pending": "Tænker...", - "share.creating_plan": "Oprettelse af plan", - "share.completing_plan": "Færdiggør plan", - "share.updating_plan": "Opdatering af plan", "share.match_one": "træf", "share.match_other": "træf", "share.result_one": "resultat", diff --git a/packages/web/src/content/i18n/de.json b/packages/web/src/content/i18n/de.json index 9d63143689..c4d66457bc 100644 --- a/packages/web/src/content/i18n/de.json +++ b/packages/web/src/content/i18n/de.json @@ -64,9 +64,6 @@ "share.attachment": "Anhang", "share.thinking": "Denken", "share.thinking_pending": "Denken...", - "share.creating_plan": "Plan wird erstellt", - "share.completing_plan": "Plan wird abgeschlossen", - "share.updating_plan": "Plan wird aktualisiert", "share.match_one": "Treffer", "share.match_other": "Treffer", "share.result_one": "Ergebnis", diff --git a/packages/web/src/content/i18n/en.json b/packages/web/src/content/i18n/en.json index fedb70a6cb..8f309c35d4 100644 --- a/packages/web/src/content/i18n/en.json +++ b/packages/web/src/content/i18n/en.json @@ -64,9 +64,6 @@ "share.attachment": "Attachment", "share.thinking": "Thinking", "share.thinking_pending": "Thinking...", - "share.creating_plan": "Creating plan", - "share.completing_plan": "Completing plan", - "share.updating_plan": "Updating plan", "share.match_one": "match", "share.match_other": "matches", "share.result_one": "result", diff --git a/packages/web/src/content/i18n/es.json b/packages/web/src/content/i18n/es.json index a30a7f0649..b8eabccd57 100644 --- a/packages/web/src/content/i18n/es.json +++ b/packages/web/src/content/i18n/es.json @@ -64,9 +64,6 @@ "share.attachment": "Adjunto", "share.thinking": "Pensamiento", "share.thinking_pending": "Pensando...", - "share.creating_plan": "Creando plan", - "share.completing_plan": "Completando el plan", - "share.updating_plan": "Actualizando el plan", "share.match_one": "coincidencia", "share.match_other": "coincidencias", "share.result_one": "resultado", diff --git a/packages/web/src/content/i18n/fr.json b/packages/web/src/content/i18n/fr.json index 294badf495..577bdf15b4 100644 --- a/packages/web/src/content/i18n/fr.json +++ b/packages/web/src/content/i18n/fr.json @@ -64,9 +64,6 @@ "share.attachment": "Pièce jointe", "share.thinking": "Réflexion", "share.thinking_pending": "Réflexion...", - "share.creating_plan": "Création du plan", - "share.completing_plan": "Finalisation du plan", - "share.updating_plan": "Mise à jour du plan", "share.match_one": "correspondance", "share.match_other": "correspondances", "share.result_one": "résultat", diff --git a/packages/web/src/content/i18n/it.json b/packages/web/src/content/i18n/it.json index a9ed2b1f86..68eaf48842 100644 --- a/packages/web/src/content/i18n/it.json +++ b/packages/web/src/content/i18n/it.json @@ -64,9 +64,6 @@ "share.attachment": "Allegato", "share.thinking": "Elaborazione", "share.thinking_pending": "Elaborazione...", - "share.creating_plan": "Creazione piano", - "share.completing_plan": "Completamento piano", - "share.updating_plan": "Aggiornamento piano", "share.match_one": "corrispondenza", "share.match_other": "corrispondenze", "share.result_one": "risultato", diff --git a/packages/web/src/content/i18n/ja.json b/packages/web/src/content/i18n/ja.json index 9ef6851e52..1cebb5e246 100644 --- a/packages/web/src/content/i18n/ja.json +++ b/packages/web/src/content/i18n/ja.json @@ -64,9 +64,6 @@ "share.attachment": "添付ファイル", "share.thinking": "思考", "share.thinking_pending": "思考中...", - "share.creating_plan": "計画を作成", - "share.completing_plan": "計画を完了", - "share.updating_plan": "計画を更新", "share.match_one": "一致", "share.match_other": "一致", "share.result_one": "結果", diff --git a/packages/web/src/content/i18n/ko.json b/packages/web/src/content/i18n/ko.json index 6336655170..3b44bc9aa3 100644 --- a/packages/web/src/content/i18n/ko.json +++ b/packages/web/src/content/i18n/ko.json @@ -64,9 +64,6 @@ "share.attachment": "첨부 파일", "share.thinking": "생각 중", "share.thinking_pending": "생각 중...", - "share.creating_plan": "계획 생성 중", - "share.completing_plan": "계획 완료 중", - "share.updating_plan": "계획 업데이트 중", "share.match_one": "일치", "share.match_other": "일치", "share.result_one": "결과", diff --git a/packages/web/src/content/i18n/nb.json b/packages/web/src/content/i18n/nb.json index c91ba2e229..7a21ed5ffa 100644 --- a/packages/web/src/content/i18n/nb.json +++ b/packages/web/src/content/i18n/nb.json @@ -64,9 +64,6 @@ "share.attachment": "Vedlegg", "share.thinking": "Tenker", "share.thinking_pending": "Tenker...", - "share.creating_plan": "Oppretter plan", - "share.completing_plan": "Fullfører plan", - "share.updating_plan": "Oppdaterer plan", "share.match_one": "treff", "share.match_other": "treff", "share.result_one": "resultat", diff --git a/packages/web/src/content/i18n/pl.json b/packages/web/src/content/i18n/pl.json index 8cc874f82c..6d4430b4ee 100644 --- a/packages/web/src/content/i18n/pl.json +++ b/packages/web/src/content/i18n/pl.json @@ -64,9 +64,6 @@ "share.attachment": "Załącznik", "share.thinking": "Myślenie", "share.thinking_pending": "Myślenie...", - "share.creating_plan": "Tworzenie planu", - "share.completing_plan": "Uzupełnianie planu", - "share.updating_plan": "Aktualizacja planu", "share.match_one": "dopasowanie", "share.match_other": "dopasowania", "share.result_one": "wynik", diff --git a/packages/web/src/content/i18n/pt-BR.json b/packages/web/src/content/i18n/pt-BR.json index c7a378131f..55df5e346e 100644 --- a/packages/web/src/content/i18n/pt-BR.json +++ b/packages/web/src/content/i18n/pt-BR.json @@ -64,9 +64,6 @@ "share.attachment": "Anexo", "share.thinking": "Pensando", "share.thinking_pending": "Pensando...", - "share.creating_plan": "Criando plano", - "share.completing_plan": "Concluindo plano", - "share.updating_plan": "Atualizando plano", "share.match_one": "correspondência", "share.match_other": "correspondências", "share.result_one": "resultado", diff --git a/packages/web/src/content/i18n/ru.json b/packages/web/src/content/i18n/ru.json index 945bc7b0bd..b1cb9693b3 100644 --- a/packages/web/src/content/i18n/ru.json +++ b/packages/web/src/content/i18n/ru.json @@ -64,9 +64,6 @@ "share.attachment": "Вложение", "share.thinking": "Размышление", "share.thinking_pending": "Размышление...", - "share.creating_plan": "Создание плана", - "share.completing_plan": "Завершение плана", - "share.updating_plan": "Обновление плана", "share.match_one": "совпадение", "share.match_other": "совпадений", "share.result_one": "результат", diff --git a/packages/web/src/content/i18n/th.json b/packages/web/src/content/i18n/th.json index 11eb7145cf..989b2372e5 100644 --- a/packages/web/src/content/i18n/th.json +++ b/packages/web/src/content/i18n/th.json @@ -64,9 +64,6 @@ "share.attachment": "ไฟล์แนบ", "share.thinking": "กำลังคิด", "share.thinking_pending": "กำลังคิด...", - "share.creating_plan": "กำลังสร้างแผน", - "share.completing_plan": "กำลังทำแผนให้เสร็จ", - "share.updating_plan": "กำลังอัปเดตแผน", "share.match_one": "รายการที่ตรงกัน", "share.match_other": "รายการที่ตรงกัน", "share.result_one": "ผลลัพธ์", diff --git a/packages/web/src/content/i18n/tr.json b/packages/web/src/content/i18n/tr.json index 9f3e95aa79..9227914891 100644 --- a/packages/web/src/content/i18n/tr.json +++ b/packages/web/src/content/i18n/tr.json @@ -64,9 +64,6 @@ "share.attachment": "Ek", "share.thinking": "Düşünüyor", "share.thinking_pending": "Düşünüyor...", - "share.creating_plan": "Plan oluşturuluyor", - "share.completing_plan": "Plan tamamlanıyor", - "share.updating_plan": "Plan güncelleniyor", "share.match_one": "eşleşme", "share.match_other": "eşleşme", "share.result_one": "sonuç", diff --git a/packages/web/src/content/i18n/zh-CN.json b/packages/web/src/content/i18n/zh-CN.json index e1c9f0c9ea..8970a586f7 100644 --- a/packages/web/src/content/i18n/zh-CN.json +++ b/packages/web/src/content/i18n/zh-CN.json @@ -64,9 +64,6 @@ "share.attachment": "附件", "share.thinking": "思考", "share.thinking_pending": "思考中...", - "share.creating_plan": "正在创建计划", - "share.completing_plan": "正在完成计划", - "share.updating_plan": "正在更新计划", "share.match_one": "匹配", "share.match_other": "匹配项", "share.result_one": "结果", diff --git a/packages/web/src/content/i18n/zh-TW.json b/packages/web/src/content/i18n/zh-TW.json index 82cc25771e..ad26ff98ec 100644 --- a/packages/web/src/content/i18n/zh-TW.json +++ b/packages/web/src/content/i18n/zh-TW.json @@ -64,9 +64,6 @@ "share.attachment": "附件", "share.thinking": "思考中", "share.thinking_pending": "思考中...", - "share.creating_plan": "建立計畫", - "share.completing_plan": "完成計畫", - "share.updating_plan": "更新計畫", "share.match_one": "符合項目", "share.match_other": "符合項目", "share.result_one": "結果", diff --git a/packages/web/src/pages/s/[id].astro b/packages/web/src/pages/s/[id].astro index 7ea42f6916..85c2d73810 100644 --- a/packages/web/src/pages/s/[id].astro +++ b/packages/web/src/pages/s/[id].astro @@ -59,9 +59,6 @@ const messages = { attachment: tx("share.attachment"), thinking: tx("share.thinking"), thinking_pending: tx("share.thinking_pending"), - creating_plan: tx("share.creating_plan"), - completing_plan: tx("share.completing_plan"), - updating_plan: tx("share.updating_plan"), match_one: tx("share.match_one"), match_other: tx("share.match_other"), result_one: tx("share.result_one"), diff --git a/specs/storage/remove-opencode-db.md b/specs/storage/remove-opencode-db.md index 071e70c184..54e56167b3 100644 --- a/specs/storage/remove-opencode-db.md +++ b/specs/storage/remove-opencode-db.md @@ -18,7 +18,7 @@ This does not mean removing SQLite or Drizzle everywhere in one step. The smalle ## Current Inventory -Production imports from `packages/opencode/src/storage/db.ts` are concentrated in 22 source files: +Production imports from `packages/opencode/src/storage/db.ts` are concentrated in 21 source files: - `packages/opencode/src/account/repo.ts` - `packages/opencode/src/cli/cmd/db.ts` @@ -36,13 +36,12 @@ Production imports from `packages/opencode/src/storage/db.ts` are concentrated i - `packages/opencode/src/session/projectors.ts` - `packages/opencode/src/session/prompt.ts` - `packages/opencode/src/session/session.ts` -- `packages/opencode/src/session/todo.ts` - `packages/opencode/src/share/share-next.ts` - `packages/opencode/src/storage/db.ts` - `packages/opencode/src/sync/index.ts` - `packages/opencode/src/worktree/index.ts` -There are 65 direct API/type references in those files. The references fall into the groups below. +There are 63 direct API/type references in those files. The references fall into the groups below. ## Group 1: Database Runtime And Startup @@ -151,7 +150,6 @@ Files: - `packages/opencode/src/session/session.ts` - `packages/opencode/src/session/message-v2.ts` - `packages/opencode/src/session/prompt.ts` -- `packages/opencode/src/session/todo.ts` - `packages/opencode/src/session/projectors.ts` Current usage: @@ -159,7 +157,6 @@ Current usage: - `session/session.ts` uses `Database.use` for session reads, list queries, children, part lookup, and global list helpers. - `session/message-v2.ts` uses `Database.use` to page messages, hydrate parts, fetch one message, and fetch parts. - `session/prompt.ts` imports `eq` from `@/storage/db` and reads current prompt-related session/message rows directly. -- `session/todo.ts` uses `Database.transaction` for todo replacement and `Database.use` for list reads. - `session/projectors.ts` uses `TxOrDb` for session/message usage projection helpers. Why this group should be split: @@ -171,7 +168,6 @@ Why this group should be split: Target shape: - Create or use a session/message read module with Effect-native methods for `get`, `list`, `page`, `parts`, and prompt assembly reads. -- Move todo persistence either into a session todo repository or into the sync event projection path. - Convert `session/projectors.ts` only after Group 2 defines the replacement projector transaction type. Suggested order: @@ -179,7 +175,6 @@ Suggested order: - Migrate `session/message-v2.ts` reads first because the module already centralizes message pagination and hydration. - Migrate `session/session.ts` read helpers next. - Migrate `session/prompt.ts` after message/session reads exist, and import drizzle operators from `drizzle-orm` if any direct SQL remains temporarily. -- Migrate `session/todo.ts` writes with the sync transaction work or move them behind a repository. ## Group 5: Legacy CLI And One-Off Admin Reads diff --git a/specs/v2/api.html b/specs/v2/api.html index 147d24f58b..3114ad0667 100644 --- a/specs/v2/api.html +++ b/specs/v2/api.html @@ -926,13 +926,6 @@ sessionID -> { directory, workspaceID? } POST /api/session/:sessionID/prompt Create a user message and queue the agent loop. - - session.todo - { sessionID: SessionID } - session - GET /api/session/:sessionID/todo - Return todos associated with the session. - session.update @@ -1143,7 +1136,6 @@ type SyncStore = { session: Record<SessionID, Session & { context: RuntimeContext }> session_diff: Record<SessionID, Snapshot.FileDiff[]> - todo: Record<SessionID, Todo[]> permission: Record<SessionID, PermissionRequest[]> question: Record<SessionID, QuestionRequest[]> diff --git a/specs/v2/schema-changelog.md b/specs/v2/schema-changelog.md index fa7170ffbd..3821248161 100644 --- a/specs/v2/schema-changelog.md +++ b/specs/v2/schema-changelog.md @@ -384,7 +384,7 @@ Change: - Add Location-scoped pending permission requests with `once`, `always`, and `reject` replies. - Attach optional originating tool message and call IDs. - Preserve authored ordered rules and saved approvals as separate inputs to evaluation. -- Establish action and resource conventions for `read`, `glob`, `grep`, `edit`, `external_directory`, `bash`, `todowrite`, and `webfetch` approvals. +- Establish action and resource conventions for `read`, `glob`, `grep`, `edit`, `external_directory`, `bash`, and `webfetch` approvals. Reason: @@ -580,37 +580,15 @@ Compatibility: - These are additive experimental V2 contracts. - No database migration is required because pending questions are intentionally in-memory Location state. -## 2026-06-03: Core-Owned Todo Update Event - -Affected schema: - -- Core-owned `SessionTodo.Info`. -- Global `todo.updated` event registration. - -Change: - -- Register the todo update event from Core session-todo ownership and expose the existing todo item shape to the Core V2 tool. - -Reason: - -- Embedded V2 `todowrite` execution needs Core-owned persistence and update publication without importing legacy application orchestration. - -Compatibility: - -- The todo table and public todo update event shape are preserved. -- No database migration is required. - ## 2026-06-03: Added Core V2 Tool Schemas Affected schema: -- New `todowrite` tool parameters and success payload. - New `question` tool parameters and success payload. - New `webfetch` tool parameters and success payload. Change: -- Add a todo replacement-list tool using `SessionTodo.Info` items. - Add a question tool using ordered `QuestionV2.Prompt` values and ordered answer arrays. - Add an HTTP(S) fetch tool with explicit `text`, `markdown`, and `html` formats, bounded timeout input, and optional managed output resource metadata.