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, spawn } from "child_process";
import {
  existsSync,
  readFileSync,
  writeFileSync,
  mkdirSync,
  readdirSync,
  unlinkSync
} from "fs";
import { join } from "path";
import { homedir } from "os";
import Database from "better-sqlite3";
import { z } from "zod";
import { FrameManager } from "../../core/context/index.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 countTokens = (text) => Math.ceil(text.length / 3.5);
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 createCaptureCommand() {
  const cmd = new Command("capture");
  cmd.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").option("--verbose", "Use verbose handoff format (full markdown)").option("--ultra", "Use ultra-compact pipe-delimited format").option(
    "--format <format>",
    "Output format: auto, ultra, compact, verbose (default: auto)"
  ).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,
          stdio: ["pipe", "pipe", "pipe"]
        });
        hasChanges = gitStatus.trim().length > 0;
      } catch {
      }
      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,
          stdio: ["pipe", "pipe", "pipe"]
        }).trim();
        const lastCommit = execSync("git log -1 --oneline", {
          encoding: "utf-8",
          cwd: projectRoot,
          stdio: ["pipe", "pipe", "pipe"]
        }).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 capture at ${timestamp}
`;
      } else {
        const enhancedGenerator = new EnhancedHandoffGenerator(projectRoot);
        const enhancedHandoff = await enhancedGenerator.generate();
        let format = "auto";
        if (options.verbose) {
          format = "verbose";
        } else if (options.ultra) {
          format = "ultra";
        } else if (options.format) {
          format = options.format;
        }
        if (format === "auto") {
          const selectedFormat = enhancedGenerator.selectFormat(enhancedHandoff);
          handoffPrompt = enhancedGenerator.toAutoFormat(enhancedHandoff);
          const actualTokens = countTokens(handoffPrompt);
          console.log(
            `Estimated tokens: ~${actualTokens} (${selectedFormat}, auto-selected)`
          );
        } else if (format === "ultra") {
          handoffPrompt = enhancedGenerator.toUltraCompact(enhancedHandoff);
          const actualTokens = countTokens(handoffPrompt);
          console.log(`Estimated tokens: ~${actualTokens} (ultra-compact)`);
        } else if (format === "verbose") {
          handoffPrompt = enhancedGenerator.toMarkdown(enhancedHandoff);
          const actualTokens = countTokens(handoffPrompt);
          console.log(`Estimated tokens: ~${actualTokens} (verbose)`);
        } else {
          handoffPrompt = enhancedGenerator.toCompact(enhancedHandoff);
          const actualTokens = countTokens(handoffPrompt);
          console.log(`Estimated tokens: ~${actualTokens} (compact)`);
        }
      }
      const stackmemoryDir = join(projectRoot, ".stackmemory");
      if (!existsSync(stackmemoryDir)) {
        mkdirSync(stackmemoryDir, { recursive: true });
      }
      const handoffPath = join(stackmemoryDir, "last-handoff.md");
      writeFileSync(handoffPath, handoffPrompt);
      let branch = "unknown";
      try {
        branch = execSync("git rev-parse --abbrev-ref HEAD", {
          encoding: "utf-8",
          cwd: projectRoot,
          stdio: ["pipe", "pipe", "pipe"]
        }).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("Capture command failed", error);
      console.error("\u274C Capture failed:", error.message);
      process.exit(1);
    }
  });
  return cmd;
}
function createRestoreCommand() {
  const cmd = new Command("restore");
  cmd.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 capture" 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",
          stdio: ["pipe", "pipe", "pipe"]
        }).trim();
        if (gitStatus) {
          console.log("\n  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("Restore failed", error);
      console.error("\u274C Restore failed:", error.message);
      process.exit(1);
    }
  });
  return cmd;
}
async function captureHandoff(reason, exitCode, wrappedCommand, sessionStart, quiet) {
  const projectRoot = process.cwd();
  const handoffDir = join(homedir(), ".stackmemory", "handoffs");
  const logFile = join(handoffDir, "auto-handoff.log");
  if (!existsSync(handoffDir)) {
    mkdirSync(handoffDir, { recursive: true });
  }
  const logMessage = (msg) => {
    const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
    const logLine = `[${timestamp}] ${msg}
`;
    try {
      writeFileSync(logFile, logLine, { flag: "a" });
    } catch {
    }
  };
  if (!quiet) {
    console.log("\nCapturing handoff context...");
  }
  logMessage(`Capturing handoff: reason=${reason}, exit_code=${exitCode}`);
  try {
    execFileSync(
      process.execPath,
      [process.argv[1], "capture", "--no-commit"],
      {
        cwd: projectRoot,
        stdio: quiet ? "pipe" : "inherit"
      }
    );
    const metadata = {
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      reason,
      exit_code: exitCode,
      command: wrappedCommand,
      pid: process.pid,
      cwd: projectRoot,
      user: process.env["USER"] || "unknown",
      session_duration: Math.floor((Date.now() - sessionStart) / 1e3)
    };
    const metadataPath = join(handoffDir, "last-handoff-meta.json");
    writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));
    if (!quiet) {
      console.log("Handoff captured successfully");
      logMessage(`Handoff captured: ${metadataPath}`);
      console.log("\nSession Summary:");
      console.log(`  Duration: ${metadata.session_duration} seconds`);
      console.log(`  Exit reason: ${reason}`);
      try {
        const gitStatus = execSync("git status --short", {
          encoding: "utf-8",
          cwd: projectRoot,
          stdio: ["pipe", "pipe", "pipe"]
        }).trim();
        if (gitStatus) {
          console.log("\nYou have uncommitted changes");
          console.log('  Run "git status" to review');
        }
      } catch {
      }
      console.log('\nRun "stackmemory restore" in your next session');
    }
  } catch (err) {
    if (!quiet) {
      console.error("Failed to capture handoff:", err.message);
    }
    logMessage(`ERROR: ${err.message}`);
  }
}
function createAutoCaptureCommand() {
  const cmd = new Command("auto-capture");
  cmd.description("Wrap a command with automatic handoff capture on termination").option("-a, --auto", "Auto-capture on normal exit (no prompt)").option("-q, --quiet", "Suppress output").option("-t, --tag <tag>", "Tag this session").argument("[command...]", "Command to wrap with auto-handoff").action(async (commandArgs, options) => {
    const autoCapture = options.auto || false;
    const quiet = options.quiet || false;
    const tag = options.tag || "";
    if (!commandArgs || commandArgs.length === 0) {
      console.log("StackMemory Auto-Handoff");
      console.log("-".repeat(50));
      console.log("");
      console.log(
        "Wraps a command with automatic handoff capture on termination."
      );
      console.log("");
      console.log("Usage:");
      console.log("  stackmemory auto-capture [options] <command> [args...]");
      console.log("");
      console.log("Examples:");
      console.log("  stackmemory auto-capture claude");
      console.log("  stackmemory auto-capture -a npm run dev");
      console.log('  stackmemory auto-capture -t "feature-work" vim');
      console.log("");
      console.log("Options:");
      console.log(
        "  -a, --auto       Auto-capture on normal exit (no prompt)"
      );
      console.log("  -q, --quiet      Suppress output");
      console.log("  -t, --tag <tag>  Tag this session");
      return;
    }
    const wrappedCommand = commandArgs.join(" ");
    const sessionStart = Date.now();
    let capturedAlready = false;
    if (!quiet) {
      console.log("StackMemory Auto-Handoff Wrapper");
      console.log(`Wrapping: ${wrappedCommand}`);
      if (tag) {
        console.log(`Tag: ${tag}`);
      }
      console.log("Handoff will be captured on termination");
      console.log("");
    }
    const [cmd2, ...args] = commandArgs;
    let childProcess;
    try {
      childProcess = spawn(cmd2, args, {
        stdio: "inherit",
        shell: false,
        cwd: process.cwd(),
        env: process.env
      });
    } catch (err) {
      console.error(`Failed to start command: ${err.message}`);
      process.exit(1);
      return;
    }
    const handleSignal = async (signal, exitCode) => {
      if (capturedAlready) return;
      capturedAlready = true;
      if (!quiet) {
        console.log(`
Received ${signal}`);
      }
      if (childProcess.pid && !childProcess.killed) {
        childProcess.kill(signal);
      }
      await captureHandoff(
        signal,
        exitCode,
        wrappedCommand,
        sessionStart,
        quiet
      );
      process.exit(exitCode);
    };
    process.on("SIGINT", () => handleSignal("SIGINT", 130));
    process.on("SIGTERM", () => handleSignal("SIGTERM", 143));
    process.on("SIGHUP", () => handleSignal("SIGHUP", 129));
    childProcess.on("exit", async (code, signal) => {
      if (capturedAlready) return;
      capturedAlready = true;
      const exitCode = code ?? (signal ? 128 : 0);
      if (signal) {
        await captureHandoff(
          signal,
          exitCode,
          wrappedCommand,
          sessionStart,
          quiet
        );
      } else if (exitCode !== 0) {
        if (!quiet) {
          console.log(`
Command exited with code: ${exitCode}`);
        }
        await captureHandoff(
          "unexpected_exit",
          exitCode,
          wrappedCommand,
          sessionStart,
          quiet
        );
      } else if (autoCapture) {
        await captureHandoff(
          "normal_exit",
          0,
          wrappedCommand,
          sessionStart,
          quiet
        );
      } else {
        if (process.stdin.isTTY) {
          console.log(
            "\nSession ending. Use -a flag for auto-capture on normal exit."
          );
        }
      }
      process.exit(exitCode);
    });
    childProcess.on("error", async (err) => {
      if (capturedAlready) return;
      capturedAlready = true;
      console.error(`Command error: ${err.message}`);
      await captureHandoff(
        "spawn_error",
        1,
        wrappedCommand,
        sessionStart,
        quiet
      );
      process.exit(1);
    });
  });
  return cmd;
}
function createHandoffCommand() {
  const cmd = new Command("handoff");
  cmd.description('(deprecated) Use "capture" or "restore" instead');
  return cmd;
}
export {
  createAutoCaptureCommand,
  createCaptureCommand,
  createHandoffCommand,
  createRestoreCommand
};
//# sourceMappingURL=handoff.js.map
