#!/usr/bin/env bash
# SPDX-License-Identifier: Apache-2.0
# AgentAnchor ghost-agent local scanner (macOS / Linux) — READ-ONLY.
#
# What it does: enumerates local signals of AI agents / inference — accelerators,
# model files, inference processes, listening ports, AI dependencies, AI-related
# env-var NAMES, and MCP/IaC config file names — and prints a report you paste
# into agentanchorai.com/scan.
#
# Privacy & safety:
#   * READ-ONLY. It never writes, installs, or changes anything.
#   * It prints file/process/port/dependency/env-var NAMES only — never the
#     CONTENTS of any file and never the VALUE of any secret/env var.
#   * Nothing is uploaded. You review this output, then choose to paste it.
#   * Review the script before running it — that's the point of a download.
#
# Usage:  bash agentscan.sh   (then copy the output into /scan)

set -u
LC_ALL=C
line() { printf '%s\n' "$1"; }
have() { command -v "$1" >/dev/null 2>&1; }
# Portable timeout: GNU coreutils `timeout` on Linux, `gtimeout` via Homebrew on
# macOS, or none (stock macOS has neither). Output stays bounded by `head` and
# `find -maxdepth` regardless, so running without a timeout is still safe.
TO="$(command -v timeout || command -v gtimeout || true)"
run() {
  if [ -n "$TO" ]; then "$TO" 12 bash -c "$1" 2>/dev/null | head -n "${2:-40}"
  else bash -c "$1" 2>/dev/null | head -n "${2:-40}"; fi
}

line "=== AgentAnchor local ghost-agent scan (read-only) ==="
line "# host: $(uname -s 2>/dev/null) $(uname -m 2>/dev/null) | $(date 2>/dev/null)"

line ""; line "## L0 accelerators"
have nvidia-smi && run "nvidia-smi --query-compute-apps=process_name,used_gpu_memory --format=csv,noheader" 20
have rocm-smi && run "rocm-smi --showpids" 20
have hl-smi && line "hl-smi present (Intel Gaudi)"
run "ls -1 /dev/nvidia* /dev/kfd /dev/accel* /dev/dri/render* 2>/dev/null" 20
have lsmod && run "lsmod | awk '{print \$1}' | grep -Ei 'nvidia_uvm|nvidia_drm|amdxdna|habanalabs|intel_vpu'" 10
have ldconfig && run "ldconfig -p | grep -Eoi 'lib(cudart|cublas|cudnn|nvinfer|amdhip64|rocblas|MIOpen|tpu|openvino)[a-z0-9._-]*' | sort -u" 20
[ "$(uname -s)" = "Darwin" ] && run "lsof -c ollama -c python -c mlx_lm 2>/dev/null | grep -Eoi 'Metal|CoreML|MPSGraph|libmlx' | sort -u" 10

line ""; line "## L1 model files & caches (names only)"
for d in "$HOME/.ollama/models" "$HOME/.cache/huggingface/hub" "$HOME/.cache/lm-studio" "$HOME/.cache/gpt4all" "$HOME/Library/Application Support/nomic.ai" "$HOME/.lmstudio"; do
  [ -d "$d" ] && line "cache-dir: ${d##*/}  (present)"
done
run "find \"$HOME\" -maxdepth 5 \\( -name '*.gguf' -o -name '*.safetensors' -o -name '*.onnx' -o -name '*.ggml' -o -name '*.mlmodel' \\) -printf '%f\\n' 2>/dev/null || find \"$HOME\" -maxdepth 5 \\( -name '*.gguf' -o -name '*.safetensors' -o -name '*.onnx' \\) 2>/dev/null -exec basename {} \\;" 30
run "find \"$HOME\" -maxdepth 6 \\( -name 'chroma.sqlite3' -o -name '*.faiss' -o -name 'lance' -o -name 'qdrant' \\) -printf '%f\\n' 2>/dev/null || find \"$HOME\" -maxdepth 6 \\( -name 'chroma.sqlite3' -o -name '*.faiss' \\) 2>/dev/null -exec basename {} \\;" 15

line ""; line "## L2 inference & agent processes"
run "ps axco command 2>/dev/null | grep -Ei '^(ollama|vllm|llama-server|llama.cpp|lmstudio|localai|koboldcpp|sglang|tabbyapi|text-generation|mlx_lm|mcp-server|langgraph|crewai)' | sort -u || ps -eo comm 2>/dev/null | grep -Ei 'ollama|vllm|llama-server|lmstudio|localai|koboldcpp|sglang|mlx_lm|mcp-server' | sort -u" 30

line ""; line "## L3 listening ports & AI egress"
if have ss; then run "ss -tlnH 2>/dev/null | awk '{print \$4}' | grep -Eo '(11434|8000|7860|1234|8080|5000|11435|8001)$' | sort -u" 15
elif have netstat; then run "netstat -an 2>/dev/null | grep LISTEN | grep -Eo '[.:](11434|8000|7860|1234|8080|5000)\\b' | sort -u" 15
elif have lsof; then run "lsof -nP -iTCP -sTCP:LISTEN 2>/dev/null | grep -Eo ':(11434|8000|7860|1234|8080)\\b' | sort -u" 15; fi
have lsof && run "lsof -nP -iTCP -sTCP:ESTABLISHED 2>/dev/null | grep -Eio '(openai|anthropic|googleapis|mistral|cohere|groq|together|openrouter|perplexity|replicate|huggingface|deepseek|fireworks|x.ai)' | sort -u" 15
run "ps axo command 2>/dev/null | grep -Eio '\\b(ngrok|cloudflared|frpc?|localtunnel|tailscale)\\b' | sort -u" 10

line ""; line "## L4 AI dependencies (package names only)"
run "find . \"$HOME\" -maxdepth 4 \\( -name package.json -o -name requirements.txt -o -name pyproject.toml \\) 2>/dev/null | head -n 30 | xargs -I{} grep -hEio '\"?(openai|anthropic|@anthropic-ai/sdk|langchain|@langchain/[a-z]+|langgraph|llama-?index|llama-cpp-python|transformers|torch|vllm|ollama|litellm|crewai|autogen|dspy|semantic-kernel|@ai-sdk/[a-z]+|guidance|smolagents)\"?' {} 2>/dev/null | tr -d '\"' | sort -u" 40

line ""; line "## L5 AI env-var NAMES (values never read) & MCP configs"
run "printenv 2>/dev/null | cut -d= -f1 | grep -Ei 'OPENAI|ANTHROPIC|GOOGLE_API|GEMINI|GROQ|MISTRAL|TOGETHER|COHERE|REPLICATE|HF_TOKEN|HUGGINGFACE|OLLAMA_HOST|AZURE_OPENAI|BEDROCK|OPENROUTER|LANGCHAIN|LANGSMITH|DEEPSEEK|PERPLEXITY|FIREWORKS|XAI' | sort -u" 30
for f in "$HOME/Library/Application Support/Claude/claude_desktop_config.json" "$HOME/.config/Claude/claude_desktop_config.json" "$HOME/.cursor/mcp.json" "$PWD/.mcp.json" "$PWD/.cursor/mcp.json"; do
  [ -f "$f" ] && line "mcp-config: $(basename "$f")  (present)"
done

line ""; line "## L6 cloud / k8s AI (manifest names & resource types)"
run "find . -maxdepth 4 \\( -name '*.tf' -o -name '*.yaml' -o -name '*.yml' \\) 2>/dev/null | head -n 40 | xargs -I{} grep -hEio '(aws_bedrock[a-z_]*|google_vertex[a-z_]*|azurerm_cognitive|sagemaker|aiplatform|vllm|text-generation-inference|kserve|seldon|ray-?serve)' {} 2>/dev/null | sort -u" 30

line ""; line "=== end of scan — paste everything above into agentanchorai.com/scan ==="
