@@ -283,30 +283,179 @@ install_mcp_entrypoint() {
283283 fi
284284
285285 mkdir -p " ${INSTALL_DIR} "
286- cat > " ${MCP_ENTRYPOINT} " << EOF
286+ cat > " ${MCP_ENTRYPOINT} " << EOF
287287#!/usr/bin/env bash
288288set -eo pipefail
289289
290290BIN="${INSTALL_DIR} /${BINARY_NAME} "
291+ ACB_BIN="${INSTALL_DIR} /acb"
292+
293+ pwd_is_project() {
294+ [ -d "\$ PWD/.git" ] || \
295+ [ -f "\$ PWD/Cargo.toml" ] || \
296+ [ -f "\$ PWD/package.json" ] || \
297+ [ -f "\$ PWD/pyproject.toml" ] || \
298+ [ -f "\$ PWD/go.mod" ] || \
299+ [ -d "\$ PWD/src" ]
300+ }
301+
302+ pwd_contains_projects() {
303+ find "\$ PWD" -maxdepth 2 -type f \
304+ \\ ( -name 'Cargo.toml' -o -name 'package.json' -o -name 'pyproject.toml' -o -name 'go.mod' \\ ) \
305+ -print -quit 2>/dev/null | grep -q .
306+ }
307+
308+ resolve_repo_root() {
309+ if [ -n "\$ {AGENTRA_WORKSPACE_ROOT:-}" ] && [ -d "\$ {AGENTRA_WORKSPACE_ROOT}" ]; then
310+ printf '%s' "\$ {AGENTRA_WORKSPACE_ROOT}"
311+ return
312+ fi
313+ if [ -n "\$ {AGENTRA_PROJECT_ROOT:-}" ] && [ -d "\$ {AGENTRA_PROJECT_ROOT}" ]; then
314+ printf '%s' "\$ {AGENTRA_PROJECT_ROOT}"
315+ return
316+ fi
317+ if pwd_is_project || pwd_contains_projects; then
318+ printf '%s' "\$ PWD"
319+ return
320+ fi
321+ if command -v git >/dev/null 2>&1; then
322+ local root
323+ root="\$ (git rev-parse --show-toplevel 2>/dev/null || true)"
324+ if [ -n "\$ root" ] && [ -d "\$ root" ]; then
325+ if [ "\$ root" = "\$ HOME" ] || [ "\$ root" = "\$ HOME/Documents" ] || [ "\$ root" = "\$ HOME/Desktop" ]; then
326+ printf '%s' "\$ PWD"
327+ return
328+ fi
329+ printf '%s' "\$ root"
330+ return
331+ fi
332+ fi
333+ printf '%s' "\$ PWD"
334+ }
335+
336+ slugify() {
337+ local raw="\$ 1"
338+ local base
339+ base="\$ (basename "\$ raw")"
340+ base="\$ (printf '%s' "\$ base" | tr '[:upper:]' '[:lower:]')"
341+ base="\$ (printf '%s' "\$ base" | sed -E 's/[^a-z0-9._-]+/-/g; s/^-+//; s/-+\$ //')"
342+ if [ -z "\$ base" ]; then
343+ base="workspace"
344+ fi
345+ printf '%s' "\$ base"
346+ }
347+
348+ can_index_repo() {
349+ local repo_root="\$ 1"
350+ if [ "\$ repo_root" = "\$ HOME" ]; then
351+ return 1
352+ fi
353+ if command -v git >/dev/null 2>&1 && git -C "\$ repo_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
354+ return 0
355+ fi
356+ find "\$ repo_root" -maxdepth 2 -type f \
357+ \\ ( -name '*.rs' -o -name '*.py' -o -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' \
358+ -o -name '*.go' -o -name '*.java' -o -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \\ ) \
359+ -print -quit 2>/dev/null | grep -q .
360+ }
361+
362+ graph_is_stale() {
363+ local repo_root="\$ 1"
364+ local graph_path="\$ 2"
365+ [ ! -f "\$ graph_path" ] && return 0
366+ find "\$ repo_root" \
367+ \\ ( -name .git -o -name target -o -name node_modules -o -name .venv -o -name venv -o -name dist -o -name build -o -name .next \\ ) -prune -o \
368+ -type f \
369+ \\ ( -name '*.rs' -o -name '*.py' -o -name '*.ts' -o -name '*.tsx' -o -name '*.js' -o -name '*.jsx' \
370+ -o -name '*.go' -o -name '*.java' -o -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \\ ) \
371+ -newer "\$ graph_path" -print -quit 2>/dev/null | grep -q .
372+ }
373+
374+ compile_graph_if_needed() {
375+ local repo_root="\$ 1"
376+ local graph_path="\$ 2"
377+ if ! can_index_repo "\$ repo_root"; then
378+ return 0
379+ fi
380+ if [ -f "\$ graph_path" ] && ! graph_is_stale "\$ repo_root" "\$ graph_path"; then
381+ return 0
382+ fi
383+
384+ local lock_dir="\$ {graph_path}.lock"
385+ local wait_count=0
386+ while ! mkdir "\$ lock_dir" 2>/dev/null; do
387+ wait_count=\$ ((wait_count + 1))
388+ if [ "\$ wait_count" -ge 90 ]; then
389+ echo "Warning: graph build lock timeout for \$ graph_path" >&2
390+ return 0
391+ fi
392+ sleep 1
393+ done
394+ trap 'rmdir "'"'\$ lock_dir'"'" >/dev/null 2>&1 || true' RETURN
395+
396+ if [ -f "\$ graph_path" ] && ! graph_is_stale "\$ repo_root" "\$ graph_path"; then
397+ return 0
398+ fi
399+ mkdir -p "\$ (dirname "\$ graph_path")"
400+ if [ -x "\$ ACB_BIN" ]; then
401+ "\$ ACB_BIN" compile "\$ repo_root" -o "\$ graph_path" >/dev/null 2>&1 || true
402+ elif command -v acb >/dev/null 2>&1; then
403+ acb compile "\$ repo_root" -o "\$ graph_path" >/dev/null 2>&1 || true
404+ fi
405+ if [ ! -f "\$ graph_path" ]; then
406+ echo "Error: unable to build code graph for \$ repo_root" >&2
407+ return 1
408+ fi
409+ }
410+
411+ latest_cached_graph() {
412+ local graph_dir="\$ 1"
413+ if [ -d "\$ graph_dir" ]; then
414+ find "\$ graph_dir" -maxdepth 1 -type f -name '*.acb' -print0 2>/dev/null \
415+ | xargs -0 ls -1t 2>/dev/null | head -n 1
416+ fi
417+ }
291418
292- find_graph () {
419+ resolve_graph () {
293420 local candidate
294- local found=""
295-
296- for candidate in \
297- "\$ {AGENTRA_ACB_PATH:-}" \
298- "\$ {AGENTRA_GRAPH_PATH:-}" \
299- "\$ {CODEX_HOME:-\$ HOME/.codex}/graphs/agentralabs-tech.acb" \
300- "\$ HOME/.agentra/graphs/default.acb" \
301- "\$ PWD/agentralabs-tech.acb" \
302- "\$ PWD/graph.acb"; do
421+ local explicit
422+ explicit=""
423+ for candidate in "\$ {AGENTRA_ACB_PATH:-}" "\$ {AGENTRA_GRAPH_PATH:-}"; do
303424 if [ -n "\$ candidate" ] && [ -f "\$ candidate" ]; then
304- found ="\$ candidate"
425+ explicit ="\$ candidate"
305426 break
306427 fi
307428 done
429+ if [ -n "\$ explicit" ]; then
430+ printf '%s' "\$ explicit"
431+ return
432+ fi
433+
434+ local repo_root repo_slug graph_dir graph_path fallback
435+ repo_root="\$ (resolve_repo_root)"
436+ repo_slug="\$ (slugify "\$ repo_root")"
437+ graph_dir="\$ {AGENTRA_GRAPH_CACHE_DIR:-\$ {CODEX_HOME:-\$ HOME/.codex}/graphs}"
438+ graph_path="\$ {graph_dir}/\$ {repo_slug}.acb"
439+
440+ if compile_graph_if_needed "\$ repo_root" "\$ graph_path"; then
441+ if [ -f "\$ graph_path" ]; then
442+ printf '%s' "\$ graph_path"
443+ return
444+ fi
445+ fi
308446
309- [ -n "\$ found" ] && printf '%s' "\$ found"
447+ fallback="\$ (latest_cached_graph "\$ graph_dir")"
448+ if [ -n "\$ fallback" ] && [ -f "\$ fallback" ]; then
449+ printf '%s' "\$ fallback"
450+ return
451+ fi
452+
453+ for candidate in "\$ HOME/.agentra/graphs/default.acb" "\$ PWD/graph.acb"; do
454+ if [ -f "\$ candidate" ]; then
455+ printf '%s' "\$ candidate"
456+ break
457+ fi
458+ done
310459}
311460
312461args=("\$ @")
@@ -326,11 +475,11 @@ for arg in "\${args[@]}"; do
326475done
327476
328477if [ "\$ has_graph" -eq 0 ]; then
329- graph_path="\$ (find_graph || true)"
478+ graph_path="\$ (resolve_graph || true)"
330479 if [ -n "\$ graph_path" ]; then
331480 args=(--graph "\$ graph_path" "\$ {args[@]}")
332481 if [ "\$ has_name" -eq 0 ]; then
333- graph_name="\$ (basename "\$ graph_path" .acb)"
482+ graph_name="\$ (basename "\$ graph_path" .acb | sed -E 's/[^a-zA-Z0-9._-]+/-/g' )"
334483 args=(--name "\$ graph_name" "\$ {args[@]}")
335484 fi
336485 fi
0 commit comments