// Force strict mode and setup for ESM
"use strict";
import {
  promptIdContext
} from "./chunk-O6GEWCJA.js";
import {
  detectTodoChanges
} from "./chunk-3APUUXRF.js";
import {
  escapeSystemReminderTags
} from "./chunk-AQ37AY7B.js";
import {
  BaseDeclarativeTool,
  BaseToolInvocation,
  ToolDisplayNames,
  ToolNames
} from "./chunk-MM7TH7ZM.js";
import {
  atomicWriteFile
} from "./chunk-HC45LTEN.js";
import {
  Storage,
  createDebugLogger
} from "./chunk-E2BHWIDT.js";
import "./chunk-QUGAUQGJ.js";
import {
  init_esbuild_shims
} from "./chunk-5O2XNYP6.js";
import {
  __name
} from "./chunk-J2S4EL5Y.js";

// packages/core/src/tools/todoWrite.ts
init_esbuild_shims();
import * as fs from "fs/promises";
import * as fsSync from "fs";
import * as path from "path";
var debugLogger = createDebugLogger("TODO_WRITE");
var MAX_ACTIVE_TODO_CONTEXT_CHARS = 800;
var todoWriteToolSchemaData = {
  name: "todo_write",
  description: "Creates and manages a concise, user-visible task list for complex or multi-step work.",
  parametersJsonSchema: {
    type: "object",
    properties: {
      todos: {
        type: "array",
        items: {
          type: "object",
          properties: {
            content: {
              type: "string",
              minLength: 1
            },
            status: {
              type: "string",
              enum: ["pending", "in_progress", "completed"]
            },
            id: {
              type: "string"
            }
          },
          required: ["content", "status", "id"],
          additionalProperties: false
        },
        description: "The updated todo list"
      }
    },
    required: ["todos"],
    $schema: "http://json-schema.org/draft-07/schema#"
  }
};
var todoWriteToolDescription = `
Use this tool to create and manage a user-visible task list when explicit progress tracking improves clarity.

## When to Use This Tool
Use this tool for work that is complex, ambiguous, or multi-phase; has multiple independent outcomes or important dependencies; benefits from checkpoints; or when the user explicitly asks for a todo list.

Do not use it for simple or single-step work, purely conversational or informational requests, or tasks that can be answered or completed directly unless the user explicitly requests a todo list.

## Planning with Todos

Keep the list short and outcome-oriented. Use a small number of meaningful, logically ordered, verifiable steps. Do not create a separate todo for every error, file, command, or minor edit.

Keep at most one task in_progress. When a plan exists, keep its statuses current, mark finished work completed, revise the plan when the scope or approach changes, and remove items that are no longer relevant. Do not mark incomplete or blocked work completed.
`;
var TODO_SUBDIR = "todos";
function getTodoFilePath(sessionId) {
  const todoDir = path.join(Storage.getRuntimeBaseDir(), TODO_SUBDIR);
  const filename = `${sessionId || "default"}.json`;
  return path.join(todoDir, filename);
}
__name(getTodoFilePath, "getTodoFilePath");
async function readTodosFromFile(sessionId) {
  try {
    const todoFilePath = getTodoFilePath(sessionId);
    const content = await fs.readFile(todoFilePath, "utf-8");
    const data = JSON.parse(content);
    return Array.isArray(data.todos) ? data.todos : [];
  } catch (err) {
    const error = err;
    if (!(error instanceof Error) || error.code !== "ENOENT") {
      throw err;
    }
    return [];
  }
}
__name(readTodosFromFile, "readTodosFromFile");
async function writeTodosToFile(todos, sessionId) {
  const todoFilePath = getTodoFilePath(sessionId);
  const todoDir = path.dirname(todoFilePath);
  await fs.mkdir(todoDir, { recursive: true });
  const data = {
    todos,
    sessionId: sessionId || "default"
  };
  await atomicWriteFile(todoFilePath, JSON.stringify(data, null, 2), {
    encoding: "utf-8"
  });
}
__name(writeTodosToFile, "writeTodosToFile");
function createBlockedTodoResult(message, systemMessage) {
  return {
    llmContent: `${message}

<system-reminder>
${systemMessage}
</system-reminder>`,
    returnDisplay: message
  };
}
__name(createBlockedTodoResult, "createBlockedTodoResult");
var TodoWriteToolInvocation = class extends BaseToolInvocation {
  constructor(config, params, operationType = "update") {
    super(params);
    this.config = config;
    this.operationType = operationType;
  }
  static {
    __name(this, "TodoWriteToolInvocation");
  }
  operationType;
  getDescription() {
    return this.operationType === "create" ? "Create todos" : "Update todos";
  }
  async execute(_signal) {
    const { todos, modified_by_user, modified_content } = this.params;
    const sessionId = this.config.getSessionId();
    try {
      const oldTodos = await readTodosFromFile(sessionId);
      let finalTodos;
      if (modified_by_user && modified_content !== void 0) {
        const data = JSON.parse(modified_content);
        finalTodos = Array.isArray(data.todos) ? data.todos : [];
      } else {
        finalTodos = todos;
      }
      const changes = detectTodoChanges(oldTodos, finalTodos);
      const oldTodosMap = new Map(oldTodos.map((t) => [t.id, t]));
      const hookSystem = this.config.getHookSystem();
      if (hookSystem && changes.created.length > 0) {
        const createdResults = await Promise.all(
          changes.created.map(
            (todo) => hookSystem.fireTodoCreatedEvent(
              todo.id,
              todo.content,
              todo.status,
              finalTodos,
              "validation" /* Validation */,
              _signal
            )
          )
        );
        const blockedCreatedResult = createdResults.find(
          (result) => result.finalOutput?.decision === "block"
        );
        if (blockedCreatedResult?.finalOutput) {
          const reason = blockedCreatedResult.finalOutput.reason || "Hook blocked todo creation";
          return createBlockedTodoResult(
            `Todo creation blocked: ${reason}`,
            `Todo list was not modified because a TodoCreated hook blocked the operation: ${reason}`
          );
        }
      }
      if (hookSystem && changes.completed.length > 0) {
        const completedResults = await Promise.all(
          changes.completed.map((todo) => {
            const oldTodo = oldTodosMap.get(todo.id);
            const previousStatus = oldTodo?.status ?? "pending";
            return hookSystem.fireTodoCompletedEvent(
              todo.id,
              todo.content,
              previousStatus,
              finalTodos,
              "validation" /* Validation */,
              _signal
            );
          })
        );
        const blockedCompletedResult = completedResults.find(
          (result) => result.finalOutput?.decision === "block"
        );
        if (blockedCompletedResult?.finalOutput) {
          const reason = blockedCompletedResult.finalOutput.reason || "Hook blocked todo completion";
          return createBlockedTodoResult(
            `Todo completion blocked: ${reason}`,
            `Todo list was not modified because a TodoCompleted hook blocked the operation: ${reason}`
          );
        }
      }
      await writeTodosToFile(finalTodos, sessionId);
      const unfinishedTodos = finalTodos.filter(
        (todo) => todo.status !== "completed"
      );
      const promptId = promptIdContext.getStore();
      if (promptId) {
        const serializedTodos = escapeSystemReminderTags(
          unfinishedTodos.map((todo) => `- [${todo.status}] ${todo.content}`).join("\n")
        );
        const todoContext = serializedTodos.slice(
          0,
          MAX_ACTIVE_TODO_CONTEXT_CHARS
        );
        this.config.setActiveTodoReminder(
          promptId,
          unfinishedTodos.length > 0 ? `<system-reminder>
The current task still has unfinished todo items:
${todoContext}${serializedTodos.length > todoContext.length ? "\n[truncated]" : ""}
Keep the todo list current and continue the task. Do not treat a successful intermediate tool call as task completion.
</system-reminder>` : void 0
        );
      }
      let postWriteError;
      try {
        if (hookSystem && changes.created.length > 0) {
          for (const todo of changes.created) {
            await hookSystem.fireTodoCreatedEvent(
              todo.id,
              todo.content,
              todo.status,
              finalTodos,
              "postWrite" /* PostWrite */,
              _signal
            );
          }
        }
        if (hookSystem && changes.completed.length > 0) {
          for (const todo of changes.completed) {
            const oldTodo = oldTodosMap.get(todo.id);
            const previousStatus = oldTodo?.status ?? "pending";
            await hookSystem.fireTodoCompletedEvent(
              todo.id,
              todo.content,
              previousStatus,
              finalTodos,
              "postWrite" /* PostWrite */,
              _signal
            );
          }
        }
      } catch (error) {
        postWriteError = error instanceof Error ? error : new Error(String(error));
        debugLogger.error(
          `[TodoWriteTool] Post-write hooks failed after todos were persisted: ${postWriteError.message}`
        );
      }
      const todoResultDisplay = {
        type: "todo_list",
        todos: finalTodos,
        changes
      };
      const todosJson = JSON.stringify(finalTodos);
      let llmContent;
      const postWriteReminder = postWriteError ? `

<system-reminder>
Todos were persisted successfully, but post-write hooks failed with error: ${postWriteError.message}. Do not tell the user the write failed; only handle any follow-up hook issues if needed.
</system-reminder>` : "";
      if (finalTodos.length === 0) {
        llmContent = `Todo list has been cleared.

<system-reminder>
Your todo list is now empty. DO NOT mention this explicitly to the user. You have no pending tasks in your todo list.
</system-reminder>${postWriteReminder}`;
      } else {
        llmContent = `Todos have been modified successfully. Ensure that you continue to use the todo list to track your progress. Please proceed with the current tasks if applicable

<system-reminder>
Your todo list has changed. DO NOT mention this explicitly to the user. Here are the latest contents of your todo list:

${todosJson}. Continue on with the tasks at hand if applicable.
</system-reminder>${postWriteReminder}`;
      }
      return {
        llmContent,
        returnDisplay: todoResultDisplay
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : String(error);
      debugLogger.error(
        `[TodoWriteTool] Error executing todo_write: ${errorMessage}`
      );
      const errorLlmContent = `Failed to modify todos. An error occurred during the operation.

<system-reminder>
Todo list modification failed with error: ${errorMessage}. You may need to retry or handle this error appropriately.
</system-reminder>`;
      return {
        llmContent: errorLlmContent,
        returnDisplay: `Error writing todos: ${errorMessage}`
      };
    }
  }
};
async function readTodosForSession(sessionId) {
  return readTodosFromFile(sessionId);
}
__name(readTodosForSession, "readTodosForSession");
async function listTodoSessions() {
  try {
    const todoDir = path.join(Storage.getRuntimeBaseDir(), TODO_SUBDIR);
    const files = await fs.readdir(todoDir);
    return files.filter((file) => file.endsWith(".json")).map((file) => file.replace(".json", ""));
  } catch (err) {
    const error = err;
    if (!(error instanceof Error) || error.code !== "ENOENT") {
      throw err;
    }
    return [];
  }
}
__name(listTodoSessions, "listTodoSessions");
var TodoWriteTool = class _TodoWriteTool extends BaseDeclarativeTool {
  constructor(config) {
    super(
      _TodoWriteTool.Name,
      ToolDisplayNames.TODO_WRITE,
      todoWriteToolDescription,
      "think" /* Think */,
      todoWriteToolSchemaData.parametersJsonSchema
    );
    this.config = config;
  }
  static {
    __name(this, "TodoWriteTool");
  }
  static Name = ToolNames.TODO_WRITE;
  validateToolParams(params) {
    if (!Array.isArray(params.todos)) {
      return 'Parameter "todos" must be an array.';
    }
    for (const todo of params.todos) {
      if (!todo.id || typeof todo.id !== "string" || todo.id.trim() === "") {
        return 'Each todo must have a non-empty "id" string.';
      }
      if (!todo.content || typeof todo.content !== "string" || todo.content.trim() === "") {
        return 'Each todo must have a non-empty "content" string.';
      }
      if (!["pending", "in_progress", "completed"].includes(todo.status)) {
        return 'Each todo must have a valid "status" (pending, in_progress, completed).';
      }
    }
    const ids = params.todos.map((todo) => todo.id);
    const uniqueIds = new Set(ids);
    if (ids.length !== uniqueIds.size) {
      return "Todo IDs must be unique within the array.";
    }
    return null;
  }
  createInvocation(params) {
    const sessionId = this.config.getSessionId();
    const todoFilePath = getTodoFilePath(sessionId);
    const operationType = fsSync.existsSync(todoFilePath) ? "update" : "create";
    return new TodoWriteToolInvocation(this.config, params, operationType);
  }
};
export {
  TodoWriteTool,
  listTodoSessions,
  readTodosForSession
};
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */
