import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { Command } from "commander";
import { execSync, execFileSync } from "child_process";
import {
  existsSync,
  readFileSync,
  writeFileSync,
  mkdirSync,
  readdirSync,
  unlinkSync
} from "fs";
import { join } from "path";
import Database from "better-sqlite3";
import { z } from "zod";
import { FrameManager } from "../../core/context/frame-manager.js";
import { LinearTaskManager } from "../../features/tasks/linear-task-manager.js";
import { logger } from "../../core/monitoring/logger.js";
import { EnhancedHandoffGenerator } from "../../core/session/enhanced-handoff.js";
const MAX_HANDOFF_VERSIONS = 10;
function saveVersionedHandoff(projectRoot, branch, content) {
  const handoffsDir = join(projectRoot, ".stackmemory", "handoffs");
  if (!existsSync(handoffsDir)) {
    mkdirSync(handoffsDir, { recursive: true });
  }
  const now = /* @__PURE__ */ new Date();
  const timestamp = now.toISOString().slice(0, 16).replace(/[T:]/g, "-");
  const safeBranch = branch.replace(/[^a-zA-Z0-9-]/g, "-").slice(0, 30);
  const filename = `${timestamp}-${safeBranch}.md`;
  const versionedPath = join(handoffsDir, filename);
  writeFileSync(versionedPath, content);
  try {
    const files = readdirSync(handoffsDir).filter((f) => f.endsWith(".md")).sort().reverse();
    for (const oldFile of files.slice(MAX_HANDOFF_VERSIONS)) {
      unlinkSync(join(handoffsDir, oldFile));
    }
  } catch {
  }
  return versionedPath;
}
const CommitMessageSchema = z.string().min(1, "Commit message cannot be empty").max(200, "Commit message too long").regex(
  /^[a-zA-Z0-9\s\-_.,:()\/\[\]]+$/,
  "Commit message contains invalid characters"
).refine(
  (msg) => !msg.includes("\n"),
  "Commit message cannot contain newlines"
).refine(
  (msg) => !msg.includes('"'),
  "Commit message cannot contain double quotes"
).refine(
  (msg) => !msg.includes("`"),
  "Commit message cannot contain backticks"
);
function createHandoffCommand() {
  const cmd = new Command("handoff");
  cmd.description("Session handoff for continuity between Claude sessions");
  cmd.command("capture", { isDefault: true }).description("Commit current work and generate a handoff prompt").option("-m, --message <message>", "Custom commit message").option("--no-commit", "Skip git commit").option("--copy", "Copy the handoff prompt to clipboard").option("--basic", "Use basic handoff format instead of enhanced").action(async (options) => {
    try {
      const projectRoot = process.cwd();
      const dbPath = join(projectRoot, ".stackmemory", "context.db");
      let gitStatus = "";
      let hasChanges = false;
      try {
        gitStatus = execSync("git status --short", {
          encoding: "utf-8",
          cwd: projectRoot
        });
        hasChanges = gitStatus.trim().length > 0;
      } catch {
        console.log("\u26A0\uFE0F  Not in a git repository");
      }
      if (hasChanges && options.commit !== false) {
        try {
          const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
            encoding: "utf-8",
            cwd: projectRoot
          }).trim();
          execSync("git add -A", { cwd: projectRoot });
          let commitMessage = options.message || `chore: handoff checkpoint on ${currentBranch}`;
          try {
            commitMessage = CommitMessageSchema.parse(commitMessage);
          } catch (validationError) {
            console.error(
              "\u274C Invalid commit message:",
              validationError.message
            );
            return;
          }
          execFileSync("git", ["commit", "-m", commitMessage], {
            cwd: projectRoot,
            stdio: "inherit"
          });
          console.log(`\u2705 Committed changes: "${commitMessage}"`);
          console.log(`   Branch: ${currentBranch}`);
        } catch (err) {
          console.error(
            "\u274C Failed to commit changes:",
            err.message
          );
        }
      } else if (!hasChanges) {
        console.log("\u2139\uFE0F  No changes to commit");
      }
      let contextSummary = "";
      let tasksSummary = "";
      let recentWork = "";
      if (existsSync(dbPath)) {
        const db = new Database(dbPath);
        const frameManager = new FrameManager(db, "cli-project");
        const activeFrames = frameManager.getActiveFramePath();
        if (activeFrames.length > 0) {
          contextSummary = "Active context frames:\n";
          activeFrames.forEach((frame) => {
            contextSummary += `  - ${frame.name} [${frame.type}]
`;
          });
        }
        const taskStore = new LinearTaskManager(projectRoot, db);
        const activeTasks = taskStore.getActiveTasks();
        const inProgress = activeTasks.filter(
          (t) => t.status === "in_progress"
        );
        const todo = activeTasks.filter((t) => t.status === "pending");
        const recentlyCompleted = activeTasks.filter((t) => t.status === "completed" && t.completed_at).sort(
          (a, b) => (b.completed_at || 0) - (a.completed_at || 0)
        ).slice(0, 3);
        if (inProgress.length > 0 || todo.length > 0) {
          tasksSummary = "\nTasks:\n";
          if (inProgress.length > 0) {
            tasksSummary += "In Progress:\n";
            inProgress.forEach((t) => {
              const externalId = t.external_refs?.linear?.id;
              tasksSummary += `  - ${t.title}${externalId ? ` [${externalId}]` : ""}
`;
            });
          }
          if (todo.length > 0) {
            tasksSummary += "TODO:\n";
            todo.slice(0, 5).forEach((t) => {
              const externalId = t.external_refs?.linear?.id;
              tasksSummary += `  - ${t.title}${externalId ? ` [${externalId}]` : ""}
`;
            });
            if (todo.length > 5) {
              tasksSummary += `  ... and ${todo.length - 5} more
`;
            }
          }
        }
        if (recentlyCompleted.length > 0) {
          recentWork = "\nRecently Completed:\n";
          recentlyCompleted.forEach((t) => {
            recentWork += `  \u2713 ${t.title}
`;
          });
        }
        const recentEvents = db.prepare(
          `
            SELECT event_type as type, payload as data, datetime(ts, 'unixepoch') as time
            FROM events
            ORDER BY ts DESC
            LIMIT 5
          `
        ).all();
        if (recentEvents.length > 0) {
          recentWork += "\nRecent Activity:\n";
          recentEvents.forEach((event) => {
            const data = JSON.parse(event.data);
            recentWork += `  - ${event.type}: ${data.message || data.name || "activity"}
`;
          });
        }
        db.close();
      }
      let gitInfo = "";
      try {
        const branch2 = execSync("git rev-parse --abbrev-ref HEAD", {
          encoding: "utf-8",
          cwd: projectRoot
        }).trim();
        const lastCommit = execSync("git log -1 --oneline", {
          encoding: "utf-8",
          cwd: projectRoot
        }).trim();
        gitInfo = `
Git Status:
  Branch: ${branch2}
  Last commit: ${lastCommit}
`;
      } catch {
      }
      let notes = "";
      const notesPath = join(projectRoot, ".stackmemory", "handoff.md");
      if (existsSync(notesPath)) {
        const handoffNotes = readFileSync(notesPath, "utf-8");
        if (handoffNotes.trim()) {
          notes = `
Notes from previous handoff:
${handoffNotes}
`;
        }
      }
      let handoffPrompt;
      if (options.basic) {
        const timestamp = (/* @__PURE__ */ new Date()).toISOString();
        handoffPrompt = `# Session Handoff - ${timestamp}

## Project: ${projectRoot.split("/").pop()}

${gitInfo}
${contextSummary}
${tasksSummary}
${recentWork}
${notes}

## Continue from here:

1. Run \`stackmemory status\` to check the current state
2. Review any in-progress tasks above
3. Check for any uncommitted changes with \`git status\`
4. Resume work on the active context

## Quick Commands:
- \`stackmemory context load --recent\` - Load recent context
- \`stackmemory task list --state in_progress\` - Show in-progress tasks
- \`stackmemory linear sync\` - Sync with Linear if configured
- \`stackmemory log recent\` - View recent activity

---
Generated by stackmemory handoff at ${timestamp}
`;
      } else {
        const enhancedGenerator = new EnhancedHandoffGenerator(projectRoot);
        const enhancedHandoff = await enhancedGenerator.generate();
        handoffPrompt = enhancedGenerator.toMarkdown(enhancedHandoff);
        console.log(`Estimated tokens: ~${enhancedHandoff.estimatedTokens}`);
      }
      const handoffPath = join(
        projectRoot,
        ".stackmemory",
        "last-handoff.md"
      );
      writeFileSync(handoffPath, handoffPrompt);
      let branch = "unknown";
      try {
        branch = execSync("git rev-parse --abbrev-ref HEAD", {
          encoding: "utf-8",
          cwd: projectRoot
        }).trim();
      } catch {
      }
      const versionedPath = saveVersionedHandoff(
        projectRoot,
        branch,
        handoffPrompt
      );
      console.log(
        `Versioned: ${versionedPath.split("/").slice(-2).join("/")}`
      );
      console.log("\n" + "=".repeat(60));
      console.log(handoffPrompt);
      console.log("=".repeat(60));
      if (options.copy) {
        try {
          if (process.platform === "darwin") {
            execFileSync("pbcopy", [], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          } else if (process.platform === "win32") {
            execFileSync("clip", [], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          } else {
            execFileSync("xclip", ["-selection", "clipboard"], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          }
          console.log("\n\u2705 Handoff prompt copied to clipboard!");
        } catch {
          console.log("\n\u26A0\uFE0F  Could not copy to clipboard");
        }
      }
      console.log(`
\u{1F4BE} Handoff saved to: ${handoffPath}`);
      console.log("\u{1F4CB} Use this prompt when starting your next session");
    } catch (error) {
      logger.error("Handoff command failed", error);
      console.error("\u274C Handoff failed:", error.message);
      process.exit(1);
    }
  });
  cmd.command("restore").description("Restore context from last handoff").option("--no-copy", "Do not copy prompt to clipboard").action(async (options) => {
    try {
      const projectRoot = process.cwd();
      const handoffPath = join(
        projectRoot,
        ".stackmemory",
        "last-handoff.md"
      );
      const metaPath = join(
        process.env["HOME"] || "~",
        ".stackmemory",
        "handoffs",
        "last-handoff-meta.json"
      );
      if (!existsSync(handoffPath)) {
        console.log("\u274C No handoff found in this project");
        console.log('\u{1F4A1} Run "stackmemory handoff" to create one');
        return;
      }
      const handoffPrompt = readFileSync(handoffPath, "utf-8");
      console.log("\n" + "=".repeat(60));
      console.log("\u{1F4CB} RESTORED HANDOFF");
      console.log("=".repeat(60));
      console.log(handoffPrompt);
      console.log("=".repeat(60));
      if (existsSync(metaPath)) {
        const metadata = JSON.parse(readFileSync(metaPath, "utf-8"));
        console.log("\n\u{1F4CA} Session Metadata:");
        console.log(`  Timestamp: ${metadata.timestamp}`);
        console.log(`  Reason: ${metadata.reason}`);
        console.log(`  Duration: ${metadata.session_duration}s`);
        console.log(`  Command: ${metadata.command}`);
      }
      try {
        const gitStatus = execSync("git status --short", {
          encoding: "utf-8"
        }).trim();
        if (gitStatus) {
          console.log("\n\u26A0\uFE0F  Current uncommitted changes:");
          console.log(gitStatus);
        }
      } catch {
      }
      if (options.copy !== false) {
        try {
          if (process.platform === "darwin") {
            execFileSync("pbcopy", [], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          } else if (process.platform === "win32") {
            execFileSync("clip", [], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          } else {
            execFileSync("xclip", ["-selection", "clipboard"], {
              input: handoffPrompt,
              cwd: projectRoot
            });
          }
          console.log("\n\u2705 Handoff prompt copied to clipboard!");
        } catch {
          console.log("\n\u26A0\uFE0F  Could not copy to clipboard");
        }
      }
      console.log("\n\u{1F680} Ready to continue where you left off!");
    } catch (error) {
      logger.error("Handoff restore failed", error);
      console.error("\u274C Restore failed:", error.message);
      process.exit(1);
    }
  });
  cmd.command("auto").description("Enable auto-capture on session termination").option("--command <command>", "Command to wrap with auto-handoff").action(async (options) => {
    const scriptPath = join(
      __dirname,
      "..",
      "..",
      "..",
      "scripts",
      "stackmemory-auto-handoff.sh"
    );
    if (!existsSync(scriptPath)) {
      console.error("\u274C Auto-handoff script not found");
      console.log("\u{1F4E6} Please ensure StackMemory is properly installed");
      return;
    }
    console.log("\u{1F6E1}\uFE0F  StackMemory Auto-Handoff");
    console.log("\u2500".repeat(50));
    if (options.command) {
      const commandSchema = z.string().min(1, "Command cannot be empty").max(200, "Command too long").regex(
        /^[a-zA-Z0-9\s\-_./:]+$/,
        "Command contains invalid characters"
      ).refine((cmd2) => !cmd2.includes(";"), 'Command cannot contain ";"').refine((cmd2) => !cmd2.includes("&"), 'Command cannot contain "&"').refine((cmd2) => !cmd2.includes("|"), 'Command cannot contain "|"').refine((cmd2) => !cmd2.includes("$"), 'Command cannot contain "$"').refine((cmd2) => !cmd2.includes("`"), 'Command cannot contain "`"');
      try {
        const validatedCommand = commandSchema.parse(options.command);
        console.log(`Wrapping command: ${validatedCommand}`);
        execFileSync(scriptPath, [validatedCommand], {
          stdio: "inherit",
          env: { ...process.env, AUTO_CAPTURE_ON_EXIT: "true" }
        });
      } catch (validationError) {
        if (validationError instanceof z.ZodError) {
          console.error("\u274C Invalid command:");
          validationError.errors.forEach((err) => {
            console.error(`  ${err.message}`);
          });
        } else {
          console.error(
            "\u274C Failed to execute command:",
            validationError.message
          );
        }
        return;
      }
    } else {
      console.log("To enable auto-handoff for your current session:");
      console.log("");
      console.log("  For bash/zsh:");
      console.log(`    source <(${scriptPath} --shell)`);
      console.log("");
      console.log("  Or wrap a command:");
      console.log(`    ${scriptPath} claude`);
      console.log(`    ${scriptPath} npm run dev`);
      console.log("");
      console.log("  Add to your shell profile for permanent setup:");
      console.log(
        `    echo 'alias claude="${scriptPath} claude"' >> ~/.bashrc`
      );
    }
  });
  return cmd;
}
export {
  createHandoffCommand
};
//# sourceMappingURL=handoff.js.map
