-
Notifications
You must be signed in to change notification settings - Fork 23
fix: convert #subdirectory= fragment to path component for local path… #163
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -296,9 +296,9 @@ def _build_include_source_resolver( | |
| resolver("git+https://github.com/org/amplifier-bundle-superpowers@main") | ||
| # -> "/local/path/superpowers" | ||
|
|
||
| # Fragment preservation: | ||
| # Fragment preservation — git URL override keeps the fragment: | ||
| resolver("git+https://github.com/org/amplifier-bundle-superpowers@main#subdirectory=foo.yaml") | ||
| # -> "/local/path/superpowers#subdirectory=foo.yaml" | ||
| # -> "/local/path/superpowers/foo.yaml" (subdirectory converted to path for local overrides) | ||
| """ | ||
| if not bundle_overrides: | ||
| return lambda _: None | ||
|
|
@@ -310,6 +310,13 @@ def resolver(source: str) -> str | None: | |
| # preserve the fragment from the original. | ||
| if "#" in source and "#" not in override: | ||
| fragment = source.split("#", 1)[1] | ||
| # For local path overrides, #subdirectory=path is a git-only | ||
| # convention and is not meaningful as a file path. Convert it | ||
| # to a path component instead. | ||
| is_local = not (override.startswith("git+") or "://" in override) | ||
| if is_local and fragment.startswith("subdirectory="): | ||
|
Comment on lines
+313
to
+317
|
||
| subdir = fragment.removeprefix("subdirectory=") | ||
| return f"{override}/{subdir}" | ||
|
Comment on lines
+317
to
+319
|
||
| return f"{override}#{fragment}" | ||
|
Comment on lines
+316
to
320
|
||
| # If override already has a fragment, override's fragment wins. | ||
| return override | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,234 @@ | ||||||||||||||||||||||||
| #!/usr/bin/env bash | ||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # Smoke test for amplifier-app-cli local changes. | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # Follows the same Docker pattern as amplifier-core's e2e-smoke-test.sh: | ||||||||||||||||||||||||
| # 1. Start a fresh container | ||||||||||||||||||||||||
| # 2. Install amplifier from GitHub (published core from PyPI) | ||||||||||||||||||||||||
| # 3. Override amplifier-app-cli with the local checkout | ||||||||||||||||||||||||
| # 4. Run targeted unit tests for the specific fix | ||||||||||||||||||||||||
| # 5. Run a full session smoke test to confirm nothing is broken | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # Prerequisites: | ||||||||||||||||||||||||
| # - Docker installed and running | ||||||||||||||||||||||||
| # - ANTHROPIC_API_KEY set (or in ~/.amplifier/keys.env) | ||||||||||||||||||||||||
| # | ||||||||||||||||||||||||
| # Usage: | ||||||||||||||||||||||||
| # ./scripts/smoke-test.sh # Test local checkout at repo root | ||||||||||||||||||||||||
| # SMOKE_PROMPT="..." ./scripts/smoke-test.sh # Override session prompt | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||||||||||||||||||||||||
| REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" | ||||||||||||||||||||||||
| CONTAINER_NAME="amplifier-app-cli-smoke-$$" | ||||||||||||||||||||||||
| SMOKE_PROMPT="${SMOKE_PROMPT:-Say exactly: smoke-test-ok}" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| RED='\033[0;31m' | ||||||||||||||||||||||||
| GREEN='\033[0;32m' | ||||||||||||||||||||||||
| YELLOW='\033[1;33m' | ||||||||||||||||||||||||
| CYAN='\033[0;36m' | ||||||||||||||||||||||||
| NC='\033[0m' | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| log() { echo -e "${YELLOW}[smoke-test]${NC} $*"; } | ||||||||||||||||||||||||
| info() { echo -e "${CYAN}[smoke-test]${NC} $*"; } | ||||||||||||||||||||||||
| pass() { echo -e "${GREEN}[PASS]${NC} $*"; } | ||||||||||||||||||||||||
| fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| cleanup() { | ||||||||||||||||||||||||
| log "Cleaning up container $CONTAINER_NAME..." | ||||||||||||||||||||||||
| docker rm -f "$CONTAINER_NAME" 2>/dev/null || true | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
| trap cleanup EXIT | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
| # Step 0: Resolve API keys | ||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| if [[ -z "${ANTHROPIC_API_KEY:-}" ]]; then | ||||||||||||||||||||||||
| KEYS_ENV="$HOME/.amplifier/keys.env" | ||||||||||||||||||||||||
| if [[ -f "$KEYS_ENV" ]]; then | ||||||||||||||||||||||||
| log "Loading API keys from $KEYS_ENV..." | ||||||||||||||||||||||||
| set -a; source "$KEYS_ENV"; set +a | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| [[ -z "${ANTHROPIC_API_KEY:-}" ]] && fail "ANTHROPIC_API_KEY not set. Set it in your environment or ~/.amplifier/keys.env" | ||||||||||||||||||||||||
| command -v docker &>/dev/null || fail "Docker not installed or not in PATH" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
| # Step 1: Start container | ||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| log "Starting isolated Docker container..." | ||||||||||||||||||||||||
| docker run -d --name "$CONTAINER_NAME" \ | ||||||||||||||||||||||||
| -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \ | ||||||||||||||||||||||||
| python:3.12-slim \ | ||||||||||||||||||||||||
| sleep 3600 \ | ||||||||||||||||||||||||
| || fail "Container creation failed" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| info "Container: $CONTAINER_NAME" | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
| # Step 2: Bootstrap (git + uv) | ||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| log "Installing prerequisites (git, uv)..." | ||||||||||||||||||||||||
| docker exec "$CONTAINER_NAME" bash -c " | ||||||||||||||||||||||||
| apt-get update -qq && apt-get install -y -qq git >/dev/null 2>&1 | ||||||||||||||||||||||||
| pip install -q uv | ||||||||||||||||||||||||
| echo 'Bootstrap OK' | ||||||||||||||||||||||||
| " || fail "Bootstrap failed" | ||||||||||||||||||||||||
|
Comment on lines
+76
to
+80
|
||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
| # Step 3: Install amplifier | ||||||||||||||||||||||||
| # --------------------------------------------------------------------------- | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| log "Installing amplifier from GitHub..." | ||||||||||||||||||||||||
| docker exec "$CONTAINER_NAME" bash -c " | ||||||||||||||||||||||||
| export PATH=/root/.local/bin:\$PATH | ||||||||||||||||||||||||
| uv tool install git+https://github.com/microsoft/amplifier@main 2>&1 | tail -3 | ||||||||||||||||||||||||
|
Comment on lines
+88
to
+89
|
||||||||||||||||||||||||
| export PATH=/root/.local/bin:\$PATH | |
| uv tool install git+https://github.com/microsoft/amplifier@main 2>&1 | tail -3 | |
| set -euo pipefail | |
| export PATH=/root/.local/bin:\$PATH | |
| uv tool install git+https://github.com/microsoft/amplifier@main |
Copilot
AI
Apr 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
timeout 120 amplifier run '$SMOKE_PROMPT' is vulnerable to quoting/injection issues if SMOKE_PROMPT contains a single quote (or shell metacharacters). Pass the prompt into the container via an env var and use proper shell escaping/"$SMOKE_PROMPT" inside the container, or avoid bash -c and pass args directly to docker exec.
| SMOKE_OUTPUT=$(docker exec "$CONTAINER_NAME" bash -c " | |
| export PATH=/root/.local/bin:\$PATH | |
| timeout 120 amplifier run '$SMOKE_PROMPT' 2>&1 | |
| ") || SMOKE_EXIT=$? | |
| SMOKE_OUTPUT=$(docker exec \ | |
| -e SMOKE_PROMPT="$SMOKE_PROMPT" \ | |
| "$CONTAINER_NAME" \ | |
| bash -c ' | |
| export PATH=/root/.local/bin:$PATH | |
| timeout 120 amplifier run "$SMOKE_PROMPT" 2>&1 | |
| ') || SMOKE_EXIT=$? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Docstring example/comment is internally inconsistent: it says “git URL override keeps the fragment” but the example override is a local path and the output shows subdirectory being converted into a path component. Please update the wording/example so it matches the actual behavior for local vs git overrides.