{"version":3,"sources":["../src/index.ts","../src/provisioning/hooks.ts"],"sourcesContent":["export const VERSION = '0.10.0'\n\nexport { installPostCommitHook, removePostCommitHook, HOOK_MARKER } from './provisioning/hooks.js'\n","import { existsSync, readFileSync, writeFileSync, chmodSync, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\n\nexport const HOOK_MARKER = '# gsd-munch: auto re-index on commit'\n\n/**\n * Installs a post-commit hook in the given git repo that re-indexes changed files\n * using the jCodeMunch venv Python directly (bypassing MCP protocol).\n *\n * @param repoRoot     Absolute path to the git repository root\n * @param venvPythonPath  Absolute path to the venv Python binary\n * @param pkgPythonDir    Absolute path to the package python/ dir (PYTHONPATH)\n * @returns 'installed'      — hook was created/appended successfully\n *          'already_present' — hook already has the gsd-munch marker (idempotent)\n *          'skipped'         — .git/hooks/ directory not found (not a git repo)\n */\nexport function installPostCommitHook(\n  repoRoot: string,\n  venvPythonPath: string,\n  pkgPythonDir: string,\n): 'installed' | 'already_present' | 'skipped' {\n  const gitHooksDir = join(repoRoot, '.git', 'hooks')\n  if (!existsSync(gitHooksDir)) {\n    return 'skipped'\n  }\n\n  const hookPath = join(gitHooksDir, 'post-commit')\n  const hookScript = buildHookScript(venvPythonPath, pkgPythonDir)\n\n  if (existsSync(hookPath)) {\n    const existing = readFileSync(hookPath, 'utf8')\n    if (existing.includes(HOOK_MARKER)) {\n      return 'already_present'\n    }\n    writeFileSync(hookPath, existing.trimEnd() + '\\n\\n' + hookScript + '\\n', 'utf8')\n  } else {\n    writeFileSync(hookPath, '#!/usr/bin/env bash\\n\\n' + hookScript + '\\n', 'utf8')\n  }\n  chmodSync(hookPath, 0o755)\n  return 'installed'\n}\n\n/**\n * Removes the gsd-munch post-commit hook block from a git repo's post-commit hook.\n * If the hook file only contained the gsd-munch block (plus optional shebang), deletes the file.\n *\n * @param repoRoot  Absolute path to the git repository root\n * @returns true if the hook block was found and removed, false otherwise\n */\nexport function removePostCommitHook(repoRoot: string): boolean {\n  const hookPath = join(repoRoot, '.git', 'hooks', 'post-commit')\n  if (!existsSync(hookPath)) {\n    return false\n  }\n\n  const content = readFileSync(hookPath, 'utf8')\n  if (!content.includes(HOOK_MARKER)) {\n    return false\n  }\n\n  // Remove from HOOK_MARKER to the next blank line after the closing `)`\n  // The block ends with `) &` followed by a newline, so strip from marker to end of block\n  const markerIndex = content.indexOf(HOOK_MARKER)\n  const beforeMarker = content.slice(0, markerIndex).trimEnd()\n\n  // Find the end of the block: look for `) &` after the marker position\n  const afterMarker = content.slice(markerIndex)\n  // The block closes with ) &\\n — find end of that line\n  const blockEndMatch = afterMarker.match(/\\) &\\n?/)\n  let afterBlock = ''\n  if (blockEndMatch && blockEndMatch.index !== undefined) {\n    afterBlock = afterMarker.slice(blockEndMatch.index + blockEndMatch[0].length).trimStart()\n  }\n\n  const cleaned = beforeMarker + (afterBlock ? '\\n\\n' + afterBlock : '')\n\n  // If remaining content is only the shebang line or empty, delete the file\n  const trimmed = cleaned.trim()\n  if (trimmed === '' || trimmed === '#!/usr/bin/env bash') {\n    unlinkSync(hookPath)\n  } else {\n    writeFileSync(hookPath, cleaned + '\\n', 'utf8')\n  }\n\n  return true\n}\n\n/**\n * Builds the post-commit hook shell script block with absolute paths embedded at install time.\n * The entire body runs in a background subshell and swallows all errors.\n */\nfunction buildHookScript(venvPython: string, pkgPythonDir: string): string {\n  return `${HOOK_MARKER}\n(\n  if [ -x \"${venvPython}\" ]; then\n    CHANGED_DIRS=$(git diff-tree --no-commit-id -r --name-only HEAD 2>/dev/null \\\\\n      | xargs -I{} dirname \"{}\" 2>/dev/null | sort -u | head -20)\n    for DIR in $CHANGED_DIRS; do\n      ABS_DIR=$(cd \"$DIR\" 2>/dev/null && pwd || true)\n      if [ -n \"$ABS_DIR\" ]; then\n        \"${venvPython}\" -c \"\nimport sys\nsys.path.insert(0, '${pkgPythonDir}')\nfrom jcodemunch_mcp.tools.index_folder import index_folder\ntry:\n    index_folder('$ABS_DIR')\nexcept Exception as e:\n    import os\n    log = os.path.expanduser('~/.code-index/reindex.log')\n    os.makedirs(os.path.dirname(log), exist_ok=True)\n    open(log, 'a').write(str(e) + '\\\\n')\n\" 2>/dev/null || true\n      fi\n    done\n  fi\n) &`\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,qBAA+E;AAC/E,uBAAqB;AAEd,IAAM,cAAc;AAapB,SAAS,sBACd,UACA,gBACA,cAC6C;AAC7C,QAAM,kBAAc,uBAAK,UAAU,QAAQ,OAAO;AAClD,MAAI,KAAC,2BAAW,WAAW,GAAG;AAC5B,WAAO;AAAA,EACT;AAEA,QAAM,eAAW,uBAAK,aAAa,aAAa;AAChD,QAAM,aAAa,gBAAgB,gBAAgB,YAAY;AAE/D,UAAI,2BAAW,QAAQ,GAAG;AACxB,UAAM,eAAW,6BAAa,UAAU,MAAM;AAC9C,QAAI,SAAS,SAAS,WAAW,GAAG;AAClC,aAAO;AAAA,IACT;AACA,sCAAc,UAAU,SAAS,QAAQ,IAAI,SAAS,aAAa,MAAM,MAAM;AAAA,EACjF,OAAO;AACL,sCAAc,UAAU,4BAA4B,aAAa,MAAM,MAAM;AAAA,EAC/E;AACA,gCAAU,UAAU,GAAK;AACzB,SAAO;AACT;AASO,SAAS,qBAAqB,UAA2B;AAC9D,QAAM,eAAW,uBAAK,UAAU,QAAQ,SAAS,aAAa;AAC9D,MAAI,KAAC,2BAAW,QAAQ,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,QAAM,cAAU,6BAAa,UAAU,MAAM;AAC7C,MAAI,CAAC,QAAQ,SAAS,WAAW,GAAG;AAClC,WAAO;AAAA,EACT;AAIA,QAAM,cAAc,QAAQ,QAAQ,WAAW;AAC/C,QAAM,eAAe,QAAQ,MAAM,GAAG,WAAW,EAAE,QAAQ;AAG3D,QAAM,cAAc,QAAQ,MAAM,WAAW;AAE7C,QAAM,gBAAgB,YAAY,MAAM,SAAS;AACjD,MAAI,aAAa;AACjB,MAAI,iBAAiB,cAAc,UAAU,QAAW;AACtD,iBAAa,YAAY,MAAM,cAAc,QAAQ,cAAc,CAAC,EAAE,MAAM,EAAE,UAAU;AAAA,EAC1F;AAEA,QAAM,UAAU,gBAAgB,aAAa,SAAS,aAAa;AAGnE,QAAM,UAAU,QAAQ,KAAK;AAC7B,MAAI,YAAY,MAAM,YAAY,uBAAuB;AACvD,mCAAW,QAAQ;AAAA,EACrB,OAAO;AACL,sCAAc,UAAU,UAAU,MAAM,MAAM;AAAA,EAChD;AAEA,SAAO;AACT;AAMA,SAAS,gBAAgB,YAAoB,cAA8B;AACzE,SAAO,GAAG,WAAW;AAAA;AAAA,aAEV,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAMZ,UAAU;AAAA;AAAA,sBAEC,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAclC;;;ADpHO,IAAM,UAAU;","names":[]}