#!/usr/bin/env node
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { spawn, execSync, execFileSync } from "child_process";
import * as fs from "fs";
import * as path from "path";
import * as os from "os";
import { program } from "commander";
import { v4 as uuidv4 } from "uuid";
import chalk from "chalk";
import { initializeTracing, trace } from "../core/trace/index.js";
class CodexSM {
  config;
  stackmemoryPath;
  constructor() {
    this.config = {
      instanceId: this.generateInstanceId(),
      useWorktree: false,
      contextEnabled: true,
      tracingEnabled: true,
      verboseTracing: false
    };
    this.stackmemoryPath = this.findStackMemory();
  }
  generateInstanceId() {
    return uuidv4().substring(0, 8);
  }
  findStackMemory() {
    const possiblePaths = [
      path.join(os.homedir(), ".stackmemory", "bin", "stackmemory"),
      "/usr/local/bin/stackmemory",
      "/opt/homebrew/bin/stackmemory",
      "stackmemory"
    ];
    for (const smPath of possiblePaths) {
      try {
        execFileSync("which", [smPath], { stdio: "ignore" });
        return smPath;
      } catch {
      }
    }
    return "stackmemory";
  }
  isGitRepo() {
    try {
      execSync("git rev-parse --git-dir", { stdio: "ignore" });
      return true;
    } catch {
      return false;
    }
  }
  getCurrentBranch() {
    try {
      return execSync("git rev-parse --abbrev-ref HEAD", {
        encoding: "utf8"
      }).trim();
    } catch {
      return "main";
    }
  }
  hasUncommittedChanges() {
    try {
      const status = execSync("git status --porcelain", { encoding: "utf8" });
      return status.length > 0;
    } catch {
      return false;
    }
  }
  resolveCodexBin() {
    if (this.config.codexBin && this.config.codexBin.trim()) {
      return this.config.codexBin.trim();
    }
    const envBin = process.env["CODEX_BIN"];
    if (envBin && envBin.trim()) {
      return envBin.trim();
    }
    try {
      execSync("which codex", { stdio: "ignore" });
      return "codex";
    } catch {
    }
    try {
      execSync("which codex-cli", { stdio: "ignore" });
      return "codex-cli";
    } catch {
    }
    return null;
  }
  setupWorktree() {
    if (!this.config.useWorktree || !this.isGitRepo()) return null;
    console.log(chalk.blue("\u{1F333} Setting up isolated worktree..."));
    const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").substring(0, 19);
    const branch = this.config.branch || `codex-${this.config.task || "work"}-${timestamp}-${this.config.instanceId}`;
    const repoName = path.basename(process.cwd());
    const worktreePath = path.join(
      path.dirname(process.cwd()),
      `${repoName}--${branch}`
    );
    try {
      const cmd = `git worktree add -b "${branch}" "${worktreePath}"`;
      execSync(cmd, { stdio: "inherit" });
      console.log(chalk.green(`Worktree created: ${worktreePath}`));
      console.log(chalk.gray(`   Branch: ${branch}`));
      const configPath = path.join(worktreePath, ".codex-instance.json");
      const configData = {
        instanceId: this.config.instanceId,
        worktreePath,
        branch,
        task: this.config.task,
        created: (/* @__PURE__ */ new Date()).toISOString(),
        parentRepo: process.cwd()
      };
      fs.writeFileSync(configPath, JSON.stringify(configData, null, 2));
      const envFiles = [".env", ".env.local", ".mise.toml", ".tool-versions"];
      for (const file of envFiles) {
        const srcPath = path.join(process.cwd(), file);
        if (fs.existsSync(srcPath))
          fs.copyFileSync(srcPath, path.join(worktreePath, file));
      }
      return worktreePath;
    } catch (err) {
      console.error(chalk.red("Failed to create worktree:"), err);
      return null;
    }
  }
  saveContext(message, metadata = {}) {
    if (!this.config.contextEnabled) return;
    try {
      const contextData = {
        message,
        metadata: {
          ...metadata,
          instanceId: this.config.instanceId,
          worktree: this.config.worktreePath,
          timestamp: (/* @__PURE__ */ new Date()).toISOString()
        }
      };
      const cmd = `${this.stackmemoryPath} context save --json '${JSON.stringify(contextData)}'`;
      execSync(cmd, { stdio: "ignore" });
    } catch {
    }
  }
  loadContext() {
    if (!this.config.contextEnabled) return;
    try {
      console.log(chalk.blue("\u{1F4DA} Loading previous context..."));
      const cmd = `${this.stackmemoryPath} context list --limit 5 --format json`;
      const output = execSync(cmd, { encoding: "utf8" });
      const contexts = JSON.parse(output);
      if (Array.isArray(contexts) && contexts.length > 0) {
        console.log(chalk.gray("Recent context loaded:"));
        contexts.forEach(
          (ctx) => {
            console.log(
              chalk.gray(`  - ${ctx.message} (${ctx.metadata?.timestamp})`)
            );
          }
        );
      }
    } catch {
    }
  }
  suggestWorktreeMode() {
    if (this.hasUncommittedChanges()) {
      console.log(chalk.yellow("WARNING: Uncommitted changes detected"));
      console.log(
        chalk.gray("   Consider using --worktree to work in isolation")
      );
    }
  }
  async run(args) {
    const codexArgs = [];
    let i = 0;
    while (i < args.length) {
      const arg = args[i];
      switch (arg) {
        case "--worktree":
        case "-w":
          this.config.useWorktree = true;
          break;
        case "--no-context":
          this.config.contextEnabled = false;
          break;
        case "--no-trace":
          this.config.tracingEnabled = false;
          break;
        case "--verbose-trace":
          this.config.verboseTracing = true;
          break;
        case "--branch":
        case "-b":
          i++;
          this.config.branch = args[i];
          break;
        case "--task":
        case "-t":
          i++;
          this.config.task = args[i];
          break;
        case "--codex-bin":
          i++;
          this.config.codexBin = args[i];
          process.env["CODEX_BIN"] = this.config.codexBin;
          break;
        case "--auto":
        case "-a":
          if (this.isGitRepo()) {
            this.config.useWorktree = this.hasUncommittedChanges();
          }
          break;
        default:
          codexArgs.push(arg);
      }
      i++;
    }
    if (this.config.tracingEnabled) {
      process.env["DEBUG_TRACE"] = "true";
      process.env["STACKMEMORY_DEBUG"] = "true";
      process.env["TRACE_OUTPUT"] = "file";
      process.env["TRACE_MASK_SENSITIVE"] = "true";
      if (this.config.verboseTracing) {
        process.env["TRACE_VERBOSITY"] = "full";
        process.env["TRACE_PARAMS"] = "true";
        process.env["TRACE_RESULTS"] = "true";
        process.env["TRACE_MEMORY"] = "true";
      } else {
        process.env["TRACE_VERBOSITY"] = "summary";
        process.env["TRACE_PARAMS"] = "true";
        process.env["TRACE_RESULTS"] = "false";
      }
      initializeTracing();
      trace.command(
        "codex-sm",
        {
          instanceId: this.config.instanceId,
          worktree: this.config.useWorktree,
          task: this.config.task
        },
        async () => {
        }
      );
    }
    console.log(chalk.blue("\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"));
    console.log(chalk.blue("\u2551     Codex + StackMemory + Worktree    \u2551"));
    console.log(chalk.blue("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
    console.log();
    if (this.isGitRepo()) {
      const branch = this.getCurrentBranch();
      console.log(chalk.gray(`\u{1F4CD} Current branch: ${branch}`));
      if (!this.config.useWorktree) this.suggestWorktreeMode();
    }
    if (this.config.useWorktree) {
      const worktreePath = this.setupWorktree();
      if (worktreePath) {
        this.config.worktreePath = worktreePath;
        process.chdir(worktreePath);
        this.saveContext("Created worktree for Codex instance", {
          action: "worktree_created",
          path: worktreePath,
          branch: this.config.branch
        });
      }
    }
    this.loadContext();
    process.env["CODEX_INSTANCE_ID"] = this.config.instanceId;
    if (this.config.worktreePath)
      process.env["CODEX_WORKTREE_PATH"] = this.config.worktreePath;
    console.log(chalk.gray(`\u{1F916} Instance ID: ${this.config.instanceId}`));
    console.log(chalk.gray(`\u{1F4C1} Working in: ${process.cwd()}`));
    console.log();
    console.log(chalk.gray("Starting Codex..."));
    console.log(chalk.gray("\u2500".repeat(42)));
    const codexBin = this.resolveCodexBin();
    if (!codexBin) {
      console.error(chalk.red("\u274C Codex CLI not found."));
      console.log(
        chalk.gray(
          "   Install codex/codex-cli or set an override:\n     export CODEX_BIN=/path/to/codex\n     codex-sm --help\n\n   Ensure PATH includes npm global bin (npm bin -g)."
        )
      );
      process.exit(1);
      return;
    }
    const child = spawn(codexBin, codexArgs, {
      stdio: "inherit",
      env: process.env
    });
    child.on("error", (err) => {
      console.error(chalk.red("\u274C Failed to launch Codex CLI."));
      if (err.code === "ENOENT") {
        console.error(
          chalk.gray(
            "   Not found. Set CODEX_BIN or install codex/codex-cli on PATH."
          )
        );
      } else if (err.code === "EPERM" || err.code === "EACCES") {
        console.error(
          chalk.gray(
            "   Permission/sandbox issue. Try running outside a sandbox or set CODEX_BIN."
          )
        );
      } else {
        console.error(chalk.gray(`   ${err.message}`));
      }
      process.exit(1);
    });
    child.on("exit", (code) => {
      this.saveContext("Codex session ended", {
        action: "session_end",
        exitCode: code
      });
      if (this.config.tracingEnabled) {
        const summary = trace.getExecutionSummary();
        console.log();
        console.log(chalk.gray("\u2500".repeat(42)));
        console.log(chalk.blue("Debug Trace Summary:"));
        console.log(chalk.gray(summary));
      }
      if (this.config.worktreePath) {
        console.log();
        console.log(chalk.gray("\u2500".repeat(42)));
        console.log(chalk.blue("Session ended in worktree:"));
        console.log(chalk.gray(`  ${this.config.worktreePath}`));
      }
      process.exit(code || 0);
    });
    process.on("SIGINT", () => {
      this.saveContext("Codex session interrupted", {
        action: "session_interrupt"
      });
      child.kill("SIGINT");
    });
    process.on("SIGTERM", () => {
      this.saveContext("Codex session terminated", {
        action: "session_terminate"
      });
      child.kill("SIGTERM");
    });
  }
}
program.name("codex-sm").description("Codex with StackMemory context and optional worktree isolation").version("1.0.0").option("-w, --worktree", "Create isolated worktree for this instance").option("-a, --auto", "Automatically detect and apply best settings").option("-b, --branch <name>", "Specify branch name for worktree").option("-t, --task <desc>", "Task description for context").option("--codex-bin <path>", "Path to codex/codex-cli (or use CODEX_BIN)").option("--no-context", "Disable StackMemory context integration").option("--no-trace", "Disable debug tracing (enabled by default)").option("--verbose-trace", "Enable verbose debug tracing with full details").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
  const codexSM = new CodexSM();
  const args = process.argv.slice(2);
  await codexSM.run(args);
});
program.parse(process.argv);
//# sourceMappingURL=codex-sm.js.map
