From 7feefb697f279fe08677512f08abf72a9f418d5a Mon Sep 17 00:00:00 2001 From: Aiden Cline <63023139+rekram1-node@users.noreply.github.com> Date: Thu, 9 Jul 2026 00:13:48 -0500 Subject: [PATCH] refactor: remove todo tool (#35989) --- github/index.ts | 1 - .../timeline-stability/tools.spec.ts | 4 - .../session-timeline-stress.fixture.ts | 1 - .../regression/cross-server-tab-close.spec.ts | 2 +- .../e2e/regression/remote-tab-busy.spec.ts | 2 +- .../session-timeline-projection.spec.ts | 2 - .../session-timeline-tool-projection.spec.ts | 2 - .../session-todo-dock-navigation.spec.ts | 186 ------ .../regression/tab-navigate-mousedown.spec.ts | 2 +- .../app/e2e/smoke/session-timeline.fixture.ts | 1 - packages/app/e2e/utils/mock-server.ts | 3 - .../src/components/prompt-input.stories.tsx | 99 --- .../app/src/components/prompt-input/submit.ts | 2 - packages/app/src/context/directory-sync.ts | 2 - .../src/context/global-sync/bootstrap.test.ts | 1 - .../src/context/global-sync/child-store.ts | 1 - .../context/global-sync/event-reducer.test.ts | 13 - .../src/context/global-sync/event-reducer.ts | 35 +- .../context/global-sync/session-cache.test.ts | 6 - .../src/context/global-sync/session-cache.ts | 3 - packages/app/src/context/global-sync/types.ts | 4 - packages/app/src/context/layout.tsx | 13 - .../app/src/context/server-session.test.ts | 1 - packages/app/src/context/server-session.ts | 25 +- packages/app/src/i18n/ar.ts | 6 - packages/app/src/i18n/br.ts | 6 - packages/app/src/i18n/bs.ts | 6 - packages/app/src/i18n/da.ts | 6 - packages/app/src/i18n/de.ts | 6 - packages/app/src/i18n/en.ts | 6 - packages/app/src/i18n/es.ts | 6 - packages/app/src/i18n/fr.ts | 6 - packages/app/src/i18n/ja.ts | 6 - packages/app/src/i18n/ko.ts | 6 - packages/app/src/i18n/no.ts | 6 - packages/app/src/i18n/pl.ts | 6 - packages/app/src/i18n/ru.ts | 6 - packages/app/src/i18n/th.ts | 6 - packages/app/src/i18n/tr.ts | 6 - packages/app/src/i18n/uk.ts | 6 - packages/app/src/i18n/zh.ts | 6 - packages/app/src/i18n/zht.ts | 6 - packages/app/src/pages/session.tsx | 44 -- .../session-composer-region-controller.ts | 69 +- .../composer/session-composer-region.tsx | 34 +- .../composer/session-composer-state.test.ts | 33 - .../composer/session-composer-state.ts | 137 +--- .../session/composer/session-todo-dock.tsx | 256 ------- .../composer/todo-panel-motion.stories.tsx | 623 ------------------ packages/cli/src/mini/demo.ts | 35 +- packages/cli/src/mini/scrollback.writer.tsx | 43 -- packages/cli/src/mini/tool.ts | 92 --- packages/cli/src/mini/types.ts | 16 +- .../client/src/promise/generated/types.ts | 11 - .../test/fixtures/opencode-v2-openapi.json | 149 ++--- packages/core/schema.json | 117 +--- packages/core/src/database/migration.gen.ts | 1 + .../migration/20260709025533_drop-todo.ts | 12 + packages/core/src/database/schema.gen.ts | 14 - packages/core/src/location-services.ts | 2 - packages/core/src/plugin/agent.ts | 7 +- packages/core/src/plugin/internal.ts | 5 - packages/core/src/plugin/supervisor.ts | 2 - .../src/session/runner/prompt/anthropic.txt | 52 -- .../core/src/session/runner/prompt/beast.txt | 15 +- packages/core/src/session/sql.ts | 19 - packages/core/src/session/todo.ts | 78 --- packages/core/src/tool/todowrite.ts | 57 -- packages/core/src/v1/config/permission.ts | 1 - .../openai-chat-streams-text.json | 2 +- packages/core/test/location-layer.test.ts | 3 - packages/core/test/permission.test.ts | 4 +- packages/core/test/session-todo.test.ts | 94 --- packages/core/test/shared-schema.test.ts | 5 - packages/core/test/tool-todowrite.test.ts | 142 ---- packages/docs/openapi.json | 149 ++--- packages/opencode/specs/effect/tools.md | 1 - packages/opencode/specs/tui-plugins.md | 4 +- packages/opencode/src/agent/agent.ts | 8 +- .../src/agent/subagent-permissions.ts | 6 +- packages/opencode/src/cli/cmd/agent.ts | 14 +- .../opencode/src/cli/cmd/github.handler.ts | 1 - packages/opencode/src/effect/app-runtime.ts | 2 - .../routes/instance/httpapi/groups/session.ts | 14 - .../instance/httpapi/handlers/session.ts | 8 - .../server/routes/instance/httpapi/server.ts | 2 - .../opencode/src/session/prompt/anthropic.txt | 53 -- .../opencode/src/session/prompt/beast.txt | 12 +- .../src/session/prompt/copilot-gpt-5.txt | 8 +- packages/opencode/src/session/todo.ts | 74 --- packages/opencode/src/storage/schema.ts | 2 +- packages/opencode/src/tool/registry.ts | 6 - packages/opencode/src/tool/task.ts | 3 - packages/opencode/src/tool/todo.ts | 46 -- packages/opencode/src/tool/todowrite.txt | 44 -- packages/opencode/test/agent/agent.test.ts | 11 - .../opencode/test/cli/github-action.test.ts | 5 +- .../__snapshots__/help-snapshots.test.ts.snap | 4 +- .../test/cli/run/scrollback.surface.test.ts | 44 +- .../test/cli/tui/plugin-loader.test.ts | 9 - packages/opencode/test/config/config.test.ts | 2 - packages/opencode/test/event-manifest.test.ts | 4 +- packages/opencode/test/fixture/tui-plugin.ts | 1 - .../test/server/httpapi-exercise/index.ts | 17 - .../test/server/httpapi-exercise/runner.ts | 1 - .../test/server/httpapi-exercise/runtime.ts | 3 - .../test/server/httpapi-exercise/types.ts | 6 - .../opencode/test/server/httpapi-sdk.test.ts | 3 - .../test/server/httpapi-session.test.ts | 8 - packages/opencode/test/session/prompt.test.ts | 2 - .../test/session/schema-decoding.test.ts | 10 - .../__snapshots__/parameters.test.ts.snap | 38 -- .../opencode/test/tool/parameters.test.ts | 14 - packages/opencode/test/tool/task.test.ts | 7 +- packages/plugin/src/tui.ts | 4 - packages/schema/AGENTS.md | 4 +- packages/schema/src/event-manifest.ts | 3 - packages/schema/src/session-todo.ts | 25 - packages/schema/test/contract-hygiene.test.ts | 10 - packages/schema/test/event-manifest.test.ts | 2 - packages/sdk/js/src/gen/sdk.gen.ts | 13 - packages/sdk/js/src/gen/types.gen.ts | 64 -- packages/sdk/js/src/v2/gen/sdk.gen.ts | 34 - packages/sdk/js/src/v2/gen/types.gen.ts | 98 --- packages/sdk/openapi.json | 230 ------- .../src/components/message-part.css | 26 - .../src/components/message-part.tsx | 63 -- .../src/components/session-turn.tsx | 3 - .../timeline-playground.stories.tsx | 19 - .../.storybook/mocks/app/context/file.ts | 8 +- .../mocks/app/context/global-sync.ts | 7 - .../.storybook/mocks/app/context/language.ts | 3 - packages/tui/src/component/todo-item.tsx | 32 - packages/tui/src/context/sync.tsx | 3 - packages/tui/src/feature-plugins/builtins.ts | 2 - .../tui/src/feature-plugins/sidebar/todo.tsx | 49 -- packages/tui/src/plugin/adapters.tsx | 3 - packages/tui/src/routes/session/index.tsx | 41 -- .../tui/inline-tool-wrap-snapshot.test.tsx | 4 - packages/ui/src/i18n/ar.ts | 2 - packages/ui/src/i18n/br.ts | 2 - packages/ui/src/i18n/bs.ts | 2 - packages/ui/src/i18n/da.ts | 2 - packages/ui/src/i18n/de.ts | 2 - packages/ui/src/i18n/en.ts | 2 - packages/ui/src/i18n/es.ts | 2 - packages/ui/src/i18n/fr.ts | 2 - packages/ui/src/i18n/ja.ts | 2 - packages/ui/src/i18n/ko.ts | 2 - packages/ui/src/i18n/no.ts | 2 - packages/ui/src/i18n/pl.ts | 2 - packages/ui/src/i18n/ru.ts | 2 - packages/ui/src/i18n/th.ts | 2 - packages/ui/src/i18n/tr.ts | 2 - packages/ui/src/i18n/uk.ts | 2 - packages/ui/src/i18n/zh.ts | 2 - packages/ui/src/i18n/zht.ts | 2 - packages/web/src/components/share.module.css | 82 --- .../web/src/components/share/part.module.css | 82 --- packages/web/src/components/share/part.tsx | 58 -- packages/web/src/content/docs/agents.mdx | 3 +- packages/web/src/content/docs/ar/agents.mdx | 2 +- packages/web/src/content/docs/ar/plugins.mdx | 4 - packages/web/src/content/docs/ar/server.mdx | 39 +- packages/web/src/content/docs/ar/tools.mdx | 21 - packages/web/src/content/docs/bs/agents.mdx | 2 +- packages/web/src/content/docs/bs/plugins.mdx | 4 - packages/web/src/content/docs/bs/server.mdx | 1 - packages/web/src/content/docs/bs/tools.mdx | 21 - packages/web/src/content/docs/cli.mdx | 14 +- packages/web/src/content/docs/da/agents.mdx | 2 +- packages/web/src/content/docs/da/plugins.mdx | 4 - packages/web/src/content/docs/da/server.mdx | 1 - packages/web/src/content/docs/da/tools.mdx | 21 - packages/web/src/content/docs/de/agents.mdx | 2 +- packages/web/src/content/docs/de/plugins.mdx | 4 - packages/web/src/content/docs/de/server.mdx | 1 - packages/web/src/content/docs/de/tools.mdx | 21 - packages/web/src/content/docs/es/plugins.mdx | 4 - packages/web/src/content/docs/es/server.mdx | 1 - packages/web/src/content/docs/es/tools.mdx | 21 - packages/web/src/content/docs/fr/agents.mdx | 2 +- packages/web/src/content/docs/fr/plugins.mdx | 4 - packages/web/src/content/docs/fr/server.mdx | 1 - packages/web/src/content/docs/fr/tools.mdx | 21 - packages/web/src/content/docs/it/agents.mdx | 2 +- packages/web/src/content/docs/it/plugins.mdx | 4 - packages/web/src/content/docs/it/server.mdx | 1 - packages/web/src/content/docs/it/tools.mdx | 21 - packages/web/src/content/docs/ja/agents.mdx | 2 +- packages/web/src/content/docs/ja/plugins.mdx | 4 - packages/web/src/content/docs/ja/server.mdx | 1 - packages/web/src/content/docs/ja/tools.mdx | 21 - packages/web/src/content/docs/ko/agents.mdx | 2 +- packages/web/src/content/docs/ko/plugins.mdx | 4 - packages/web/src/content/docs/ko/server.mdx | 1 - packages/web/src/content/docs/ko/tools.mdx | 21 - packages/web/src/content/docs/nb/agents.mdx | 2 +- packages/web/src/content/docs/nb/plugins.mdx | 4 - packages/web/src/content/docs/nb/server.mdx | 1 - packages/web/src/content/docs/nb/tools.mdx | 21 - packages/web/src/content/docs/pl/plugins.mdx | 4 - packages/web/src/content/docs/pl/server.mdx | 1 - packages/web/src/content/docs/pl/tools.mdx | 21 - packages/web/src/content/docs/plugins.mdx | 4 - .../web/src/content/docs/pt-br/agents.mdx | 2 +- .../web/src/content/docs/pt-br/plugins.mdx | 4 - .../web/src/content/docs/pt-br/server.mdx | 1 - packages/web/src/content/docs/pt-br/tools.mdx | 21 - packages/web/src/content/docs/ru/plugins.mdx | 4 - packages/web/src/content/docs/ru/server.mdx | 1 - packages/web/src/content/docs/ru/tools.mdx | 21 - packages/web/src/content/docs/server.mdx | 1 - packages/web/src/content/docs/th/plugins.mdx | 4 - packages/web/src/content/docs/th/server.mdx | 1 - packages/web/src/content/docs/th/tools.mdx | 21 - packages/web/src/content/docs/tools.mdx | 21 - packages/web/src/content/docs/tr/plugins.mdx | 4 - packages/web/src/content/docs/tr/server.mdx | 1 - packages/web/src/content/docs/tr/tools.mdx | 21 - .../web/src/content/docs/zh-cn/agents.mdx | 2 +- .../web/src/content/docs/zh-cn/plugins.mdx | 4 - .../web/src/content/docs/zh-cn/server.mdx | 1 - packages/web/src/content/docs/zh-cn/tools.mdx | 21 - .../web/src/content/docs/zh-tw/agents.mdx | 2 +- .../web/src/content/docs/zh-tw/plugins.mdx | 4 - .../web/src/content/docs/zh-tw/server.mdx | 1 - packages/web/src/content/docs/zh-tw/tools.mdx | 21 - packages/web/src/content/i18n/ar.json | 3 - packages/web/src/content/i18n/bs.json | 3 - packages/web/src/content/i18n/da.json | 3 - packages/web/src/content/i18n/de.json | 3 - packages/web/src/content/i18n/en.json | 3 - packages/web/src/content/i18n/es.json | 3 - packages/web/src/content/i18n/fr.json | 3 - packages/web/src/content/i18n/it.json | 3 - packages/web/src/content/i18n/ja.json | 3 - packages/web/src/content/i18n/ko.json | 3 - packages/web/src/content/i18n/nb.json | 3 - packages/web/src/content/i18n/pl.json | 3 - packages/web/src/content/i18n/pt-BR.json | 3 - packages/web/src/content/i18n/ru.json | 3 - packages/web/src/content/i18n/th.json | 3 - packages/web/src/content/i18n/tr.json | 3 - packages/web/src/content/i18n/zh-CN.json | 3 - packages/web/src/content/i18n/zh-TW.json | 3 - packages/web/src/pages/s/[id].astro | 3 - specs/storage/remove-opencode-db.md | 9 +- specs/v2/api.html | 8 - specs/v2/schema-changelog.md | 24 +- 250 files changed, 237 insertions(+), 4755 deletions(-) delete mode 100644 packages/app/e2e/regression/session-todo-dock-navigation.spec.ts delete mode 100644 packages/app/src/pages/session/composer/session-todo-dock.tsx delete mode 100644 packages/app/src/pages/session/composer/todo-panel-motion.stories.tsx create mode 100644 packages/core/src/database/migration/20260709025533_drop-todo.ts delete mode 100644 packages/core/src/session/todo.ts delete mode 100644 packages/core/src/tool/todowrite.ts delete mode 100644 packages/core/test/session-todo.test.ts delete mode 100644 packages/core/test/tool-todowrite.test.ts delete mode 100644 packages/opencode/src/session/todo.ts delete mode 100644 packages/opencode/src/tool/todo.ts delete mode 100644 packages/opencode/src/tool/todowrite.txt delete mode 100644 packages/schema/src/session-todo.ts delete mode 100644 packages/tui/src/component/todo-item.tsx delete mode 100644 packages/tui/src/feature-plugins/sidebar/todo.tsx diff --git a/github/index.ts b/github/index.ts index 4e1af9cf5..e8acd9a9c 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 d28fdaa65..d26968e1c 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 e6fdd5d47..2e20d9841 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 159b5a506..9fd799143 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 119fc7ee2..ad7e2e1d9 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 b6679ab4e..45304df36 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 071b03007..4c2c1c4ea 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 603c411d5..000000000 --- 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 94afbc9a9..6bc417af8 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 ff857d817..beb2d7cf7 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 53adfd155..c69382bba 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 362a74140..272079e10 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 05d978a94..cba1e4c88 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 68e6b19ce..7ccd6e975 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 40735fb82..872f0929c 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 53b953618..66e40f66e 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 2811e6e3c..8e2113709 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 40b7acbbd..935fc14e3 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 3dda5a542..41034186e 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 39535abe2..6f2c3dc54 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 46a0dc826..fb4443a3e 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 a46eb744d..12c3d8abb 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 c60920d10..b82435440 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 12911744e..f431dbc8f 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 086ecc1b4..e5d48e5d1 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 859bea230..8435d9e37 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 c96dc232a..2895f5783 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 3da8183bb..559c6ba17 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 5ef7862cd..ec6205cf9 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 77a543180..c5da26534 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 24d1a29e8..435def9b1 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 cf789f564..c6e7f142b 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 f3faa3138..e066ff379 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 295d8e615..9bc10269f 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 7ef78bb48..466f18b1c 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 686db7407..cd42cc46d 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 b578f89cc..c3cc62c94 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 ff18c8e34..f4bc44eb2 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 3cccc0c82..bd12a9dba 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 afe285f6e..b2a1a6f3a 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 2d06109bd..bbbadb756 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 4073f1c19..ff425b4c2 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 600ff41e3..feb2b0aee 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 45f5e4cb2..eb282c15f 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 f68428fcd..000000000 --- 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 61cfaf931..000000000 --- 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 ed0b6878f..93790ce65 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 be814dbbf..74f4a97ad 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 9eb8782a1..9c13d1ee2 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 00f8d8dae..0e3b4bea3 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 45e44c521..c61fdb5ee 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 c2cd5a1d2..543a41817 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 acfa072f6..77884cc9f 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 e2f17df56..70cbfca73 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 000000000..1557f889b --- /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 bc7cc5f7a..d175f7cf7 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 7e52aea14..2da72df1d 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 e6e03a4f1..8b94e219a 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 ad5553928..9b75645db 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 5b29d643a..0dd3a31d7 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 0fdf700d5..1df6f4d69 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 e92e4d020..a0a927a6d 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 e8cdebd90..bdc7b0796 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 56c73042c..000000000 --- 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 96c0f10f1..000000000 --- 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 475dc7bbf..ef2da34e9 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 ff501af21..90154112d 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 60e788f7b..34288c042 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 9bc045329..669fb4d96 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 9b848f827..000000000 --- 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 61b03b748..8cbe9f9e2 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 055df2fbc..000000000 --- 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 c2cd5a1d2..543a41817 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 61b8aa40d..862b58270 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 06f7757d5..9dd593242 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 5c819e521..6d4a7599d 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 b1b99b484..596b30a17 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 c9c1d2c16..076160b41 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 d55c0bf3f..edaecb7b5 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 19328e73c..1ebed3b47 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 959a303dc..4fb08281c 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 662585020..f0478b6fb 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 108888d4f..471d9aa37 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 21d9c0e9f..a816861b2 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 e92e4d020..193bd05c5 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 d8da6d201..d7a777678 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 cd80828de..000000000 --- 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 06d095f06..450ccb43d 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 037cf236d..4576bd7a8 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 4039fd36f..c753d1771 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 69fb0550e..000000000 --- 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 a21630c15..000000000 --- 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 efeaf408a..2e13e26a9 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 57567d8c9..2cf914ed7 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 5c84f0d38..90da1632d 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 abe40559e..039ab156f 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 49ea06aff..c542914ca 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 e281831dd..ac408ea81 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 64755ad44..a54a0c6ac 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 5d93139f0..d94b02e7c 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 195699f9c..b815f5f7d 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 b7ad6d620..37e24b790 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 81bd302a1..b7a3952bd 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 acc1898e3..089521650 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 0af92ae38..a6f308f03 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 a5677d527..4b3e7e3f9 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 9ca8669e8..420bd4932 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 3bcbd55d4..379494822 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 51ff867ea..48c6b5558 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 9c540daad..11db271b9 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 32171789c..fc75c3d72 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 8e2fee590..7c1d321ed 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 400b4b312..f079b42a2 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 035f72568..386d75034 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 f4d68268f..000000000 --- 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 23f6521da..140be20cb 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 3c31d09c2..80d179ae2 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 5e3e67e1c..4b5d9284c 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 1055d82ce..e9b704b46 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 d26e05ef2..c1ecda15e 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 efa4f18d3..92b9514db 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 a3886cc0c..d5a273ede 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 88779a3c6..b50f0902d 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 f147cd738..f78ba5f30 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 21884c42b..a6d0f11ef 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 53699094a..091e4f655 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 db2158a5c..550d32f5b 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 c538168be..2d7b990ec 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 df28d79fb..731e3f931 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 b54cc4633..000000000 --- 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 40eac011a..c35927d6f 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 569f3db02..0069d5693 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 15a78b0eb..000000000 --- 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 068b51c73..7da68b8e8 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 c95e3834d..8f07f8184 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 8e112e4d1..875de8c91 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 4661ece48..140b24762 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 eac44effd..e59b68aa4 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 0057691b2..92cff0007 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 492652742..a3835c3b4 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 f982766d1..aa2471d52 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 59502b842..53813885d 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 ccf681cc8..4610b607f 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 f22c0f6d5..f25521155 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 f358810fd..0391842e3 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 0ee729adc..21ed01ad7 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 4dbbe03ad..7350210a1 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 80694cdbe..481d6202c 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 10675a28d..c80e7461e 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 5cdebfd6f..e795a03d7 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 abb35c79f..80558833f 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 8a9e18aee..7462eceee 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 19ba8e410..7b8cc1b6e 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 9930e6b57..1af9b5389 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 b1269445f..2cbb20c2d 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 67099196a..b314afc0d 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 53048b792..0c0a5e228 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 af12a6769..4dde97d7d 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 d7c025bbc..031171db8 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 017a81eaf..8b679909b 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 0323e8d8e..687854388 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 a2e211b19..87af54e49 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 7e046cb83..c7d709da3 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 5237873d5..54ba859c3 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 c2d5aa2dd..555343bf2 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 748452136..7c3b1e3d7 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 058f9eec6..7e773c681 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 908c6e111..2b78dd113 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 6eb74d946..51060112f 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 31c980082..d6d1b5d9f 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 6bca53488..ee715bb88 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 57fcdbba6..6b83f116f 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 64322bda8..8a8604390 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 8f5e7c071..29d934df2 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 dc4418072..22f69de57 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 c3ce97421..ca6c0656f 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 5a0cca969..34dfa8515 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 a6b323dfc..c989d8f09 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 48cdc4d11..30a1ff38b 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 a376f4a18..f95a8f14e 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 72edf9819..f462d0edc 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 70aea5753..6faa76a19 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 3fc22a78c..3f1cbbe09 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 df66d39fd..473bb8e7c 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 e3f2f23ce..402c86ef9 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 539d30faf..64e57acf5 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 06a0dca9a..990d4690b 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 cbea87083..8ca98f4d8 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 1473a0b36..a75595128 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 02f31c5b6..b9120d5c7 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 f20eb90c4..27e20a5d5 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 a6914605a..ffd1d947a 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 8fe5ab1d0..7df5cb6cb 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 f9971758d..f5cbf7bc3 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 27d23ec63..ccf8a933d 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 a6ad8c6df..07eb7f58c 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 2e6f61ba0..d23a231d0 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 510c8a22e..75dfd052c 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 0efcf486f..31195b6e8 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 6b8a5eeb4..3b30d3efe 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 a8be79821..b845af67f 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 815264d84..d89addf7a 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 54c5b1ffa..0d809d620 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 6d2e9eb38..1659c5cdc 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 86fd714d3..4635cf06b 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 1d7ffb339..7b2e9cdf9 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 2356543df..d54e7bbdf 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 b34d30465..a84dd0e45 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 4510bd498..8abd2aa08 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 e672715a4..2a913837c 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 13302cf57..53dad053f 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 5006b41de..6be8ef788 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 e8d5e0963..e2ea6c258 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 4926f5f70..9321eef36 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 e9af6afd0..a51608c53 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 29c1e0054..32c35eb66 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 6f821ff7f..b87ce42a5 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 e8a8bd70c..bd1548263 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 d28342ecc..250f12a0a 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 1a58eece5..55607d4d9 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 a9c7bbadb..e67cea395 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 8163c291e..d2ffac538 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 411bc0eb7..1cbb04059 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 763d0ce9a..1d5c3da84 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 d8029441f..1f1b30ae7 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 6dc96ce7f..b393f4eba 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 a375c6713..40a40180c 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 9d6314368..c4d66457b 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 fedb70a6c..8f309c35d 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 a30a7f064..b8eabccd5 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 294badf49..577bdf15b 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 a9ed2b1f8..68eaf4884 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 9ef6851e5..1cebb5e24 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 633665517..3b44bc9aa 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 c91ba2e22..7a21ed5ff 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 8cc874f82..6d4430b4e 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 c7a378131..55df5e346 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 945bc7b0b..b1cb9693b 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 11eb7145c..989b2372e 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 9f3e95aa7..922791489 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 e1c9f0c9e..8970a586f 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 82cc25771..ad26ff98e 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 7ea42f691..85c2d7381 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 071e70c18..54e56167b 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 147d24f58..3114ad066 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 fa7170ffb..382124816 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.