diff --git a/packages/types/npm/package.json b/packages/types/npm/package.json index 76bc0eb4e4..924e5251cb 100644 --- a/packages/types/npm/package.json +++ b/packages/types/npm/package.json @@ -1,6 +1,6 @@ { "name": "@roo-code/types", - "version": "1.34.0", + "version": "1.35.0", "description": "TypeScript type definitions for Roo Code.", "publishConfig": { "access": "public", diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index cf163e26a6..129ddebdd5 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -51,6 +51,7 @@ export const globalSettingsSchema = z.object({ allowedCommands: z.array(z.string()).optional(), deniedCommands: z.array(z.string()).optional(), commandExecutionTimeout: z.number().optional(), + preventCompletionWithOpenTodos: z.boolean().optional(), allowedMaxRequests: z.number().nullish(), autoCondenseContext: z.boolean().optional(), autoCondenseContextPercent: z.number().optional(), @@ -202,6 +203,7 @@ export const EVALS_SETTINGS: RooCodeSettings = { followupAutoApproveTimeoutMs: 0, allowedCommands: ["*"], commandExecutionTimeout: 30_000, + preventCompletionWithOpenTodos: false, browserToolEnabled: false, browserViewportSize: "900x600", diff --git a/src/core/tools/__tests__/attemptCompletionTool.spec.ts b/src/core/tools/__tests__/attemptCompletionTool.spec.ts new file mode 100644 index 0000000000..b39c1acac6 --- /dev/null +++ b/src/core/tools/__tests__/attemptCompletionTool.spec.ts @@ -0,0 +1,412 @@ +import { describe, it, expect, vi, beforeEach } from "vitest" +import { TodoItem } from "@roo-code/types" +import { AttemptCompletionToolUse } from "../../../shared/tools" + +// Mock the formatResponse module before importing the tool +vi.mock("../../prompts/responses", () => ({ + formatResponse: { + toolError: vi.fn((msg: string) => `Error: ${msg}`), + }, +})) + +// Mock vscode module +vi.mock("vscode", () => ({ + workspace: { + getConfiguration: vi.fn(() => ({ + get: vi.fn(), + })), + }, +})) + +// Mock Package module +vi.mock("../../../shared/package", () => ({ + Package: { + name: "roo-cline", + }, +})) + +import { attemptCompletionTool } from "../attemptCompletionTool" +import { Task } from "../../task/Task" +import * as vscode from "vscode" + +describe("attemptCompletionTool", () => { + let mockTask: Partial + let mockPushToolResult: ReturnType + let mockAskApproval: ReturnType + let mockHandleError: ReturnType + let mockRemoveClosingTag: ReturnType + let mockToolDescription: ReturnType + let mockAskFinishSubTaskApproval: ReturnType + let mockGetConfiguration: ReturnType + + beforeEach(() => { + mockPushToolResult = vi.fn() + mockAskApproval = vi.fn() + mockHandleError = vi.fn() + mockRemoveClosingTag = vi.fn() + mockToolDescription = vi.fn() + mockAskFinishSubTaskApproval = vi.fn() + mockGetConfiguration = vi.fn(() => ({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return defaultValue // Default to false unless overridden in test + } + return defaultValue + }), + })) + + // Setup vscode mock + vi.mocked(vscode.workspace.getConfiguration).mockImplementation(mockGetConfiguration) + + mockTask = { + consecutiveMistakeCount: 0, + recordToolError: vi.fn(), + todoList: undefined, + } + }) + + describe("todo list validation", () => { + it("should allow completion when there is no todo list", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + mockTask.todoList = undefined + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + // Should not call pushToolResult with an error for empty todo list + expect(mockTask.consecutiveMistakeCount).toBe(0) + expect(mockTask.recordToolError).not.toHaveBeenCalled() + }) + + it("should allow completion when todo list is empty", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + mockTask.todoList = [] + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + expect(mockTask.consecutiveMistakeCount).toBe(0) + expect(mockTask.recordToolError).not.toHaveBeenCalled() + }) + + it("should allow completion when all todos are completed", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const completedTodos: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "completed" }, + ] + + mockTask.todoList = completedTodos + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + expect(mockTask.consecutiveMistakeCount).toBe(0) + expect(mockTask.recordToolError).not.toHaveBeenCalled() + }) + + it("should prevent completion when there are pending todos", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const todosWithPending: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "pending" }, + ] + + mockTask.todoList = todosWithPending + + // Enable the setting to prevent completion with open todos + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return true // Setting is enabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + expect(mockTask.consecutiveMistakeCount).toBe(1) + expect(mockTask.recordToolError).toHaveBeenCalledWith("attempt_completion") + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + + it("should prevent completion when there are in-progress todos", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const todosWithInProgress: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "in_progress" }, + ] + + mockTask.todoList = todosWithInProgress + + // Enable the setting to prevent completion with open todos + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return true // Setting is enabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + expect(mockTask.consecutiveMistakeCount).toBe(1) + expect(mockTask.recordToolError).toHaveBeenCalledWith("attempt_completion") + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + + it("should prevent completion when there are mixed incomplete todos", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const mixedTodos: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "pending" }, + { id: "3", content: "Third task", status: "in_progress" }, + ] + + mockTask.todoList = mixedTodos + + // Enable the setting to prevent completion with open todos + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return true // Setting is enabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + expect(mockTask.consecutiveMistakeCount).toBe(1) + expect(mockTask.recordToolError).toHaveBeenCalledWith("attempt_completion") + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + + it("should allow completion when setting is disabled even with incomplete todos", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const todosWithPending: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "pending" }, + ] + + mockTask.todoList = todosWithPending + + // Ensure the setting is disabled (default behavior) + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return false // Setting is disabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + // Should not prevent completion when setting is disabled + expect(mockTask.consecutiveMistakeCount).toBe(0) + expect(mockTask.recordToolError).not.toHaveBeenCalled() + expect(mockPushToolResult).not.toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + + it("should prevent completion when setting is enabled with incomplete todos", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const todosWithPending: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "pending" }, + ] + + mockTask.todoList = todosWithPending + + // Enable the setting + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return true // Setting is enabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + // Should prevent completion when setting is enabled and there are incomplete todos + expect(mockTask.consecutiveMistakeCount).toBe(1) + expect(mockTask.recordToolError).toHaveBeenCalledWith("attempt_completion") + expect(mockPushToolResult).toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + + it("should allow completion when setting is enabled but all todos are completed", async () => { + const block: AttemptCompletionToolUse = { + type: "tool_use", + name: "attempt_completion", + params: { result: "Task completed successfully" }, + partial: false, + } + + const completedTodos: TodoItem[] = [ + { id: "1", content: "First task", status: "completed" }, + { id: "2", content: "Second task", status: "completed" }, + ] + + mockTask.todoList = completedTodos + + // Enable the setting + mockGetConfiguration.mockReturnValue({ + get: vi.fn((key: string, defaultValue: any) => { + if (key === "preventCompletionWithOpenTodos") { + return true // Setting is enabled + } + return defaultValue + }), + }) + + await attemptCompletionTool( + mockTask as Task, + block, + mockAskApproval, + mockHandleError, + mockPushToolResult, + mockRemoveClosingTag, + mockToolDescription, + mockAskFinishSubTaskApproval, + ) + + // Should allow completion when setting is enabled but all todos are completed + expect(mockTask.consecutiveMistakeCount).toBe(0) + expect(mockTask.recordToolError).not.toHaveBeenCalled() + expect(mockPushToolResult).not.toHaveBeenCalledWith( + expect.stringContaining("Cannot complete task while there are incomplete todos"), + ) + }) + }) +}) diff --git a/src/core/tools/attemptCompletionTool.ts b/src/core/tools/attemptCompletionTool.ts index 57f5870022..ef7881854f 100644 --- a/src/core/tools/attemptCompletionTool.ts +++ b/src/core/tools/attemptCompletionTool.ts @@ -1,4 +1,5 @@ import Anthropic from "@anthropic-ai/sdk" +import * as vscode from "vscode" import { TelemetryService } from "@roo-code/telemetry" @@ -14,6 +15,7 @@ import { AskFinishSubTaskApproval, } from "../../shared/tools" import { formatResponse } from "../prompts/responses" +import { Package } from "../../shared/package" export async function attemptCompletionTool( cline: Task, @@ -28,6 +30,25 @@ export async function attemptCompletionTool( const result: string | undefined = block.params.result const command: string | undefined = block.params.command + // Get the setting for preventing completion with open todos from VSCode configuration + const preventCompletionWithOpenTodos = vscode.workspace + .getConfiguration(Package.name) + .get("preventCompletionWithOpenTodos", false) + + // Check if there are incomplete todos (only if the setting is enabled) + const hasIncompleteTodos = cline.todoList && cline.todoList.some((todo) => todo.status !== "completed") + + if (preventCompletionWithOpenTodos && hasIncompleteTodos) { + cline.consecutiveMistakeCount++ + cline.recordToolError("attempt_completion") + pushToolResult( + formatResponse.toolError( + "Cannot complete task while there are incomplete todos. Please finish all todos before attempting completion.", + ), + ) + return + } + try { const lastMessage = cline.clineMessages.at(-1) diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index 772156286e..633208d4bc 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Esteu segur que voleu suprimir aquest mode personalitzat?", "confirm": "Suprimeix" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Evitar la finalització de tasques quan hi ha todos incomplets a la llista de todos" + } } } diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index c136fba809..71155b1ebe 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Bist du sicher, dass du diesen benutzerdefinierten Modus löschen möchtest?", "confirm": "Löschen" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Aufgabenabschluss verhindern, wenn unvollständige Todos in der Todo-Liste vorhanden sind" + } } } diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index b0fdb9d8df..6bab0ab9a9 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -155,5 +155,10 @@ "descriptionNoRules": "Are you sure you want to delete this custom mode?", "confirm": "Delete" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Prevent task completion when there are incomplete todos in the todo list" + } } } diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 39cf48383e..d307800c79 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "¿Estás seguro de que quieres eliminar este modo personalizado?", "confirm": "Eliminar" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Prevenir la finalización de tareas cuando hay todos incompletos en la lista de todos" + } } } diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index ace5bbe47a..b0571e3714 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Êtes-vous sûr de vouloir supprimer ce mode personnalisé ?", "confirm": "Supprimer" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Empêcher la finalisation des tâches lorsqu'il y a des todos incomplets dans la liste de todos" + } } } diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index 84dbe9052a..ca4efea535 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "क्या आप वाकई इस कस्टम मोड को हटाना चाहते हैं?", "confirm": "हटाएं" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "जब टूडू सूची में अधूरे टूडू हों तो कार्य पूर्ण होने से रोकें" + } } } diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index fb2a30994e..46ce587e61 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Anda yakin ingin menghapus mode kustom ini?", "confirm": "Hapus" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Mencegah penyelesaian tugas ketika ada todo yang belum selesai dalam daftar todo" + } } } diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 4681612e9d..11bae26eb3 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Sei sicuro di voler eliminare questa modalità personalizzata?", "confirm": "Elimina" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Impedire il completamento delle attività quando ci sono todo incompleti nella lista dei todo" + } } } diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index 38fc9d27c5..52ab094633 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "このカスタムモードを削除してもよろしいですか?", "confirm": "削除" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Todoリストに未完了のTodoがある場合、タスクの完了を防ぐ" + } } } diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index d76a82a7c2..63566f946b 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "이 사용자 정의 모드를 삭제하시겠습니까?", "confirm": "삭제" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "할 일 목록에 미완료된 할 일이 있을 때 작업 완료를 방지" + } } } diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index 5caa0534ee..fc3c1ce018 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Weet je zeker dat je deze aangepaste modus wilt verwijderen?", "confirm": "Verwijderen" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Voorkom taakafronding wanneer er onvolledige todos in de todolijst staan" + } } } diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 77008aa0ab..ef756ec1ce 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Czy na pewno chcesz usunąć ten tryb niestandardowy?", "confirm": "Usuń" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Zapobiegaj ukończeniu zadania gdy na liście zadań są nieukończone zadania" + } } } diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index 6f63d9d1ed..8856e541be 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Tem certeza de que deseja excluir este modo personalizado?", "confirm": "Excluir" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Impedir a conclusão de tarefas quando há todos incompletos na lista de todos" + } } } diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 4e354bcbc5..fd23dffe2a 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Вы уверены, что хотите удалить этот пользовательский режим?", "confirm": "Удалить" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Предотвратить завершение задач при наличии незавершенных дел в списке дел" + } } } diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index 5de82d00c6..9eeae720ef 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "Bu özel modu silmek istediğinizden emin misiniz?", "confirm": "Sil" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Todo listesinde tamamlanmamış todolar olduğunda görev tamamlanmasını engelle" + } } } diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index 014bddda58..bd66d623bb 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -173,5 +173,10 @@ "descriptionNoRules": "Bạn có chắc chắn muốn xóa chế độ tùy chỉnh này không?", "confirm": "Xóa" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "Ngăn chặn hoàn thành nhiệm vụ khi có các todo chưa hoàn thành trong danh sách todo" + } } } diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 268ee5fbb1..515ee7d048 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -171,5 +171,10 @@ "descriptionNoRules": "您确定要删除此自定义模式吗?", "confirm": "删除" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "当待办事项列表中有未完成的待办事项时阻止任务完成" + } } } diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index dec20a1f9a..cceb53e5f3 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -166,5 +166,10 @@ "descriptionNoRules": "您確定要刪除此自訂模式嗎?", "confirm": "刪除" } + }, + "commands": { + "preventCompletionWithOpenTodos": { + "description": "當待辦事項清單中有未完成的待辦事項時阻止工作完成" + } } } diff --git a/src/package.json b/src/package.json index 5cf8727545..448463b750 100644 --- a/src/package.json +++ b/src/package.json @@ -345,6 +345,11 @@ "maximum": 600, "description": "%commands.commandExecutionTimeout.description%" }, + "roo-cline.preventCompletionWithOpenTodos": { + "type": "boolean", + "default": false, + "description": "%commands.preventCompletionWithOpenTodos.description%" + }, "roo-cline.vsCodeLmModelSelector": { "type": "object", "properties": { diff --git a/src/package.nls.json b/src/package.nls.json index c5225c45c8..b52f2d11c2 100644 --- a/src/package.nls.json +++ b/src/package.nls.json @@ -29,6 +29,7 @@ "commands.allowedCommands.description": "Commands that can be auto-executed when 'Always approve execute operations' is enabled", "commands.deniedCommands.description": "Command prefixes that will be automatically denied without asking for approval. In case of conflicts with allowed commands, the longest prefix match takes precedence. Add * to deny all commands.", "commands.commandExecutionTimeout.description": "Maximum time in seconds to wait for command execution to complete before timing out (0 = no timeout, 1-600s, default: 0s)", + "commands.preventCompletionWithOpenTodos.description": "Prevent task completion when there are incomplete todos in the todo list", "settings.vsCodeLmModelSelector.description": "Settings for VSCode Language Model API", "settings.vsCodeLmModelSelector.vendor.description": "The vendor of the language model (e.g. copilot)", "settings.vsCodeLmModelSelector.family.description": "The family of the language model (e.g. gpt-4)",