ci: enforce strict exit codes in workflow tests
Some checks failed
API Endpoint Tests / test-api-endpoints (push) Failing after 36s
CLI Tests / test-cli (push) Failing after 3m9s
Documentation Validation / validate-docs (push) Successful in 8s
Integration Tests / test-service-integration (push) Failing after 3s
JavaScript SDK Tests / test-js-sdk (push) Successful in 7s
Package Tests / test-python-packages (map[name:aitbc-agent-sdk path:packages/py/aitbc-agent-sdk]) (push) Failing after 8s
Package Tests / test-python-packages (map[name:aitbc-core path:packages/py/aitbc-core]) (push) Failing after 29s
Package Tests / test-python-packages (map[name:aitbc-crypto path:packages/py/aitbc-crypto]) (push) Failing after 13s
Package Tests / test-python-packages (map[name:aitbc-sdk path:packages/py/aitbc-sdk]) (push) Failing after 16s
Package Tests / test-javascript-packages (map[name:aitbc-sdk-js path:packages/js/aitbc-sdk]) (push) Successful in 7s
Package Tests / test-javascript-packages (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Failing after 18s
Python Tests / test-python (push) Failing after 3m37s
Rust ZK Components Tests / test-rust-zk (push) Successful in 28s
Security Scanning / security-scan (push) Failing after 46s
Smart Contract Tests / test-solidity (map[name:aitbc-token path:packages/solidity/aitbc-token]) (push) Failing after 18s
Smart Contract Tests / test-solidity (map[name:zk-circuits path:apps/zk-circuits]) (push) Failing after 43s
Smart Contract Tests / lint-solidity (push) Failing after 12s
Staking Tests / test-staking-service (push) Failing after 2m33s
Staking Tests / test-staking-integration (push) Has been skipped
Staking Tests / test-staking-contract (push) Has been skipped
Staking Tests / run-staking-test-runner (push) Has been skipped
Systemd Sync / sync-systemd (push) Failing after 4s

- Remove `|| echo "⚠️ ..."` fallbacks that masked failures
- Add explicit `exit 1` on port readiness failures and missing test directories
- Track port_ready flag in health check loops to fail if services don't start
- Replace warning emoji (⚠️) with error emoji () for actual failures
- Fix docs-validation to use curated Markdown target list excluding high-noise directories
- Update rust-zk-tests paths from gpu_acceleration/research to dev
This commit is contained in:
aitbc
2026-04-18 11:57:35 +02:00
parent 40698f91fd
commit 23348892b9
34 changed files with 2680 additions and 1445 deletions

View File

@@ -44,31 +44,39 @@ jobs:
run: |
echo "Waiting for AITBC services..."
for port in 8000 8001 8003 8006; do
port_ready=0
for i in $(seq 1 15); do
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/health" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/api/health" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
[ "$i" -eq 15 ] && echo "⚠️ Port $port not ready"
[ "$i" -eq 15 ] && echo " Port $port not ready"
sleep 2
done
if [[ $port_ready -ne 1 ]]; then
exit 1
fi
done
- name: Run API endpoint tests
run: |
cd /var/lib/aitbc-workspaces/api-tests/repo
venv/bin/python scripts/ci/test_api_endpoints.py || echo "⚠️ Some endpoints unavailable"
venv/bin/python scripts/ci/test_api_endpoints.py
echo "✅ API endpoint tests completed"
- name: Cleanup

View File

@@ -49,7 +49,7 @@ jobs:
source venv/bin/activate
export PYTHONPATH="cli:packages/py/aitbc-sdk/src:packages/py/aitbc-crypto/src:."
python3 -c "from core.main import cli; print('✅ CLI imports OK')" || echo "⚠️ CLI import issues"
python3 -c "from core.main import cli; print('✅ CLI imports OK')"
- name: Run CLI tests
run: |
@@ -59,9 +59,10 @@ jobs:
if [[ -d "cli/tests" ]]; then
# Run the CLI test runner that uses virtual environment
python3 cli/tests/run_cli_tests.py || echo "⚠️ Some CLI tests failed"
python3 cli/tests/run_cli_tests.py
else
echo "⚠️ No CLI tests directory"
echo " No CLI tests directory"
exit 1
fi
echo "✅ CLI tests completed"

View File

@@ -5,10 +5,14 @@ on:
branches: [main, develop]
paths:
- 'docs/**'
- '**/*.md'
- '*.md'
- '.gitea/workflows/docs-validation.yml'
pull_request:
branches: [main, develop]
paths:
- 'docs/**'
- '*.md'
- '.gitea/workflows/docs-validation.yml'
workflow_dispatch:
concurrency:
@@ -42,9 +46,32 @@ jobs:
echo "=== Linting Markdown ==="
if command -v markdownlint >/dev/null 2>&1; then
markdownlint "docs/**/*.md" "*.md" \
--ignore "docs/archive/**" \
--ignore "node_modules/**" || echo "⚠️ Markdown linting warnings"
shopt -s globstar nullglob
targets=(
*.md
docs/*.md
docs/11_agents/**/*.md
docs/agent-sdk/**/*.md
docs/blockchain/**/*.md
docs/deployment/**/*.md
docs/development/**/*.md
docs/general/**/*.md
docs/governance/**/*.md
docs/implementation/**/*.md
docs/infrastructure/**/*.md
docs/openclaw/**/*.md
docs/policies/**/*.md
docs/security/**/*.md
docs/workflows/**/*.md
)
if [[ ${#targets[@]} -eq 0 ]]; then
echo "⚠️ No curated Markdown targets matched"
else
echo "Curated advisory scope: ${#targets[@]} Markdown files"
echo "Excluded high-noise areas: about, advanced, archive, backend, beginner, completed, expert, intermediate, project, reports, summaries, trail"
markdownlint "${targets[@]}" --ignore "node_modules/**" || echo "⚠️ Markdown linting warnings in curated docs scope"
fi
else
echo "⚠️ markdownlint not available, skipping"
fi

View File

@@ -30,19 +30,26 @@ jobs:
git clone --depth 1 http://gitea.bubuit.net:3000/oib/aitbc.git repo
- name: Sync systemd files
if: github.event_name != 'pull_request'
run: |
cd /var/lib/aitbc-workspaces/integration-tests/repo
if [[ -d "systemd" ]]; then
echo "Syncing systemd service files..."
for f in systemd/*.service; do
fname=$(basename "$f")
cp "$f" "/etc/systemd/system/$fname" 2>/dev/null || true
done
systemctl daemon-reload
echo "✅ Systemd files synced"
echo "Linking systemd service files..."
if [[ -x /opt/aitbc/scripts/utils/link-systemd.sh ]]; then
if [[ $EUID -eq 0 ]]; then
/opt/aitbc/scripts/utils/link-systemd.sh
else
sudo /opt/aitbc/scripts/utils/link-systemd.sh
fi
echo "✅ Systemd files linked"
else
echo "❌ /opt/aitbc/scripts/utils/link-systemd.sh not found"
exit 1
fi
fi
- name: Start services
if: github.event_name != 'pull_request'
run: |
echo "Starting AITBC services..."
for svc in aitbc-coordinator-api aitbc-exchange-api aitbc-wallet aitbc-blockchain-rpc aitbc-blockchain-node; do
@@ -58,26 +65,34 @@ jobs:
run: |
echo "Waiting for services..."
for port in 8000 8001 8003 8006; do
port_ready=0
for i in $(seq 1 15); do
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/health" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
# Try alternate paths
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/api/health" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
code=$(curl -so /dev/null -w '%{http_code}' "http://localhost:$port/" 2>/dev/null) || code=0
if [ "$code" -gt 0 ] && [ "$code" -lt 600 ]; then
echo "✅ Port $port ready (HTTP $code)"
port_ready=1
break
fi
[ "$i" -eq 15 ] && echo "⚠️ Port $port not ready"
[ "$i" -eq 15 ] && echo " Port $port not ready"
sleep 2
done
if [[ $port_ready -ne 1 ]]; then
exit 1
fi
done
- name: Setup test environment
@@ -97,11 +112,11 @@ jobs:
# Run existing test suites
if [[ -d "tests" ]]; then
pytest tests/ -x --timeout=30 -q || echo "⚠️ Some tests failed"
pytest tests/ -x --timeout=30 -q
fi
# Service health check integration
python3 scripts/ci/test_api_endpoints.py || echo "⚠️ Some endpoints unavailable"
python3 scripts/ci/test_api_endpoints.py
echo "✅ Integration tests completed"
- name: Service status report

View File

@@ -56,13 +56,16 @@ jobs:
- name: Lint
run: |
cd /var/lib/aitbc-workspaces/js-sdk-tests/repo/packages/js/aitbc-sdk
npm run lint 2>/dev/null && echo "✅ Lint passed" || echo "⚠️ Lint skipped"
npx prettier --check "src/**/*.ts" 2>/dev/null && echo "✅ Prettier passed" || echo "⚠️ Prettier skipped"
npm run lint
echo "✅ Lint passed"
npx prettier --check "src/**/*.ts"
echo "✅ Prettier passed"
- name: Run tests
run: |
cd /var/lib/aitbc-workspaces/js-sdk-tests/repo/packages/js/aitbc-sdk
npm test 2>/dev/null && echo "✅ Tests passed" || echo "⚠️ Tests skipped"
npm test
echo "✅ Tests passed"
- name: Cleanup
if: always()

View File

@@ -59,12 +59,12 @@ jobs:
# Install dependencies
if [[ -f "pyproject.toml" ]]; then
pip install -q -e ".[dev]" 2>/dev/null || pip install -q -e . 2>/dev/null || true
pip install -q -e ".[dev]" 2>/dev/null || pip install -q -e .
fi
if [[ -f "requirements.txt" ]]; then
pip install -q -r requirements.txt 2>/dev/null || true
pip install -q -r requirements.txt
fi
pip install -q pytest mypy black 2>/dev/null || true
pip install -q pytest mypy black
# Linting
echo "=== Linting ==="
@@ -76,7 +76,7 @@ jobs:
# Tests
echo "=== Tests ==="
if [[ -d "tests" ]]; then
pytest tests/ -q --tb=short || echo "⚠️ Some tests failed"
pytest tests/ -q --tb=short
else
echo "⚠️ No tests directory found"
fi
@@ -89,10 +89,11 @@ jobs:
cd "$WORKSPACE/repo/${{ matrix.package.path }}"
if [[ -f "pyproject.toml" ]]; then
python3 -m venv venv 2>/dev/null || true
python3 -m venv venv
source venv/bin/activate
pip install -q build 2>/dev/null || true
python -m build 2>/dev/null && echo "✅ Package built" || echo "⚠️ Build failed"
pip install -q build
python -m build
echo "✅ Package built"
fi
- name: Cleanup
@@ -134,7 +135,7 @@ jobs:
node --version
npm --version
npm install --legacy-peer-deps 2>/dev/null || npm install 2>/dev/null || true
npm install --legacy-peer-deps 2>/dev/null || npm install
# Fix missing Hardhat dependencies for aitbc-token
if [[ "${{ matrix.package.name }}" == "aitbc-token" ]]; then
@@ -147,13 +148,15 @@ jobs:
fi
# Build
npm run build && echo "✅ Build passed" || echo "⚠️ Build failed"
npm run build
echo "✅ Build passed"
# Lint
npm run lint 2>/dev/null && echo "✅ Lint passed" || echo "⚠️ Lint skipped"
# Test
npm test && echo "✅ Tests passed" || echo "⚠️ Tests skipped"
npm test
echo "✅ Tests passed"
echo "✅ ${{ matrix.package.name }} completed"

View File

@@ -69,8 +69,8 @@ jobs:
export PYTHONPATH="apps/coordinator-api/src:apps/blockchain-node/src:apps/wallet/src:packages/py/aitbc-crypto/src:packages/py/aitbc-sdk/src:."
# Test if packages are importable
python3 -c "import aitbc_crypto; print('✅ aitbc_crypto imported')" || echo "❌ aitbc_crypto import failed"
python3 -c "import aitbc_sdk; print('✅ aitbc_sdk imported')" || echo "❌ aitbc_sdk import failed"
python3 -c "import aitbc_crypto; print('✅ aitbc_crypto imported')"
python3 -c "import aitbc_sdk; print('✅ aitbc_sdk imported')"
pytest tests/ \
apps/coordinator-api/tests/ \
@@ -79,8 +79,7 @@ jobs:
packages/py/aitbc-crypto/tests/ \
packages/py/aitbc-sdk/tests/ \
--tb=short -q --timeout=30 \
--ignore=apps/coordinator-api/tests/test_confidential*.py \
|| echo "⚠️ Some tests failed"
--ignore=apps/coordinator-api/tests/test_confidential*.py
echo "✅ Python tests completed"

View File

@@ -4,7 +4,7 @@ on:
push:
branches: [main, develop]
paths:
- 'gpu_acceleration/research/gpu_zk_research/**'
- 'dev/gpu/gpu_zk_research/**'
- '.gitea/workflows/rust-zk-tests.yml'
pull_request:
branches: [main, develop]
@@ -40,37 +40,40 @@ jobs:
export CARGO_HOME="$HOME/.cargo"
export PATH="$CARGO_HOME/bin:$PATH"
if ! command -v rustc >/dev/null 2>&1; then
if ! command -v rustup >/dev/null 2>&1; then
echo "Installing Rust..."
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
fi
source "$CARGO_HOME/env" 2>/dev/null || true
source "$CARGO_HOME/env"
rustup default stable
rustc --version
cargo --version
rustup component add rustfmt clippy 2>/dev/null || true
rustup component add rustfmt clippy
- name: Check formatting
run: |
export HOME=/root
export PATH="$HOME/.cargo/bin:$PATH"
source "$HOME/.cargo/env" 2>/dev/null || true
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/gpu_acceleration/research/gpu_zk_research
cargo fmt -- --check 2>/dev/null && echo "✅ Formatting OK" || echo "⚠️ Format warnings"
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/dev/gpu/gpu_zk_research
cargo fmt --all -- --check
echo "✅ Formatting OK"
- name: Run Clippy
run: |
export HOME=/root
export PATH="$HOME/.cargo/bin:$PATH"
source "$HOME/.cargo/env" 2>/dev/null || true
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/gpu_acceleration/research/gpu_zk_research
cargo clippy -- -D warnings 2>/dev/null && echo "✅ Clippy OK" || echo "⚠️ Clippy warnings"
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/dev/gpu/gpu_zk_research
cargo clippy --all-targets -- -D warnings
echo "✅ Clippy OK"
- name: Build
run: |
export HOME=/root
export PATH="$HOME/.cargo/bin:$PATH"
source "$HOME/.cargo/env" 2>/dev/null || true
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/gpu_acceleration/research/gpu_zk_research
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/dev/gpu/gpu_zk_research
cargo build --release
echo "✅ Build completed"
@@ -79,8 +82,9 @@ jobs:
export HOME=/root
export PATH="$HOME/.cargo/bin:$PATH"
source "$HOME/.cargo/env" 2>/dev/null || true
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/gpu_acceleration/research/gpu_zk_research
cargo test && echo "✅ Tests passed" || echo "⚠️ Tests completed with issues"
cd /var/lib/aitbc-workspaces/rust-zk-tests/repo/dev/gpu/gpu_zk_research
cargo test --all-targets
echo "✅ Tests passed"
- name: Cleanup
if: always()

View File

@@ -41,7 +41,7 @@ jobs:
python3 -m venv venv
source venv/bin/activate
pip install -q bandit safety pip-audit
pip install -q bandit pip-audit
echo "✅ Security tools installed"
- name: Python dependency audit
@@ -49,7 +49,7 @@ jobs:
cd /var/lib/aitbc-workspaces/security-scan/repo
source venv/bin/activate
echo "=== Dependency Audit ==="
pip-audit -r requirements.txt --desc 2>/dev/null || echo "⚠️ Some vulnerabilities found"
pip-audit -r requirements.txt --desc
echo "✅ Dependency audit completed"
- name: Bandit security scan
@@ -60,7 +60,7 @@ jobs:
bandit -r apps/ packages/py/ cli/ \
-s B101,B311 \
--severity-level medium \
-f txt -q 2>/dev/null || echo "⚠️ Bandit findings"
-f txt -q
echo "✅ Bandit scan completed"
- name: Check for secrets
@@ -68,8 +68,28 @@ jobs:
cd /var/lib/aitbc-workspaces/security-scan/repo
echo "=== Secret Detection ==="
# Simple pattern check for leaked secrets
grep -rn "PRIVATE_KEY\s*=\s*['\"]" apps/ packages/ cli/ 2>/dev/null | grep -v "example\|test\|mock\|dummy" && echo "⚠️ Possible secrets found" || echo "✅ No secrets detected"
grep -rn "password\s*=\s*['\"][^'\"]*['\"]" apps/ packages/ cli/ 2>/dev/null | grep -v "example\|test\|mock\|dummy\|placeholder" | head -5 && echo "⚠️ Possible hardcoded passwords" || echo "✅ No hardcoded passwords"
secret_matches=$(mktemp)
password_matches=$(mktemp)
grep -RInE "PRIVATE_KEY[[:space:]]*=[[:space:]]*['\"]" apps/ packages/ cli/ 2>/dev/null | grep -v "example\|test\|mock\|dummy" > "$secret_matches" || true
grep -RInE "password[[:space:]]*=[[:space:]]*['\"][^'\"]*['\"]" apps/ packages/ cli/ 2>/dev/null | grep -v "example\|test\|mock\|dummy\|placeholder" > "$password_matches" || true
if [[ -s "$secret_matches" ]]; then
echo "❌ Possible secrets found"
cat "$secret_matches"
rm -f "$secret_matches" "$password_matches"
exit 1
fi
if [[ -s "$password_matches" ]]; then
echo "❌ Possible hardcoded passwords"
head -5 "$password_matches"
rm -f "$secret_matches" "$password_matches"
exit 1
fi
rm -f "$secret_matches" "$password_matches"
echo "✅ No hardcoded secrets detected"
- name: Cleanup
if: always()

View File

@@ -54,28 +54,44 @@ jobs:
echo "Node: $(node --version), npm: $(npm --version)"
# Install
npm install --legacy-peer-deps 2>/dev/null || npm install 2>/dev/null || true
npm install --legacy-peer-deps 2>/dev/null || npm install
# Fix missing Hardhat dependencies for aitbc-token
if [[ "${{ matrix.project.name }}" == "aitbc-token" ]]; then
echo "Installing missing Hardhat dependencies..."
npm install --save-dev "@nomicfoundation/hardhat-ignition@^0.15.16" "@nomicfoundation/ignition-core@^0.15.15" 2>/dev/null || true
# Fix formatting issues
echo "Fixing formatting issues..."
npm run format 2>/dev/null || echo "⚠️ Format fix failed"
npm install --no-save "@nomicfoundation/hardhat-ignition@^0.15.16" "@nomicfoundation/ignition-core@^0.15.15"
fi
# Compile
if [[ -f "hardhat.config.js" ]] || [[ -f "hardhat.config.ts" ]]; then
npx hardhat compile && echo "✅ Compiled" || echo "⚠️ Compile failed"
npx hardhat test && echo "✅ Tests passed" || echo "⚠️ Tests failed"
npx hardhat compile
echo "✅ Compiled"
npx hardhat test
echo "✅ Tests passed"
elif [[ -f "foundry.toml" ]]; then
forge build && echo "✅ Compiled" || echo "⚠️ Compile failed"
forge test && echo "✅ Tests passed" || echo "⚠️ Tests failed"
forge build
echo "✅ Compiled"
forge test
echo "✅ Tests passed"
else
npm run build 2>/dev/null || echo "⚠️ No build script"
npm test 2>/dev/null || echo "⚠️ No test script"
if node -e "const pkg=require('./package.json'); process.exit(pkg.scripts && pkg.scripts.compile ? 0 : 1)"; then
npm run compile
echo "✅ Compiled"
elif node -e "const pkg=require('./package.json'); process.exit(pkg.scripts && pkg.scripts.build ? 0 : 1)"; then
npm run build
echo "✅ Compiled"
else
echo "❌ No compile or build script found"
exit 1
fi
if node -e "const pkg=require('./package.json'); process.exit(pkg.scripts && pkg.scripts.test ? 0 : 1)"; then
npm test
echo "✅ Tests passed"
else
echo "❌ No test script found"
exit 1
fi
fi
echo "✅ ${{ matrix.project.name }} completed"
@@ -108,19 +124,20 @@ jobs:
if [[ -d "$project" ]] && [[ -f "$project/package.json" ]]; then
echo "=== Linting $project ==="
cd "$project"
npm install --legacy-peer-deps 2>/dev/null || npm install 2>/dev/null || true
npm install --legacy-peer-deps 2>/dev/null || npm install
# Fix missing Hardhat dependencies and formatting for aitbc-token
if [[ "$project" == "packages/solidity/aitbc-token" ]]; then
echo "Installing missing Hardhat dependencies..."
npm install --save-dev "@nomicfoundation/hardhat-ignition@^0.15.16" "@nomicfoundation/ignition-core@^0.15.15" 2>/dev/null || true
# Fix formatting issues
echo "Fixing formatting issues..."
npm run format 2>/dev/null || echo "⚠️ Format fix failed"
npm install --no-save "@nomicfoundation/hardhat-ignition@^0.15.16" "@nomicfoundation/ignition-core@^0.15.15"
fi
if node -e "const pkg=require('./package.json'); process.exit(pkg.scripts && pkg.scripts.lint ? 0 : 1)"; then
npm run lint
echo "✅ Lint passed"
else
echo "⚠️ No lint script for $project, skipping"
fi
npm run lint 2>/dev/null && echo "✅ Lint passed" || echo "⚠️ Lint skipped"
cd /var/lib/aitbc-workspaces/solidity-lint/repo
fi
done

View File

@@ -131,7 +131,8 @@ jobs:
cd /var/lib/aitbc-workspaces/staking-contract/repo/contracts
echo "🧪 Running staking contract tests..."
npx hardhat test test/AgentStaking.test.js || echo "⚠️ Contract tests blocked by compilation errors"
npx hardhat compile
npx hardhat test test/AgentStaking.test.js
echo "✅ Contract tests completed"
- name: Cleanup
@@ -141,7 +142,7 @@ jobs:
run-staking-test-runner:
runs-on: debian
timeout-minutes: 25
needs: [test-staking-service, test-staking-integration]
needs: [test-staking-service, test-staking-integration, test-staking-contract]
steps:
- name: Clone repository

View File

@@ -57,7 +57,12 @@ jobs:
echo "=== Found $(ls systemd/*.service 2>/dev/null | wc -l) service files, $errors errors ==="
if [[ $errors -gt 0 ]]; then
exit 1
fi
- name: Sync service files
if: github.event_name != 'pull_request'
run: |
cd /var/lib/aitbc-workspaces/systemd-sync/repo
@@ -66,11 +71,16 @@ jobs:
fi
echo "=== Syncing systemd files ==="
for f in systemd/*.service; do
fname=$(basename "$f")
cp "$f" "/etc/systemd/system/$fname"
echo " ✅ $fname synced"
done
if [[ -x /opt/aitbc/scripts/utils/link-systemd.sh ]]; then
if [[ $EUID -eq 0 ]]; then
/opt/aitbc/scripts/utils/link-systemd.sh
else
sudo /opt/aitbc/scripts/utils/link-systemd.sh
fi
else
echo "⚠️ /opt/aitbc/scripts/utils/link-systemd.sh not found"
exit 1
fi
systemctl daemon-reload
echo "✅ Systemd daemon reloaded"