#!/usr/bin/env bash # 组合指针一致:容器仓在 Dev 钉住的提交上,deps/ 里的每个 gitlink # 必须等于 Dev 顶层对应指针。development-guidelines 只告警。 set -euo pipefail root=$(cd "$(dirname "$0")/.." && pwd) cd "$root" # New layouts have one version authority per dependency kind. Inspect the formal # source map when supplied, otherwise verify prepared fixed application sources. if [ -f components.json ]; then python3 - "$root" <<'PYCODE' import importlib.util, json, os, pathlib, subprocess, sys root = pathlib.Path(sys.argv[1]) sys.path.insert(0, str(root / "scripts")) spec = importlib.util.spec_from_file_location("component_source", root / "scripts/component-source.py") resolver = importlib.util.module_from_spec(spec); spec.loader.exec_module(resolver) try: document = json.loads((root / "components.json").read_text()) components = {entry["id"]: entry for entry in document["components"]} marker = os.environ.get("COMPOSITION_SOURCE_MAP") if marker: names = [name for name in json.loads(pathlib.Path(marker).read_text())["components"] if name in components] else: names = [name for name, entry in components.items() if entry["role"] == "application"] for name in names: component = components[name] path = resolver.source_path(root, name) if component["role"] == "application" and (path / ".gitmodules").exists(): raise ValueError("legacy gitlink declaration remains in fixed source: " + name) for module in component.get("modules", []): directory = path / module.get("directory", ".") if not (directory / "go.mod").is_file(): raise ValueError("declared module source is missing: " + name) env = os.environ | {"GOWORK": "off", "GOTOOLCHAIN": "local"} result = subprocess.run(["go", "mod", "edit", "-json"], cwd=directory, env=env, capture_output=True, text=True) if result.returncode: raise ValueError("Go module cannot be parsed: " + name) parsed = json.loads(result.stdout) if parsed["Module"]["Path"] != module["path"]: raise ValueError("module identity differs from approved mapping: " + name) if any(not replacement["New"].get("Version") for replacement in parsed.get("Replace") or []): raise ValueError("local replace in fixed source: " + name) npm_lock = path / "package-lock.json" if npm_lock.exists(): for entry in json.loads(npm_lock.read_text()).get("packages", {}).values(): if entry.get("link") or str(entry.get("resolved", "")).startswith(("file:", "link:")): raise ValueError("local npm overlay in fixed source: " + name) print("ok fixed source " + name) if not names: raise ValueError("fixed application sources are missing") except (ValueError, KeyError, TypeError, OSError) as error: print("pin: " + str(error), file=sys.stderr); sys.exit(1) print("version authorities ok (source lock / go.mod / npm lock; no gitlink alignment)") PYCODE exit $? fi fail=0 pin_of() { git rev-parse ":$1" } check_link() { local container="$1" name="$2" sha="$3" expect_path="$4" local expect if ! expect=$(pin_of "$expect_path" 2>/dev/null); then echo "pin: $container deps/$name has no Dev pin at $expect_path" >&2 fail=1 return fi if [ "$sha" != "$expect" ]; then local sha_tree expect_tree if ! sha_tree=$(git -C "$expect_path" rev-parse "${sha}^{tree}" 2>/dev/null); then echo "pin: $container deps/$name ${sha:0:12} is missing locally; fetch $expect_path first" >&2 fail=1 return fi if ! expect_tree=$(git -C "$expect_path" rev-parse "${expect}^{tree}" 2>/dev/null); then echo "pin: Dev $expect_path ${expect:0:12} is missing locally; fetch $expect_path first" >&2 fail=1 return fi if [ "$sha_tree" = "$expect_tree" ]; then echo "ok $container $name (same tree)" return fi echo "pin: $container deps/$name is ${sha:0:12}, Dev $expect_path is ${expect:0:12}" >&2 fail=1 return fi echo "ok $container $name" } containers=(modules/backend deps/agent-native deps/agent-squad deps/agent-intent) for container in "${containers[@]}"; do commit=$(pin_of "$container") while read -r mode _typ sha name; do [ "$mode" = "160000" ] || continue base=${name#deps/} if [ "$base" = "development-guidelines" ]; then dev=$(pin_of deps/development-guidelines) if [ "$sha" != "$dev" ]; then echo "warn: $container deps/development-guidelines is ${sha:0:12}, Dev is ${dev:0:12}" >&2 fi continue fi if [ "$base" = "agent-system-core" ]; then check_link "$container" "$base" "$sha" modules/core else check_link "$container" "$base" "$sha" "deps/$base" fi done < <(git -C "$container" ls-tree "$commit" deps/) done if [ "$fail" -ne 0 ]; then exit 1 fi echo "pins ok"