#!/usr/bin/env bash # 依赖边界:公开扩展 SDK 与示例不得导入后端 internal。 # pkg/extension/link 是唯一例外:下游空白导入它才能把 extension.Main 接到产品组合根。 set -euo pipefail root=$(cd "$(dirname "$0")/.." && pwd) fail=0 check() { local path="$1" if [ -d "$path" ] && grep -R -n --include='*.go' --include='*.ts' --include='*.tsx' 'agent-system-backend/internal' "$path" >/dev/null; then echo "boundary: $path imports agent-system-backend/internal" >&2 grep -R -n --include='*.go' --include='*.ts' --include='*.tsx' 'agent-system-backend/internal' "$path" >&2 fail=1 fi } sdk="$root/modules/backend/pkg/extension" if [ -d "$sdk" ]; then hits=$(grep -R -n --include='*.go' 'agent-system-backend/internal' "$sdk" | grep -v '/link/' || true) if [ -n "$hits" ]; then echo "boundary: pkg/extension imports agent-system-backend/internal" >&2 echo "$hits" >&2 fail=1 fi fi check "$root/examples" # 库间依赖棘轮:三个库的包导入兄弟库的配对,相对白名单只许减少、不许新增。 allow="$root/policy/lib-deps-allowlist.txt" observed=$(mktemp) recorded=$(mktemp) trap 'rm -f "$observed" "$recorded"' EXIT siblings=(agent-intent agent-native agent-squad) for dir in deps/agent-intent deps/agent-native deps/agent-squad; do mod=$(awk '/^module /{print $2; exit}' "$root/$dir/go.mod") ( cd "$root/scripts" go run lint-imports.go "$root/$dir" ) | while read -r importer rest; do for imp in $rest; do for sib in "${siblings[@]}"; do case "$imp" in "$sib"|"$sib"/*) ;; *) continue ;; esac case "$importer" in "$mod"|"$mod"/*) ;; *) continue ;; esac if [ "$sib" != "$mod" ]; then echo "$importer $imp" fi done done done done | sort -u >"$observed" grep -v -e '^#' -e '^$' "$allow" | sort -u >"$recorded" || true new_pairs=$(comm -13 "$recorded" "$observed" || true) if [ -n "$new_pairs" ]; then echo "boundary: new sibling-library import pairs" >&2 echo "$new_pairs" >&2 fail=1 fi stale_pairs=$(comm -23 "$recorded" "$observed" || true) if [ -n "$stale_pairs" ]; then echo "warn: sibling-library pairs no longer imported; delete from policy/lib-deps-allowlist.txt" >&2 echo "$stale_pairs" >&2 fi # 核心模块的依赖图不得出现兄弟库。go list ./... 不进入带 go.mod 的子目录。 for dir in deps/agent-intent deps/agent-native deps/agent-squad; do mod=$(awk '/^module /{print $2; exit}' "$root/$dir/go.mod") deps_out=$(cd "$root/$dir" && GOWORK=off go list -deps ./...) || fail=1 for sib in "${siblings[@]}"; do [ "$sib" = "$mod" ] && continue if grep -E -q "^(${sib}|${sib}/)" <<<"$deps_out"; then echo "boundary: $mod core depends on $sib" >&2 fail=1 fi done done # agent-intent 只许被小队意图适配器和后端识别适配器导入。 while IFS= read -r f; do grep -q '"agent-intent/' "$f" || continue case "$f" in */deps/agent-squad/adapters/intent/*|*/modules/backend/internal/intentgate/*|*/modules/backend/internal/intentsem/*) ;; *) echo "boundary: $f imports agent-intent" >&2 fail=1 ;; esac done < <(find "$root/deps/agent-native" "$root/deps/agent-squad" "$root/modules/backend" \ -path '*/deps/*' -prune -o -name '*.go' -print) if [ "$fail" -ne 0 ]; then exit 1 fi bash "$root/scripts/lint-architecture.sh" echo "boundaries ok"