From 8d35275b01a6ba4f750f561c229d1b4c1c4e9dbb Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 8 Sep 2026 16:19:03 +0000 Subject: [PATCH 1/4] fix: restore configurable depth and bootstrap missing review baselines directly Amp-Thread-ID: https://ampcode.com/threads/T-01a081b5-9435-7555-a03c-caf44e0d0dbf Co-authored-by: Ivan Milev --- README.md | 12 +++++ action.yml | 7 +++ docs/COMMIT_STRATEGY.md | 9 ++-- scripts/action/analyze.sh | 46 ++++++++--------- scripts/action/state-names.sh | 4 +- tests/run_local.sh | 8 +-- tests/test_action_inputs.py | 7 +++ tests/test_action_state.py | 94 +++++++++++++++++++++++++++++++++-- 8 files changed, 148 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 78d7081..ece03e7 100644 --- a/README.md +++ b/README.md @@ -304,6 +304,7 @@ With the default `github.token`, the repository or organization must allow GitHu | `model` | both | empty | Default model for both analysis and parsing. | | `agent_model` | both | empty | Analysis-only override for `model`. | | `parsing_model` | both | empty | Parsing-only override for `model`. | +| `depth_level` | both | `2` | Positive integer analysis depth cap, including full-analysis fallbacks. Changing it rebuilds incompatible state. | | `github_token` | both | `${{ github.token }}` | Token for comments and sync delivery. | | `sync_strategy` | sync | `push` | `push` or `pull_request`. | | `target_branch` | sync | event branch | Branch receiving the baseline or rolling PR. | @@ -312,6 +313,17 @@ With the default `github.token`, the repository or organization must allow GitHu The `/codeboarding` command, comment heading, Mermaid direction (`LR`), hosted webview URL, rolling sync branch, commit message, and CodeBoarding 0.14.0 version are intentionally fixed rather than exposed as configuration. +Review mode needs no sync workflow or committed `.codeboarding` directory. If no +usable merge-base analysis exists, it runs full analysis there directly, then +seeds an incremental analysis of the PR head and publishes both states. Later +runs prefer compatible prior PR state for incremental updates, while the review +still compares the merge base with the current head. + +Set `depth_level` in the action's `with:` block (for example, `depth_level: 4`). +This configuration is authoritative: stored `metadata.depth_cap` is checked for +compatibility, not inherited, and legacy `metadata.depth_level` is not used as a +fallback. Missing or incompatible baseline depth triggers a rebuild. + ## Outputs | Output | Mode | Description | diff --git a/action.yml b/action.yml index cf4f57b..9f9a679 100644 --- a/action.yml +++ b/action.yml @@ -125,6 +125,10 @@ inputs: description: 'Optional parsing-model override. Takes precedence over model.' required: false default: '' + depth_level: + description: 'Positive integer analysis depth cap, used for both review and sync, including full fallbacks.' + required: false + default: '2' github_token: description: 'Token used for comments and sync delivery.' required: false @@ -382,6 +386,7 @@ runs: IS_FORK: ${{ steps.guard.outputs.is_fork }} LLM_PROVIDER: ${{ steps.llm.outputs.provider }} BACKEND_ID: ${{ steps.llm.outputs.backend_id }} + DEPTH_LEVEL: ${{ inputs.depth_level }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} @@ -430,6 +435,7 @@ runs: CHECKOUT_DIR: ${{ github.workspace }}/.codeboarding-target STAGE_DIR: ${{ runner.temp }}/cb-state/${{ github.action }}/out FORCE_FULL: ${{ inputs.force_full }} + DEPTH_LEVEL: ${{ inputs.depth_level }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} @@ -521,6 +527,7 @@ runs: CFG_HASH: ${{ steps.state.outputs.cfg_hash }} GIT_TOKEN: ${{ inputs.github_token }} GITHUB_SERVER_URL: ${{ github.server_url }} + DEPTH_LEVEL: ${{ inputs.depth_level }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} diff --git a/docs/COMMIT_STRATEGY.md b/docs/COMMIT_STRATEGY.md index d1a9106..eba8c22 100644 --- a/docs/COMMIT_STRATEGY.md +++ b/docs/COMMIT_STRATEGY.md @@ -99,13 +99,16 @@ them: | Source | Engine cost | |---|---| -| the published `codeboarding-base--` artifact | none | -| no artifact — check out the merge base, seed from the baseline committed there, catch up | one incremental | -| no committed baseline either | full analysis | +| the published `codeboarding-base--` artifact with a compatible depth cap | none | +| no usable artifact — check out the merge base, seed from a compatible baseline committed there, catch up | one incremental, full if Core requires it | +| no compatible committed baseline either | full analysis directly, at the configured `depth_level` | A trusted run that computed the base publishes it, so the next pull request forking from that commit gets the first row. +The configuration hash includes `depth_level`. The workflow input controls depth +for both fresh and fallback analyses; stored legacy depth values never override it. + **Head**, first match wins: | Source | Covers | diff --git a/scripts/action/analyze.sh b/scripts/action/analyze.sh index d8e432e..b0b47a2 100755 --- a/scripts/action/analyze.sh +++ b/scripts/action/analyze.sh @@ -1,6 +1,11 @@ #!/usr/bin/env bash # Runs incremental/full Core analysis and outputs the selected analysis paths and mode. set -euo pipefail +DEPTH_LEVEL="${DEPTH_LEVEL:-2}" +if [[ ! "$DEPTH_LEVEL" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::depth_level must be a positive integer." + exit 1 +fi parse_output() { local output="$1" ANALYSIS_MODE="$(awk -F= '$1 == "analysis_mode" {print $2; exit}' <<< "$output")" @@ -27,16 +32,14 @@ full() { exit 1 fi } -# Core resolves depth from depth_cap, falling back to depth_level for baselines -# predating it. Use the same value everywhere: a run that stopped short of its -# cap must not be read as a scope change, and rebuilding at the realized depth -# would ratchet the configured depth down every time a full run happens. +# Metadata is only a compatibility check, never the source of configuration. +# Legacy baselines without a configured cap are rebuilt at the requested depth. depth_cap_from() { local analysis="$1" [ -f "$analysis" ] || return 0 python3 -c 'import json,sys metadata = json.load(open(sys.argv[1])).get("metadata", {}) -print(metadata.get("depth_cap", metadata.get("depth_level", "")))' "$analysis" 2>/dev/null || true +print(metadata.get("depth_cap", ""))' "$analysis" 2>/dev/null || true } seed_state() { @@ -120,16 +123,13 @@ analyze_sync() { local work="$RUNNER_TEMP/codeboarding-sync" state="$RUNNER_TEMP/codeboarding-sync/analysis" rm -rf "$work" seed_state "$CHECKOUT_DIR" "$state" - local depth - depth="$(depth_cap_from "$state/analysis.json")" - depth="${depth:-2}" - if [ "${FORCE_FULL,,}" = true ]; then - full "$CHECKOUT_DIR" "$state" "$depth" + if [ "${FORCE_FULL,,}" = true ] || [ "$(depth_cap_from "$state/analysis.json")" != "$DEPTH_LEVEL" ]; then + full "$CHECKOUT_DIR" "$state" "$DEPTH_LEVEL" else incremental "$CHECKOUT_DIR" "$state" if [ "$REQUIRES_FULL" = true ]; then - full "$CHECKOUT_DIR" "$state" "$depth" + full "$CHECKOUT_DIR" "$state" "$DEPTH_LEVEL" fi fi # Sync already computes the graph every review of this branch compares against, @@ -148,14 +148,12 @@ fetch_commit() { "${GITHUB_SERVER_URL%/}/${repository}.git" "$sha" --depth=1 } -# The artifact name pins the engine, the analysis scope and the models. Depth and -# lineage are read from the bundle itself, so they are checked here. +# The artifact name pins configuration; verify the stored cap and lineage too. warmstart_usable() { - local base_analysis="$1" bundle_cap base_cap + local base_analysis="$1" bundle_cap [ -f "${WARMSTART_DIR:-}/analysis.json" ] || return 1 bundle_cap="$(depth_cap_from "$WARMSTART_DIR/analysis.json")" - base_cap="$(depth_cap_from "$base_analysis")" - if [ -n "$bundle_cap" ] && [ -n "$base_cap" ] && [ "$bundle_cap" != "$base_cap" ]; then + if [ "$bundle_cap" != "$DEPTH_LEVEL" ]; then echo "::notice::Analysis depth changed since the last run; re-seeding from the base analysis." return 1 fi @@ -178,7 +176,7 @@ analyze_review() { # needs no engine run at all. Without one, the merge base is checked out and # analyzed from whatever baseline the repository committed there. local base_source=published - if [ -f "${BASE_DIR:-}/analysis.json" ]; then + if [ "$(depth_cap_from "${BASE_DIR:-}/analysis.json")" = "$DEPTH_LEVEL" ]; then mkdir -p "$base_state" cp -a "$BASE_DIR/." "$base_state/" else @@ -186,20 +184,18 @@ analyze_review() { fetch_commit "$REVIEW_BASE_REPO" "$REVIEW_BASE_SHA" git -C "$CHECKOUT_DIR" worktree add --detach "$base_checkout" "$REVIEW_BASE_SHA" >/dev/null seed_state "$base_checkout" "$base_state" - local base_depth - base_depth="$(depth_cap_from "$base_state/analysis.json")" - incremental "$base_checkout" "$base_state" + REQUIRES_FULL=true + if [ "$(depth_cap_from "$base_state/analysis.json")" = "$DEPTH_LEVEL" ]; then + incremental "$base_checkout" "$base_state" + fi if [ "$REQUIRES_FULL" = true ]; then - full "$base_checkout" "$base_state" "${base_depth:-2}" + full "$base_checkout" "$base_state" "$DEPTH_LEVEL" fi fi unset GIT_TOKEN local base_analysis="$base_state/analysis.json" [ -f "$base_analysis" ] || { echo "::error::Review baseline analysis is missing."; exit 1; } - local depth - depth="$(depth_cap_from "$base_analysis")" - depth="${depth:-2}" # Seed the head from this pull request's own last analysis when there is one, # so the run only covers commits pushed since it. @@ -219,7 +215,7 @@ analyze_review() { incremental "$CHECKOUT_DIR" "$head_state" if [ "$REQUIRES_FULL" = true ]; then - full "$CHECKOUT_DIR" "$head_state" "$depth" + full "$CHECKOUT_DIR" "$head_state" "$DEPTH_LEVEL" fi write_origin "$head_state" "$seed_source" "$chain_depth" "$(analysis_digest "$base_analysis")" diff --git a/scripts/action/state-names.sh b/scripts/action/state-names.sh index e91f3a0..d3c81f0 100755 --- a/scripts/action/state-names.sh +++ b/scripts/action/state-names.sh @@ -35,8 +35,8 @@ ignore_file="$CHECKOUT_DIR/.codeboarding/.codeboardingignore" # does. It carries no key: rotating a secret must not throw away reusable analysis. model_digest="$(printf '%s\n%s\n%s\n%s\n%s\n' \ "${LLM_PROVIDER:-}" "${BACKEND_ID:-}" "${MODEL:-}" "${AGENT_MODEL_INPUT:-}" "${PARSING_MODEL_INPUT:-}" | digest)" -cfg="$(printf '%s\n%s\n%s\n%s\n' \ - "$STATE_SCHEMA" "$engine_version" "$ignore_digest" "$model_digest" | digest)" +cfg="$(printf '%s\n%s\n%s\n%s\n%s\n' \ + "$STATE_SCHEMA" "$engine_version" "$ignore_digest" "$model_digest" "${DEPTH_LEVEL:-2}" | digest)" { echo "engine_version=$engine_version" diff --git a/tests/run_local.sh b/tests/run_local.sh index 601a524..ba110e0 100755 --- a/tests/run_local.sh +++ b/tests/run_local.sh @@ -111,14 +111,10 @@ else BASELINE_DEPTH="" if [ -f "$BASE_DIR/.codeboarding/analysis.json" ]; then - BASELINE_DEPTH="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1])); print(data.get("metadata", {}).get("depth_level", ""))' "$BASE_DIR/.codeboarding/analysis.json" 2>/dev/null || true)" + BASELINE_DEPTH="$(python3 -c 'import json, sys; data = json.load(open(sys.argv[1])); print(data.get("metadata", {}).get("depth_cap", ""))' "$BASE_DIR/.codeboarding/analysis.json" 2>/dev/null || true)" fi - if [ -n "$BASELINE_DEPTH" ] && [[ "$BASELINE_DEPTH" =~ ^[0-9]+$ ]]; then - DEPTH="$BASELINE_DEPTH" - fi - - if [ -f "$BASE_DIR/.codeboarding/analysis.json" ]; then + if [ "$BASELINE_DEPTH" = "$DEPTH" ]; then cp -a "$BASE_DIR/.codeboarding/." "$BASE_STATE/" BASE_OUTPUT="$(run_inc "$BASE_DIR" "$BASE_STATE")" BASE_MODE="$(parse_value analysis_mode "$BASE_OUTPUT")" diff --git a/tests/test_action_inputs.py b/tests/test_action_inputs.py index ec5d246..6b14546 100644 --- a/tests/test_action_inputs.py +++ b/tests/test_action_inputs.py @@ -62,6 +62,13 @@ def test_llm_is_required_and_has_no_default(self) -> None: self.assertIn("required: true", block) self.assertNotIn("default:", block) + def test_depth_is_wired_to_state_identity_and_both_analysis_modes(self) -> None: + self.assertIn("default: '2'", self.inputs["depth_level"]) + for identifier in ("id: state", "id: sync_analyze", "id: review_analyze"): + start = ACTION.index(identifier) + block = ACTION[start : ACTION.index("\n run:", start)] + self.assertIn("DEPTH_LEVEL: ${{ inputs.depth_level }}", block) + def test_the_inferred_credential_inputs_are_gone(self) -> None: """`llm_api_key`/`llm_provider` are what made a fallback expressible at all.""" for stale in ("llm_api_key", "llm_provider"): diff --git a/tests/test_action_state.py b/tests/test_action_state.py index e5060fe..22846e4 100644 --- a/tests/test_action_state.py +++ b/tests/test_action_state.py @@ -28,8 +28,14 @@ "depth": argv[argv.index("--depth-level") + 1] if "--depth-level" in argv else None, }) + "\\n") analysis = os.path.join(output, "analysis.json") +metadata = json.load(open(analysis))["metadata"] if os.path.isfile(analysis) else {} +if argv[0] == "incremental" and os.environ.get("CB_REQUIRE_FULL") == "true": + print(json.dumps({"requiresFullAnalysis": True})) + sys.exit(0) +if argv[0] == "full": + metadata = {"depth_cap": int(argv[argv.index("--depth-level") + 1])} with open(analysis, "w") as handle: - json.dump({"metadata": {"depth_level": 2}, "components": [], "components_relations": []}, handle) + json.dump({"metadata": metadata, "components": [], "components_relations": []}, handle) print(json.dumps({"requiresFullAnalysis": False, "analysis_path": analysis})) ''' @@ -41,7 +47,7 @@ def _digest(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest()[:16] -def _state(directory: Path, depth: int = 2, cap: int | None = None, **origin: object) -> Path: +def _state(directory: Path, depth: int = 2, cap: int | None = 2, **origin: object) -> Path: directory.mkdir(parents=True, exist_ok=True) metadata: dict[str, int] = {"depth_level": depth} if cap is not None: @@ -128,6 +134,7 @@ def test_analysis_scope_and_engine_version_change_the_identity(self) -> None: def test_model_selection_changes_the_identity(self) -> None: baseline = self._run() + self.assertNotEqual(baseline["cfg_hash"], self._run(DEPTH_LEVEL="4")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(MODEL="gpt-5")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(AGENT_MODEL_INPUT="gpt-5")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(PARSING_MODEL_INPUT="gpt-5")["cfg_hash"]) @@ -234,12 +241,93 @@ def test_a_published_base_without_a_stored_head_seeds_from_the_base(self) -> Non def test_depth_change_discards_the_stored_analysis(self) -> None: _state(self.base_dir, depth=2) - _state(self.warmstart_dir, depth=1, chain_depth=3) + _state(self.warmstart_dir, depth=1, cap=1, chain_depth=3) values = self._analyze() self.assertEqual(values["seed_source"], "base") + def _commit_base(self, cap: int | None = None, legacy: bool = False) -> str: + if cap is not None or legacy: + _state(self.checkout / ".codeboarding", depth=1, cap=cap) + (self.checkout / "code.py").write_text("pass\n") + for args in ( + ("init",), + ("add", "."), + ( + "-c", + "user.name=Test", + "-c", + "user.email=test@example.com", + "-c", + "commit.gpgsign=false", + "commit", + "-m", + "test: base", + ), + ): + subprocess.run(["git", "-C", str(self.checkout), *args], check=True, capture_output=True) + return subprocess.check_output(["git", "-C", str(self.checkout), "rev-parse", "HEAD"], text=True).strip() + + def test_missing_baseline_runs_full_then_incremental_at_configured_depth(self) -> None: + sha = self._commit_base() + values = self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + calls = self._engine_calls() + self.assertEqual([c["mode"] for c in calls], ["full", "incremental"]) + self.assertEqual(calls[0]["depth"], "4") + self.assertEqual(calls[1]["checkout"], str(self.checkout)) + self.assertEqual(values["publish_base"], "true") + for kind in ("base", "warmstart"): + analysis = json.loads((self.stage_dir / kind / "analysis.json").read_text()) + self.assertEqual(analysis["metadata"]["depth_cap"], 4) + + def test_compatible_committed_baseline_runs_incrementally(self) -> None: + sha = self._commit_base(cap=4) + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self.assertEqual([c["mode"] for c in self._engine_calls()], ["incremental", "incremental"]) + + def test_legacy_committed_depth_is_not_inherited(self) -> None: + sha = self._commit_base(legacy=True) + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self.assertEqual([c["mode"] for c in self._engine_calls()], ["full", "incremental"]) + self.assertEqual(self._engine_calls()[0]["depth"], "4") + + def test_changed_configuration_rebuilds_the_base(self) -> None: + sha = self._commit_base(cap=2) + _state(self.base_dir, cap=2) + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self.assertEqual([c["mode"] for c in self._engine_calls()], ["full", "incremental"]) + self.assertEqual(self._engine_calls()[0]["depth"], "4") + + def test_head_full_fallback_uses_configured_cap(self) -> None: + _state(self.base_dir, depth=1, cap=4) + self._analyze(DEPTH_LEVEL="4", CB_REQUIRE_FULL="true") + self.assertEqual([c["mode"] for c in self._engine_calls()], ["incremental", "full"]) + self.assertEqual(self._engine_calls()[1]["depth"], "4") + + def test_base_and_head_fallbacks_keep_configured_depth(self) -> None: + sha = self._commit_base(cap=4) + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4", CB_REQUIRE_FULL="true") + calls = self._engine_calls() + self.assertEqual([c["mode"] for c in calls], ["incremental", "full", "incremental", "full"]) + self.assertEqual([c["depth"] for c in calls if c["mode"] == "full"], ["4", "4"]) + + def test_invalid_depth_fails_before_analysis(self) -> None: + result = subprocess.run( + [str(ANALYZE)], + env={"PATH": os.environ["PATH"], "DEPTH_LEVEL": "-1"}, + capture_output=True, + text=True, + ) + self.assertNotEqual(result.returncode, 0) + self.assertIn("depth_level must be a positive integer", result.stdout) + self.assertEqual(self._engine_calls(), []) + + def test_sync_without_baseline_uses_configured_depth_directly(self) -> None: + self._analyze(ANALYSIS_KIND="sync", FORCE_FULL="false", DEPTH_LEVEL="4") + self.assertEqual([c["mode"] for c in self._engine_calls()], ["full"]) + self.assertEqual(self._engine_calls()[0]["depth"], "4") + def test_a_run_that_stopped_short_of_its_cap_keeps_the_chain(self) -> None: # Core resolves incremental depth from depth_cap, so a realized # depth_level below the cap is not a scope change. From 37f0de0facaa3b218308ba466cab8f6501453d91 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 8 Sep 2026 16:55:27 +0000 Subject: [PATCH 2/4] fix: name the configured analysis ceiling depth_cap Amp-Thread-ID: https://ampcode.com/threads/T-01a081b5-9435-7555-a03c-caf44e0d0dbf Co-authored-by: Ivan Milev --- README.md | 11 +++++++++-- action.yml | 8 ++++---- docs/COMMIT_STRATEGY.md | 4 ++-- scripts/action/analyze.sh | 23 ++++++++++++----------- scripts/action/state-names.sh | 2 +- tests/test_action_inputs.py | 5 +++-- tests/test_action_state.py | 20 ++++++++++---------- 7 files changed, 41 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index ece03e7..4d718d6 100644 --- a/README.md +++ b/README.md @@ -304,7 +304,7 @@ With the default `github.token`, the repository or organization must allow GitHu | `model` | both | empty | Default model for both analysis and parsing. | | `agent_model` | both | empty | Analysis-only override for `model`. | | `parsing_model` | both | empty | Parsing-only override for `model`. | -| `depth_level` | both | `2` | Positive integer analysis depth cap, including full-analysis fallbacks. Changing it rebuilds incompatible state. | +| `depth_cap` | both | `2` | Positive integer maximum analysis depth, including full-analysis fallbacks. Changing it rebuilds incompatible state. | | `github_token` | both | `${{ github.token }}` | Token for comments and sync delivery. | | `sync_strategy` | sync | `push` | `push` or `pull_request`. | | `target_branch` | sync | event branch | Branch receiving the baseline or rolling PR. | @@ -319,11 +319,18 @@ seeds an incremental analysis of the PR head and publishes both states. Later runs prefer compatible prior PR state for incremental updates, while the review still compares the merge base with the current head. -Set `depth_level` in the action's `with:` block (for example, `depth_level: 4`). +Set `depth_cap` in the action's `with:` block (for example, `depth_cap: 4`). This configuration is authoritative: stored `metadata.depth_cap` is checked for compatibility, not inherited, and legacy `metadata.depth_level` is not used as a fallback. Missing or incompatible baseline depth triggers a rebuild. +`metadata.depth_cap` records the configured maximum; `metadata.depth_level` +records the depth actually reached, which can be shallower. Comparing the cap +avoids rejecting valid state or reducing future rebuild depth when a run stops +early. The action input matches the metadata name. Only the engine CLI boundary +still uses `--depth-level`, Core's existing flag for the cap. Historical workflows +using the removed `depth_level` action input should switch to `depth_cap`. + ## Outputs | Output | Mode | Description | diff --git a/action.yml b/action.yml index 9f9a679..193d67d 100644 --- a/action.yml +++ b/action.yml @@ -125,7 +125,7 @@ inputs: description: 'Optional parsing-model override. Takes precedence over model.' required: false default: '' - depth_level: + depth_cap: description: 'Positive integer analysis depth cap, used for both review and sync, including full fallbacks.' required: false default: '2' @@ -386,7 +386,7 @@ runs: IS_FORK: ${{ steps.guard.outputs.is_fork }} LLM_PROVIDER: ${{ steps.llm.outputs.provider }} BACKEND_ID: ${{ steps.llm.outputs.backend_id }} - DEPTH_LEVEL: ${{ inputs.depth_level }} + DEPTH_CAP: ${{ inputs.depth_cap }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} @@ -435,7 +435,7 @@ runs: CHECKOUT_DIR: ${{ github.workspace }}/.codeboarding-target STAGE_DIR: ${{ runner.temp }}/cb-state/${{ github.action }}/out FORCE_FULL: ${{ inputs.force_full }} - DEPTH_LEVEL: ${{ inputs.depth_level }} + DEPTH_CAP: ${{ inputs.depth_cap }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} @@ -527,7 +527,7 @@ runs: CFG_HASH: ${{ steps.state.outputs.cfg_hash }} GIT_TOKEN: ${{ inputs.github_token }} GITHUB_SERVER_URL: ${{ github.server_url }} - DEPTH_LEVEL: ${{ inputs.depth_level }} + DEPTH_CAP: ${{ inputs.depth_cap }} MODEL: ${{ inputs.model }} AGENT_MODEL_INPUT: ${{ inputs.agent_model }} PARSING_MODEL_INPUT: ${{ inputs.parsing_model }} diff --git a/docs/COMMIT_STRATEGY.md b/docs/COMMIT_STRATEGY.md index eba8c22..2849dfb 100644 --- a/docs/COMMIT_STRATEGY.md +++ b/docs/COMMIT_STRATEGY.md @@ -101,12 +101,12 @@ them: |---|---| | the published `codeboarding-base--` artifact with a compatible depth cap | none | | no usable artifact — check out the merge base, seed from a compatible baseline committed there, catch up | one incremental, full if Core requires it | -| no compatible committed baseline either | full analysis directly, at the configured `depth_level` | +| no compatible committed baseline either | full analysis directly, at the configured `depth_cap` | A trusted run that computed the base publishes it, so the next pull request forking from that commit gets the first row. -The configuration hash includes `depth_level`. The workflow input controls depth +The configuration hash includes `depth_cap`. The workflow input controls depth for both fresh and fallback analyses; stored legacy depth values never override it. **Head**, first match wins: diff --git a/scripts/action/analyze.sh b/scripts/action/analyze.sh index b0b47a2..aff5eeb 100755 --- a/scripts/action/analyze.sh +++ b/scripts/action/analyze.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash # Runs incremental/full Core analysis and outputs the selected analysis paths and mode. set -euo pipefail -DEPTH_LEVEL="${DEPTH_LEVEL:-2}" -if [[ ! "$DEPTH_LEVEL" =~ ^[1-9][0-9]*$ ]]; then - echo "::error::depth_level must be a positive integer." +DEPTH_CAP="${DEPTH_CAP:-2}" +if [[ ! "$DEPTH_CAP" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::depth_cap must be a positive integer." exit 1 fi parse_output() { @@ -24,6 +24,7 @@ incremental() { } full() { local checkout="$1" output_dir="$2" depth="$3" output + # Core's CLI calls the configured cap --depth-level; metadata stores depth_cap. output="$(python3 "$ACTION_PATH/scripts/analyze_repository.py" full \ --checkout "$checkout" --output-dir "$output_dir" --depth-level "$depth")" parse_output "$output" @@ -124,12 +125,12 @@ analyze_sync() { rm -rf "$work" seed_state "$CHECKOUT_DIR" "$state" - if [ "${FORCE_FULL,,}" = true ] || [ "$(depth_cap_from "$state/analysis.json")" != "$DEPTH_LEVEL" ]; then - full "$CHECKOUT_DIR" "$state" "$DEPTH_LEVEL" + if [ "${FORCE_FULL,,}" = true ] || [ "$(depth_cap_from "$state/analysis.json")" != "$DEPTH_CAP" ]; then + full "$CHECKOUT_DIR" "$state" "$DEPTH_CAP" else incremental "$CHECKOUT_DIR" "$state" if [ "$REQUIRES_FULL" = true ]; then - full "$CHECKOUT_DIR" "$state" "$DEPTH_LEVEL" + full "$CHECKOUT_DIR" "$state" "$DEPTH_CAP" fi fi # Sync already computes the graph every review of this branch compares against, @@ -153,7 +154,7 @@ warmstart_usable() { local base_analysis="$1" bundle_cap [ -f "${WARMSTART_DIR:-}/analysis.json" ] || return 1 bundle_cap="$(depth_cap_from "$WARMSTART_DIR/analysis.json")" - if [ "$bundle_cap" != "$DEPTH_LEVEL" ]; then + if [ "$bundle_cap" != "$DEPTH_CAP" ]; then echo "::notice::Analysis depth changed since the last run; re-seeding from the base analysis." return 1 fi @@ -176,7 +177,7 @@ analyze_review() { # needs no engine run at all. Without one, the merge base is checked out and # analyzed from whatever baseline the repository committed there. local base_source=published - if [ "$(depth_cap_from "${BASE_DIR:-}/analysis.json")" = "$DEPTH_LEVEL" ]; then + if [ "$(depth_cap_from "${BASE_DIR:-}/analysis.json")" = "$DEPTH_CAP" ]; then mkdir -p "$base_state" cp -a "$BASE_DIR/." "$base_state/" else @@ -185,11 +186,11 @@ analyze_review() { git -C "$CHECKOUT_DIR" worktree add --detach "$base_checkout" "$REVIEW_BASE_SHA" >/dev/null seed_state "$base_checkout" "$base_state" REQUIRES_FULL=true - if [ "$(depth_cap_from "$base_state/analysis.json")" = "$DEPTH_LEVEL" ]; then + if [ "$(depth_cap_from "$base_state/analysis.json")" = "$DEPTH_CAP" ]; then incremental "$base_checkout" "$base_state" fi if [ "$REQUIRES_FULL" = true ]; then - full "$base_checkout" "$base_state" "$DEPTH_LEVEL" + full "$base_checkout" "$base_state" "$DEPTH_CAP" fi fi unset GIT_TOKEN @@ -215,7 +216,7 @@ analyze_review() { incremental "$CHECKOUT_DIR" "$head_state" if [ "$REQUIRES_FULL" = true ]; then - full "$CHECKOUT_DIR" "$head_state" "$DEPTH_LEVEL" + full "$CHECKOUT_DIR" "$head_state" "$DEPTH_CAP" fi write_origin "$head_state" "$seed_source" "$chain_depth" "$(analysis_digest "$base_analysis")" diff --git a/scripts/action/state-names.sh b/scripts/action/state-names.sh index d3c81f0..3c7dec9 100755 --- a/scripts/action/state-names.sh +++ b/scripts/action/state-names.sh @@ -36,7 +36,7 @@ ignore_file="$CHECKOUT_DIR/.codeboarding/.codeboardingignore" model_digest="$(printf '%s\n%s\n%s\n%s\n%s\n' \ "${LLM_PROVIDER:-}" "${BACKEND_ID:-}" "${MODEL:-}" "${AGENT_MODEL_INPUT:-}" "${PARSING_MODEL_INPUT:-}" | digest)" cfg="$(printf '%s\n%s\n%s\n%s\n%s\n' \ - "$STATE_SCHEMA" "$engine_version" "$ignore_digest" "$model_digest" "${DEPTH_LEVEL:-2}" | digest)" + "$STATE_SCHEMA" "$engine_version" "$ignore_digest" "$model_digest" "${DEPTH_CAP:-2}" | digest)" { echo "engine_version=$engine_version" diff --git a/tests/test_action_inputs.py b/tests/test_action_inputs.py index 6b14546..eb7f21d 100644 --- a/tests/test_action_inputs.py +++ b/tests/test_action_inputs.py @@ -63,11 +63,12 @@ def test_llm_is_required_and_has_no_default(self) -> None: self.assertNotIn("default:", block) def test_depth_is_wired_to_state_identity_and_both_analysis_modes(self) -> None: - self.assertIn("default: '2'", self.inputs["depth_level"]) + self.assertIn("default: '2'", self.inputs["depth_cap"]) + self.assertNotIn("depth_level", self.inputs) for identifier in ("id: state", "id: sync_analyze", "id: review_analyze"): start = ACTION.index(identifier) block = ACTION[start : ACTION.index("\n run:", start)] - self.assertIn("DEPTH_LEVEL: ${{ inputs.depth_level }}", block) + self.assertIn("DEPTH_CAP: ${{ inputs.depth_cap }}", block) def test_the_inferred_credential_inputs_are_gone(self) -> None: """`llm_api_key`/`llm_provider` are what made a fallback expressible at all.""" diff --git a/tests/test_action_state.py b/tests/test_action_state.py index 22846e4..74e7c11 100644 --- a/tests/test_action_state.py +++ b/tests/test_action_state.py @@ -134,7 +134,7 @@ def test_analysis_scope_and_engine_version_change_the_identity(self) -> None: def test_model_selection_changes_the_identity(self) -> None: baseline = self._run() - self.assertNotEqual(baseline["cfg_hash"], self._run(DEPTH_LEVEL="4")["cfg_hash"]) + self.assertNotEqual(baseline["cfg_hash"], self._run(DEPTH_CAP="4")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(MODEL="gpt-5")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(AGENT_MODEL_INPUT="gpt-5")["cfg_hash"]) self.assertNotEqual(baseline["cfg_hash"], self._run(PARSING_MODEL_INPUT="gpt-5")["cfg_hash"]) @@ -271,7 +271,7 @@ def _commit_base(self, cap: int | None = None, legacy: bool = False) -> str: def test_missing_baseline_runs_full_then_incremental_at_configured_depth(self) -> None: sha = self._commit_base() - values = self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + values = self._analyze(REVIEW_BASE_SHA=sha, DEPTH_CAP="4") calls = self._engine_calls() self.assertEqual([c["mode"] for c in calls], ["full", "incremental"]) self.assertEqual(calls[0]["depth"], "4") @@ -283,31 +283,31 @@ def test_missing_baseline_runs_full_then_incremental_at_configured_depth(self) - def test_compatible_committed_baseline_runs_incrementally(self) -> None: sha = self._commit_base(cap=4) - self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_CAP="4") self.assertEqual([c["mode"] for c in self._engine_calls()], ["incremental", "incremental"]) def test_legacy_committed_depth_is_not_inherited(self) -> None: sha = self._commit_base(legacy=True) - self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_CAP="4") self.assertEqual([c["mode"] for c in self._engine_calls()], ["full", "incremental"]) self.assertEqual(self._engine_calls()[0]["depth"], "4") def test_changed_configuration_rebuilds_the_base(self) -> None: sha = self._commit_base(cap=2) _state(self.base_dir, cap=2) - self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4") + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_CAP="4") self.assertEqual([c["mode"] for c in self._engine_calls()], ["full", "incremental"]) self.assertEqual(self._engine_calls()[0]["depth"], "4") def test_head_full_fallback_uses_configured_cap(self) -> None: _state(self.base_dir, depth=1, cap=4) - self._analyze(DEPTH_LEVEL="4", CB_REQUIRE_FULL="true") + self._analyze(DEPTH_CAP="4", CB_REQUIRE_FULL="true") self.assertEqual([c["mode"] for c in self._engine_calls()], ["incremental", "full"]) self.assertEqual(self._engine_calls()[1]["depth"], "4") def test_base_and_head_fallbacks_keep_configured_depth(self) -> None: sha = self._commit_base(cap=4) - self._analyze(REVIEW_BASE_SHA=sha, DEPTH_LEVEL="4", CB_REQUIRE_FULL="true") + self._analyze(REVIEW_BASE_SHA=sha, DEPTH_CAP="4", CB_REQUIRE_FULL="true") calls = self._engine_calls() self.assertEqual([c["mode"] for c in calls], ["incremental", "full", "incremental", "full"]) self.assertEqual([c["depth"] for c in calls if c["mode"] == "full"], ["4", "4"]) @@ -315,16 +315,16 @@ def test_base_and_head_fallbacks_keep_configured_depth(self) -> None: def test_invalid_depth_fails_before_analysis(self) -> None: result = subprocess.run( [str(ANALYZE)], - env={"PATH": os.environ["PATH"], "DEPTH_LEVEL": "-1"}, + env={"PATH": os.environ["PATH"], "DEPTH_CAP": "-1"}, capture_output=True, text=True, ) self.assertNotEqual(result.returncode, 0) - self.assertIn("depth_level must be a positive integer", result.stdout) + self.assertIn("depth_cap must be a positive integer", result.stdout) self.assertEqual(self._engine_calls(), []) def test_sync_without_baseline_uses_configured_depth_directly(self) -> None: - self._analyze(ANALYSIS_KIND="sync", FORCE_FULL="false", DEPTH_LEVEL="4") + self._analyze(ANALYSIS_KIND="sync", FORCE_FULL="false", DEPTH_CAP="4") self.assertEqual([c["mode"] for c in self._engine_calls()], ["full"]) self.assertEqual(self._engine_calls()[0]["depth"], "4") From 9bde03542d65a249fbda14f35f0b22d182fd6ad7 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 8 Sep 2026 17:59:16 +0000 Subject: [PATCH 3/4] fix: require depth-cap throughout the engine CLI boundary Amp-Thread-ID: https://ampcode.com/threads/T-01a081b5-9435-7555-a03c-caf44e0d0dbf Co-authored-by: Ivan Milev --- README.md | 12 +++++++++--- scripts/action/analyze.sh | 3 +-- scripts/analyze_repository.py | 10 +++++----- tests/run_local.sh | 6 +++--- tests/test_action_state.py | 4 ++-- tests/test_analyze_repository.py | 11 ++++++++++- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4d718d6..b59efbb 100644 --- a/README.md +++ b/README.md @@ -327,9 +327,15 @@ fallback. Missing or incompatible baseline depth triggers a rebuild. `metadata.depth_cap` records the configured maximum; `metadata.depth_level` records the depth actually reached, which can be shallower. Comparing the cap avoids rejecting valid state or reducing future rebuild depth when a run stops -early. The action input matches the metadata name. Only the engine CLI boundary -still uses `--depth-level`, Core's existing flag for the cap. Historical workflows -using the removed `depth_level` action input should switch to `depth_cap`. +early. The action input matches the metadata name and the engine receives only +`--depth-cap`. There are no old-name input aliases. Historical workflows using +the removed `depth_level` action input must switch to `depth_cap`. + +**Release blocker:** this branch requires Core PR #578's new CLI contract. +The current 0.14.0 engine pin does not support `--depth-cap`; do not merge or +release this action until a compatible Core release is published and both the +engine pin and supported-provider table are updated. Earlier eShop evidence +predates this final breaking CLI migration. ## Outputs diff --git a/scripts/action/analyze.sh b/scripts/action/analyze.sh index aff5eeb..5f246a0 100755 --- a/scripts/action/analyze.sh +++ b/scripts/action/analyze.sh @@ -24,9 +24,8 @@ incremental() { } full() { local checkout="$1" output_dir="$2" depth="$3" output - # Core's CLI calls the configured cap --depth-level; metadata stores depth_cap. output="$(python3 "$ACTION_PATH/scripts/analyze_repository.py" full \ - --checkout "$checkout" --output-dir "$output_dir" --depth-level "$depth")" + --checkout "$checkout" --output-dir "$output_dir" --depth-cap "$depth")" parse_output "$output" if [ "$ANALYSIS_MODE" != full ] || [ ! -f "$ANALYSIS_PATH" ]; then echo "::error::Invalid full-analysis result." diff --git a/scripts/analyze_repository.py b/scripts/analyze_repository.py index 6dab352..aba775a 100755 --- a/scripts/analyze_repository.py +++ b/scripts/analyze_repository.py @@ -95,7 +95,7 @@ def main(argv: list[str] | None = None) -> int: parser.add_argument("mode", choices=["incremental", "full"], help="Which CLI command to invoke") parser.add_argument("--checkout", required=True, help="Path to repository checkout") parser.add_argument("--output-dir", required=True, help="Action-owned output directory") - parser.add_argument("--depth-level", help="Depth passed to full analyses") + parser.add_argument("--depth-cap", help="Maximum hierarchy depth allowed for full analyses") args = parser.parse_args(argv) checkout = Path(args.checkout) @@ -112,8 +112,8 @@ def main(argv: list[str] | None = None) -> int: print(f"analysis_path={analysis_path or ''}") return 0 - if not args.depth_level: - raise SystemExit("--depth-level is required for mode=full") + if not args.depth_cap: + raise SystemExit("--depth-cap is required for mode=full") shutil.rmtree(output_dir) output_dir.mkdir(parents=True) command = [ @@ -123,8 +123,8 @@ def main(argv: list[str] | None = None) -> int: str(checkout), "--output-dir", str(output_dir), - "--depth-level", - args.depth_level, + "--depth-cap", + args.depth_cap, "--force", ] _run_command(command, output_dir) diff --git a/tests/run_local.sh b/tests/run_local.sh index ba110e0..8234a19 100755 --- a/tests/run_local.sh +++ b/tests/run_local.sh @@ -7,7 +7,7 @@ set -euo pipefail # 2) REVIEW LOCAL (full local pipeline): # tests/run_local.sh --repo /path/to/repo --base --head # 3) REVIEW LOCAL against committed baseline only (if available): -# tests/run_local.sh --repo /path/to/repo --base --head --depth 2 +# tests/run_local.sh --repo /path/to/repo --base --head --depth-cap 2 # # Output: # diagram.md Mermaid payload posted by the action @@ -29,7 +29,7 @@ while [ $# -gt 0 ]; do --base-json) BASE_JSON="$2"; shift 2;; --head-json) HEAD_JSON="$2"; shift 2;; --out) OUT="$2"; shift 2;; - --depth) DEPTH="$2"; shift 2;; + --depth-cap) DEPTH="$2"; shift 2;; --direction) DIRECTION="$2"; shift 2;; --no-open) OPEN="no"; shift;; -h|--help) @@ -67,7 +67,7 @@ run_full() { python3 "$ACTION_DIR/scripts/analyze_repository.py" full \ --checkout "$checkout" \ --output-dir "$out_dir" \ - --depth-level "$DEPTH" + --depth-cap "$DEPTH" } if [ -n "$BASE_JSON" ] && [ -n "$HEAD_JSON" ]; then diff --git a/tests/test_action_state.py b/tests/test_action_state.py index 74e7c11..7b5a8aa 100644 --- a/tests/test_action_state.py +++ b/tests/test_action_state.py @@ -25,7 +25,7 @@ log.write(json.dumps({ "mode": argv[0], "checkout": argv[argv.index("--local") + 1], - "depth": argv[argv.index("--depth-level") + 1] if "--depth-level" in argv else None, + "depth": argv[argv.index("--depth-cap") + 1] if "--depth-cap" in argv else None, }) + "\\n") analysis = os.path.join(output, "analysis.json") metadata = json.load(open(analysis))["metadata"] if os.path.isfile(analysis) else {} @@ -33,7 +33,7 @@ print(json.dumps({"requiresFullAnalysis": True})) sys.exit(0) if argv[0] == "full": - metadata = {"depth_cap": int(argv[argv.index("--depth-level") + 1])} + metadata = {"depth_cap": int(argv[argv.index("--depth-cap") + 1])} with open(analysis, "w") as handle: json.dump({"metadata": metadata, "components": [], "components_relations": []}, handle) print(json.dumps({"requiresFullAnalysis": False, "analysis_path": analysis})) diff --git a/tests/test_analyze_repository.py b/tests/test_analyze_repository.py index 66fdfc5..d394736 100644 --- a/tests/test_analyze_repository.py +++ b/tests/test_analyze_repository.py @@ -135,6 +135,8 @@ def test_main_full_uses_generated_analysis_file(self) -> None: stale_artifact.write_text("stale", encoding="utf-8") def fake_run(_args, output_dir): + self.assertIn("--depth-cap", _args) + self.assertNotIn("--depth-level", _args) (output_dir / "analysis.json").write_text("ok", encoding="utf-8") return "human-readable CLI output" @@ -147,7 +149,7 @@ def fake_run(_args, output_dir): str(checkout), "--output-dir", str(out_dir), - "--depth-level", + "--depth-cap", "1", ] ) @@ -155,6 +157,13 @@ def fake_run(_args, output_dir): self.assertIn(f"analysis_path={out_dir / 'analysis.json'}", stdout.getvalue()) self.assertFalse(stale_artifact.exists()) + def test_old_depth_input_is_rejected(self) -> None: + with patch("sys.stderr", io.StringIO()), patch.object(ar, "_run_command") as command: + with self.assertRaises(SystemExit) as raised: + ar.main(["full", "--checkout", ".", "--output-dir", ".", "--depth-level", "3"]) + self.assertEqual(raised.exception.code, 2) + command.assert_not_called() + def test_main_rejects_bad_cli_output(self) -> None: with tempfile.TemporaryDirectory() as tmp: root = Path(tmp) From df9286fc3138536b87af5cbab6afa1fef8b06703 Mon Sep 17 00:00:00 2001 From: Amp Date: Tue, 8 Sep 2026 18:16:33 +0000 Subject: [PATCH 4/4] fix: pin analysis engine to Core 0.14.1 Amp-Thread-ID: https://ampcode.com/threads/T-01a081b5-9435-7555-a03c-caf44e0d0dbf Co-authored-by: Ivan Milev --- README.md | 12 +++++------- action.yml | 2 +- scripts/action/supported-providers.json | 2 +- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b59efbb..1d01f82 100644 --- a/README.md +++ b/README.md @@ -311,7 +311,7 @@ With the default `github.token`, the repository or organization must allow GitHu | `force_full` | sync | `false` | Ignore the committed baseline for this run. | | `warmstart_retention_days` | review | `1` | Days to keep the reusable analysis. Only the next run reads it. | -The `/codeboarding` command, comment heading, Mermaid direction (`LR`), hosted webview URL, rolling sync branch, commit message, and CodeBoarding 0.14.0 version are intentionally fixed rather than exposed as configuration. +The `/codeboarding` command, comment heading, Mermaid direction (`LR`), hosted webview URL, rolling sync branch, commit message, and CodeBoarding 0.14.1 version are intentionally fixed rather than exposed as configuration. Review mode needs no sync workflow or committed `.codeboarding` directory. If no usable merge-base analysis exists, it runs full analysis there directly, then @@ -331,11 +331,9 @@ early. The action input matches the metadata name and the engine receives only `--depth-cap`. There are no old-name input aliases. Historical workflows using the removed `depth_level` action input must switch to `depth_cap`. -**Release blocker:** this branch requires Core PR #578's new CLI contract. -The current 0.14.0 engine pin does not support `--depth-cap`; do not merge or -release this action until a compatible Core release is published and both the -engine pin and supported-provider table are updated. Earlier eShop evidence -predates this final breaking CLI migration. +This action pins Core 0.14.1 for the `--depth-cap` CLI contract. Publish that Core +release before releasing the action. Earlier eShop evidence predates this final +breaking CLI migration. ## Outputs @@ -372,7 +370,7 @@ Run the local analysis pipeline: ```bash export OPENROUTER_API_KEY=sk-or-... -python -m pip install codeboarding==0.14.0 +python -m pip install codeboarding==0.14.1 tests/run_local.sh --repo /path/to/repo --base main --head feature ``` diff --git a/action.yml b/action.yml index 193d67d..2d815f7 100644 --- a/action.yml +++ b/action.yml @@ -357,7 +357,7 @@ runs: if: steps.guard.outputs.skip != 'true' shell: bash run: | - python -m pip install --disable-pip-version-check 'codeboarding==0.14.0' + python -m pip install --disable-pip-version-check 'codeboarding==0.14.1' # Fail here, with the reason, rather than mid-analysis with a traceback: # pinning a release does not pin what its dependencies resolve to. Run # the console script, not `python -c`, which would put the analyzed diff --git a/scripts/action/supported-providers.json b/scripts/action/supported-providers.json index abb7c78..dc343ff 100644 --- a/scripts/action/supported-providers.json +++ b/scripts/action/supported-providers.json @@ -18,7 +18,7 @@ "a selection env (AWS_DEFAULT_REGION, OLLAMA_API_KEY) therefore cannot select a provider", "on its own, which is why ollama and litellm need their base URL and not just a key." ], - "engine": "0.14.0", + "engine": "0.14.1", "hosted_provider": "openrouter", "providers": { "openrouter": {