"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// git/index.ts
var git_exports = {};
__export(git_exports, {
  MorphGit: () => MorphGit,
  git: () => import_isomorphic_git2.default,
  http: () => import_node2.default
});
module.exports = __toCommonJS(git_exports);

// git/client.ts
var import_isomorphic_git = __toESM(require("isomorphic-git"), 1);
var import_node = __toESM(require("isomorphic-git/http/node"), 1);
var import_fs = __toESM(require("fs"), 1);
var DEFAULT_PROXY_URL = "https://repos.morphllm.com";
var MorphGit = class {
  apiKey;
  proxyUrl;
  constructor(config) {
    if (!config.apiKey) {
      throw new Error("API key is required. Get one at https://morphllm.com/dashboard");
    }
    if (!config.apiKey.startsWith("sk-") && !config.apiKey.startsWith("morph-")) {
      throw new Error("Invalid API key format. Expected: sk-... or morph-...");
    }
    this.apiKey = config.apiKey;
    this.proxyUrl = config.proxyUrl || DEFAULT_PROXY_URL;
  }
  /**
   * Get auth callback for isomorphic-git operations
   * @private
   */
  getAuthCallback() {
    return () => ({
      username: "morph",
      password: this.apiKey
    });
  }
  /**
   * Initialize a new repository
   * Creates the repo in the database and in the git provider
   * 
   * @example
   * ```ts
   * await morphGit.init({
   *   repoId: 'my-project',
   *   dir: './my-project',
   *   defaultBranch: 'main'
   * });
   * ```
   */
  async init(options) {
    const { repoId, dir, defaultBranch = "main" } = options;
    const response = await fetch(`${this.proxyUrl}/v1/repos`, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${this.apiKey}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        repoId,
        name: repoId,
        defaultBranch
      })
    });
    if (!response.ok) {
      const error = await response.text();
      throw new Error(`Failed to create repository: ${error}`);
    }
    await import_isomorphic_git.default.init({
      fs: import_fs.default,
      dir,
      defaultBranch
    });
    await import_isomorphic_git.default.addRemote({
      fs: import_fs.default,
      dir,
      remote: "origin",
      url: `${this.proxyUrl}/v1/repos/${repoId}`
    });
    console.log(`\u2713 Repository '${repoId}' initialized`);
  }
  /**
   * Clone a repository from Morph repos
   * 
   * @example
   * ```ts
   * await morphGit.clone({
   *   repoId: 'my-project',
   *   dir: './my-project'
   * });
   * ```
   */
  async clone(options) {
    const { repoId, dir, branch = "main", depth, singleBranch = true } = options;
    await import_isomorphic_git.default.clone({
      fs: import_fs.default,
      http: import_node.default,
      dir,
      url: `${this.proxyUrl}/v1/repos/${repoId}`,
      ref: branch,
      singleBranch,
      depth,
      onAuth: this.getAuthCallback()
    });
  }
  /**
   * Push changes to remote repository
   * 
   * @example
   * ```ts
   * await morphGit.push({ 
   *   dir: './my-project',
   *   branch: 'main', // Required: explicit branch name
   *   index: true     // Optional: generate embeddings for semantic search
   * });
   * ```
   */
  async push(options) {
    const { dir, remote = "origin", branch, waitForEmbeddings, index = false } = options;
    if (!branch) {
      throw new Error(
        'branch is required for push operations. Specify the branch explicitly: { dir: "./my-project", branch: "main" }'
      );
    }
    const commitHash = await import_isomorphic_git.default.resolveRef({ fs: import_fs.default, dir, ref: "HEAD" });
    let repoId;
    const remotes = await import_isomorphic_git.default.listRemotes({ fs: import_fs.default, dir });
    const originRemote = remotes.find((r) => r.remote === remote);
    if (originRemote) {
      const match = originRemote.url.match(/\/repos\/([^\/]+)$/);
      if (match) {
        repoId = match[1];
      }
    }
    await import_isomorphic_git.default.push({
      fs: import_fs.default,
      http: import_node.default,
      dir,
      remote,
      ref: branch,
      onAuth: this.getAuthCallback()
    });
    if (repoId && commitHash) {
      await this.configureCommit({ repoId, commitHash, branch, index });
    }
    if (waitForEmbeddings && repoId && commitHash && index) {
      await this.waitForEmbeddings({ repoId, commitHash });
    }
  }
  /**
   * Configure commit settings on the backend after push.
   * Sets the index flag to control embedding generation.
   * @private
   */
  async configureCommit(options) {
    const { repoId, commitHash, branch, index } = options;
    const response = await fetch(
      `${this.proxyUrl}/v1/repos/${repoId}/commits/${commitHash}/config`,
      {
        method: "POST",
        headers: {
          "Authorization": `Bearer ${this.apiKey}`,
          "Content-Type": "application/json"
        },
        body: JSON.stringify({ index, branch })
      }
    );
    if (!response.ok) {
      console.warn(`Failed to configure commit: ${response.status}`);
    }
  }
  /**
   * Pull changes from remote repository
   * 
   * @example
   * ```ts
   * await morphGit.pull({ 
   *   dir: './my-project',
   *   branch: 'main' // Required: explicit branch name
   * });
   * ```
   */
  async pull(options) {
    const { dir, remote = "origin", branch } = options;
    if (!branch) {
      throw new Error(
        'branch is required for pull operations. Specify the branch explicitly: { dir: "./my-project", branch: "main" }'
      );
    }
    await import_isomorphic_git.default.pull({
      fs: import_fs.default,
      http: import_node.default,
      dir,
      remote,
      ref: branch,
      onAuth: this.getAuthCallback(),
      author: {
        name: "Morph Agent",
        email: "agent@morph.com"
      }
    });
  }
  /**
   * Wait for embeddings to complete after push.
   * Polls status endpoint until embeddings are done.
   * 
   * @example
   * ```ts
   * await morphGit.push({ dir: './my-project', branch: 'main' });
   * await morphGit.waitForEmbeddings({
   *   repoId: 'my-project',
   *   onProgress: (p) => console.log(`${p.filesProcessed}/${p.totalFiles}`)
   * });
   * ```
   */
  async waitForEmbeddings(options) {
    const { repoId, commitHash, timeout = 12e4, onProgress } = options;
    const startTime = Date.now();
    const pollInterval = 1e3;
    while (Date.now() - startTime < timeout) {
      const statusUrl = `${this.proxyUrl}/v1/repos/${repoId}/embedding-status` + (commitHash ? `?commit_hash=${commitHash}` : "");
      const response = await fetch(statusUrl, {
        headers: { "Authorization": `Bearer ${this.apiKey}` }
      });
      if (response.status === 404) {
        await new Promise((resolve) => setTimeout(resolve, pollInterval));
        continue;
      }
      if (!response.ok) {
        throw new Error(`Failed to get embedding status: ${response.status}`);
      }
      const status = await response.json();
      if (onProgress && status.progress) {
        onProgress(status.progress);
      }
      if (status.status === "completed") {
        return;
      }
      if (status.status === "failed") {
        throw new Error(`Embeddings failed: ${status.error || "Unknown error"}`);
      }
      await new Promise((resolve) => setTimeout(resolve, pollInterval));
    }
    throw new Error(`Embeddings timed out after ${timeout}ms`);
  }
  /**
   * Stage a file for commit
   * 
   * @example
   * ```ts
   * await morphGit.add({
   *   dir: './my-project',
   *   filepath: 'src/app.ts'
   * });
   * ```
   */
  async add(options) {
    const { dir, filepath } = options;
    await import_isomorphic_git.default.add({
      fs: import_fs.default,
      dir,
      filepath
    });
  }
  /**
   * Remove a file from staging
   * 
   * @example
   * ```ts
   * await morphGit.remove({
   *   dir: './my-project',
   *   filepath: 'src/old-file.ts'
   * });
   * ```
   */
  async remove(options) {
    const { dir, filepath } = options;
    await import_isomorphic_git.default.remove({
      fs: import_fs.default,
      dir,
      filepath
    });
  }
  /**
   * Commit staged changes
   * 
   * @example
   * ```ts
   * await morphGit.commit({
   *   dir: './my-project',
   *   message: 'Add new feature',
   *   author: {
   *     name: 'AI Agent',
   *     email: 'ai@example.com'
   *   },
   *   metadata: { issueId: 'PROJ-123', source: 'agent' },
   *   chatHistory: [
   *     { role: 'user', content: 'Please add a new feature' },
   *     { role: 'assistant', content: 'I will add that feature' }
   *   ],
   *   recordingId: 'rec_123'
   * });
   * ```
   */
  async commit(options) {
    const { dir, message, author, metadata, chatHistory, recordingId } = options;
    const commitAuthor = author || {
      name: "Morph SDK",
      email: "sdk@morphllm.com"
    };
    const sha = await import_isomorphic_git.default.commit({
      fs: import_fs.default,
      dir,
      message,
      author: commitAuthor
    });
    if (metadata || chatHistory || recordingId) {
      const notes = {
        metadata,
        chatHistory,
        recordingId,
        _version: 1
      };
      await import_isomorphic_git.default.addNote({
        fs: import_fs.default,
        dir,
        ref: "refs/notes/morph-metadata",
        oid: sha,
        note: JSON.stringify(notes, null, 2),
        author: commitAuthor
      });
    }
    return sha;
  }
  /**
   * Get status of a file
   * 
   * @example
   * ```ts
   * const status = await morphGit.status({
   *   dir: './my-project',
   *   filepath: 'src/app.ts'
   * });
   * console.log(status); // 'modified', '*added', etc.
   * ```
   */
  async status(options) {
    const { dir, filepath } = options;
    if (!filepath) {
      throw new Error("filepath is required for status check");
    }
    const status = await import_isomorphic_git.default.status({
      fs: import_fs.default,
      dir,
      filepath
    });
    return status;
  }
  /**
   * Get commit history
   * 
   * @example
   * ```ts
   * const commits = await morphGit.log({
   *   dir: './my-project',
   *   depth: 10
   * });
   * ```
   */
  async log(options) {
    const { dir, depth, ref } = options;
    const commits = await import_isomorphic_git.default.log({
      fs: import_fs.default,
      dir,
      depth,
      ref
    });
    return commits;
  }
  /**
   * Checkout a branch or commit
   * 
   * @example
   * ```ts
   * await morphGit.checkout({
   *   dir: './my-project',
   *   ref: 'feature-branch'
   * });
   * ```
   */
  async checkout(options) {
    const { dir, ref } = options;
    await import_isomorphic_git.default.checkout({
      fs: import_fs.default,
      dir,
      ref
    });
  }
  /**
   * Create a new branch
   * 
   * @example
   * ```ts
   * await morphGit.branch({
   *   dir: './my-project',
   *   name: 'feature-branch',
   *   checkout: true
   * });
   * ```
   */
  async branch(options) {
    const { dir, name, checkout = false } = options;
    await import_isomorphic_git.default.branch({
      fs: import_fs.default,
      dir,
      ref: name,
      checkout
    });
  }
  /**
   * List all branches
   * 
   * @example
   * ```ts
   * const branches = await morphGit.listBranches({
   *   dir: './my-project'
   * });
   * ```
   */
  async listBranches(options) {
    const { dir } = options;
    const branches = await import_isomorphic_git.default.listBranches({
      fs: import_fs.default,
      dir
    });
    return branches;
  }
  /**
   * Get the current branch name
   * 
   * @example
   * ```ts
   * const branch = await morphGit.currentBranch({
   *   dir: './my-project'
   * });
   * ```
   */
  async currentBranch(options) {
    const { dir } = options;
    const branch = await import_isomorphic_git.default.currentBranch({
      fs: import_fs.default,
      dir
    });
    return branch || void 0;
  }
  /**
   * Get list of changed files (similar to git diff --name-only)
   * 
   * @example
   * ```ts
   * const changes = await morphGit.statusMatrix({
   *   dir: './my-project'
   * });
   * ```
   */
  async statusMatrix(options) {
    const { dir } = options;
    const matrix = await import_isomorphic_git.default.statusMatrix({
      fs: import_fs.default,
      dir
    });
    return matrix.map(([filepath, HEADStatus, workdirStatus, stageStatus]) => {
      let status = "unmodified";
      if (HEADStatus === 1 && workdirStatus === 2 && stageStatus === 2) {
        status = "modified";
      } else if (HEADStatus === 1 && workdirStatus === 2 && stageStatus === 1) {
        status = "*modified";
      } else if (HEADStatus === 0 && workdirStatus === 2 && stageStatus === 2) {
        status = "added";
      } else if (HEADStatus === 0 && workdirStatus === 2 && stageStatus === 0) {
        status = "*added";
      } else if (HEADStatus === 1 && workdirStatus === 0 && stageStatus === 0) {
        status = "deleted";
      } else if (HEADStatus === 1 && workdirStatus === 0 && stageStatus === 1) {
        status = "*deleted";
      } else if (HEADStatus === 1 && workdirStatus === 1 && stageStatus === 1) {
        status = "unmodified";
      } else if (HEADStatus === 0 && workdirStatus === 0 && stageStatus === 0) {
        status = "absent";
      }
      return {
        filepath,
        status
      };
    });
  }
  /**
   * Get the current commit hash
   * 
   * @example
   * ```ts
   * const hash = await morphGit.resolveRef({
   *   dir: './my-project',
   *   ref: 'HEAD'
   * });
   * ```
   */
  async resolveRef(options) {
    const { dir, ref } = options;
    const oid = await import_isomorphic_git.default.resolveRef({
      fs: import_fs.default,
      dir,
      ref
    });
    return oid;
  }
  /**
   * Get notes (metadata, chat history, recording ID) attached to a commit
   * 
   * @example
   * ```ts
   * const notes = await morphGit.getCommitMetadata({
   *   dir: './my-project',
   *   commitSha: 'abc123...'
   * });
   * 
   * if (notes) {
   *   console.log('Metadata:', notes.metadata);
   *   console.log('Chat history:', notes.chatHistory);
   *   console.log('Recording ID:', notes.recordingId);
   * }
   * ```
   */
  async getCommitMetadata(options) {
    try {
      const note = await import_isomorphic_git.default.readNote({
        fs: import_fs.default,
        dir: options.dir,
        ref: "refs/notes/morph-metadata",
        oid: options.commitSha
      });
      const notes = JSON.parse(new TextDecoder().decode(note));
      return notes;
    } catch (err) {
      return null;
    }
  }
};

// git/index.ts
var import_isomorphic_git2 = __toESM(require("isomorphic-git"), 1);
var import_node2 = __toESM(require("isomorphic-git/http/node"), 1);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  MorphGit,
  git,
  http
});
//# sourceMappingURL=index.cjs.map