Skip to content

feat(release): add P2 distribution channels - #41

Merged
elkaix merged 6 commits into
mainfrom
feat/p2-distribution-channels
Jun 1, 2026
Merged

feat(release): add P2 distribution channels#41
elkaix merged 6 commits into
mainfrom
feat/p2-distribution-channels

Conversation

@elkaix

@elkaix elkaix commented Jun 1, 2026

Copy link
Copy Markdown
Member

Summary

  • Add Docker/GHCR distribution with PyPI wheel install, multi-arch digest publishing, and promoted-only :latest movement.
  • Add Scoop manifest generator/template/test plus App-token bucket publish workflow.
  • Add Nix apps.default, PYTHINKER_MANAGED=nix wrapper env, CI smoke, and monthly flake.lock update PR workflow.
  • Add manual-only WinGet submission workflow and README version-less Docker/Scoop/Nix install snippets.
  • Ignore Graphify .understand-anything cache output.

Verification

  • uv run pytest tests/test_scoop_manifest.py tests/test_version_lockstep.py -vv
  • uv run ruff check packages/scoop-bucket/generate-manifest.py tests/test_scoop_manifest.py
  • uv run ruff format --check packages/scoop-bucket/generate-manifest.py tests/test_scoop_manifest.py
  • docker run --rm --security-opt label=disable -v /home/ai/Projects/pythinker-code-main:/repo -w /repo docker.io/rhysd/actionlint:latest -color .github/workflows/docker.yml .github/workflows/scoop-bucket.yml .github/workflows/update-flake-lock.yml .github/workflows/winget.yml .github/workflows/ci-pythinker-cli.yml
  • docker build --build-arg PYTHINKER_VERSION=0.27.0 -t pythinker-docker-test:local .
  • docker run --rm pythinker-docker-test:local --version
  • docker run --rm --entrypoint env pythinker-docker-test:local | grep PYTHINKER_MANAGED
  • uv run python packages/scoop-bucket/generate-manifest.py --version 0.27.0 --template packages/scoop-bucket/pythinker-code.json.tmpl --output <tmp>/pythinker-code.json

Notes

  • Local Nix evaluation was not run because nix is not installed locally; CI covers the Nix smoke.
  • Scoop/WinGet live publication still requires operator setup of the target repo/App secrets/PAT before dispatching those workflows.

Summary by CodeRabbit

  • New Features

    • Publishes multi-arch Docker images to GHCR; adds a prebuilt Docker image option.
    • Adds Windows install via Scoop and WinGet.
    • Adds Nix flake app outputs and marks Nix installs as managed with auto-update disabled.
  • Documentation

    • Quick Start updated with Docker, Scoop, WinGet, and Nix install rows.
  • Tests

    • Added tests for Scoop manifest generation.
  • Chores

    • New CI workflows for Docker/GHCR, Scoop, WinGet, and monthly flake-lock updates; CI now validates Nix app behavior.
    • Updated Docker build ignore configuration.

@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds multi-platform distribution: Dockerfile + GHCR workflow, Scoop manifest generator + bucket workflow, WinGet submission workflow, Nix flake app export and CI check, monthly flake.lock updater, README/ignore/changelog updates, and Scoop manifest tests.

Changes

Multi-Platform Distribution

Layer / File(s) Summary
Docker containerization foundation
.dockerignore, Dockerfile
Dockerfile builds a Python 3.14-slim image, installs pythinker-code from PyPI with constraints, sets PYTHINKER_MANAGED=docker, configures non-root runtime, and defaults to pythinker --help; .dockerignore ignores everything except Dockerfile.
Docker multi-arch GHCR publication pipeline
.github/workflows/docker.yml
Publishes multi-arch images: resolves version, polls PyPI for the wheel, builds/pushes amd64 and arm64 digests, creates a versioned multi-arch manifest, and conditionally updates :latest with ancestor gating.
Nix flake app export and environment configuration
flake.nix, .github/workflows/ci-pythinker-cli.yml
flake.nix adds PYTHINKER_MANAGED=nix to the wrapper and exports apps.default; CI adds a step that runs/builds .#default and checks the wrapper contains PYTHINKER_MANAGED.
Scoop manifest generator, template, and tests
packages/scoop-bucket/generate-manifest.py, packages/scoop-bucket/pythinker-code.json.tmpl, tests/test_scoop_manifest.py
Script fetches GitHub Release assets, resolves SHA-256 (asset digest or .sha256), substitutes __VERSION__/__URL__/__SHA256__ into the template, validates JSON, and tests rendering, missing-asset error, and asset naming.
Scoop bucket synchronization workflow
.github/workflows/scoop-bucket.yml
Workflow resolves version from tag/input, retries up to ~30 minutes for Windows onedir zip availability, generates manifest, mints a GitHub App installation token scoped to the bucket, and commits/pushes the manifest to the bucket repo.
WinGet submission workflow
.github/workflows/winget.yml
Manual workflow_dispatch that verifies the release is not a prerelease and runs wingetcreate.exe update to submit the installer URL for TechMatrixLabs.PythinkerCode.
Dependency automation and documentation
.github/workflows/update-flake-lock.yml, README.md, .gitignore, CHANGELOG.md
Monthly/manual update-flake-lock workflow added; README Quick Start gains Docker/Scoop/Nix rows; .gitignore updated to ignore IDE dir; changelog notes broadened distribution channels.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 70.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format with type 'feat', scope 'release', and clear description of adding P2 distribution channels.
Description check ✅ Passed Description includes comprehensive summary of changes, verification steps, and relevant notes. Core requirements met despite checklist items not explicitly marked.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/p2-distribution-channels

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci-pythinker-cli.yml:
- Around line 338-344: Replace the loose presence check for PYTHINKER_MANAGED
with a strict equality assertion: update the CI step that runs apps.default (the
nix run/.#default and build result/bin/pythinker check) to verify that the
wrapper sets PYTHINKER_MANAGED to the string "nix" (for example by matching the
exact exported/assigned value such as PYTHINKER_MANAGED="nix" or an equivalent
exact check) instead of only grepping for the variable name.

In @.github/workflows/docker.yml:
- Around line 54-69: The current loop only checks for HTTP 200 from the pypi
JSON endpoint; update the "Wait for the wheel on PyPI" step to fetch the JSON
body into a variable (using curl with per-call timeouts such as
--connect-timeout and --max-time) and parse it to ensure at least one entry in
the urls array has packagetype == "bdist_wheel" before exiting the loop; replace
the until condition that only checks HTTP code with a check that verifies
presence of a bdist_wheel (use jq or a safe grep/json parse) and handle curl
failures by retrying until the 30-minute deadline, keeping informative log
messages referencing PKG_VERSION and the url variable.
- Around line 14-17: The workflow currently grants packages: write at the
workflow-level which exposes write permissions to all jobs including resolve;
change the workflow-level permissions to only what's needed (e.g., keep
contents: read and set packages: read or remove packages entirely) and then add
packages: write specifically to the publishing jobs by updating the job-level
permissions for the jobs named build-amd64, build-arm64, and merge (move-latest
already has it) so only those jobs have packages: write while resolve retains
read-only permissions.

In @.github/workflows/scoop-bucket.yml:
- Around line 36-44: The version-selection block accepts any non-empty
INPUT_VERSION; change it to validate strict semver and fail fast: replace the
elif [[ -n "${INPUT_VERSION:-}" ]] branch with a test that the INPUT_VERSION
matches the regex ^[0-9]+\.[0-9]+\.[0-9]+$ (e.g. [[ "$INPUT_VERSION" =~
^[0-9]+\.[0-9]+\.[0-9]+$ ]]) and only assign version="$INPUT_VERSION" if it
matches; if it does not match emit an error (echo "::error::Invalid version:
...") and exit 1. This keeps the tag-match branch using GITHUB_REF unchanged and
ensures the version variable is always valid semver.
- Around line 1-25: Add a GitHub Actions concurrency guard to the workflow to
serialize bucket updates and avoid race conditions: inside the update job (job
name "update") add a concurrency block with a stable group name that includes
the bucket/repo and ref or version (for example use group: "scoop-bucket-${{
env.BUCKET_REPO }}-${{ github.ref || github.event.inputs.version }}") and set
cancel-in-progress appropriately (e.g., cancel-in-progress: false to queue new
runs or true to cancel in-flight runs) so only one run may push to
scoop-pythinker:main at a time.
- Around line 26-27: The checkout step "Checkout source repo" uses
actions/checkout@de0fac2e... which leaves persist-credentials true by default;
update that step to explicitly set persist-credentials: false so the checkout
token is not written to local git config (keep the same pinned action version
and step name).

In @.github/workflows/update-flake-lock.yml:
- Line 14: The GitHub Actions job currently declared as "update-lock" lacks a
human-readable display name; add a top-level name: field for the job (the job
keyed as update-lock) in the .github/workflows/update-flake-lock.yml so the
Actions UI shows a descriptive title (e.g., name: "Update flake lock" or
similar) directly under the update-lock job definition.
- Around line 3-7: Add a GitHub Actions concurrency block to the workflow to
prevent duplicate runs/PRs by setting a stable concurrency group name (e.g.,
"update-flake-lock") and enabling cancel-in-progress; modify the top-level
workflow "on:" section (near the existing schedule/cron and workflow_dispatch
entries) to include a concurrency key with a fixed group string and
cancel-in-progress: true so manual triggers during scheduled runs won't spawn
concurrent update jobs.
- Around line 17-18: The checkout step named "Checkout repository" currently
uses actions/checkout@de0fac2e... and leaves the GITHUB_TOKEN in the checked-out
.git/config; update that step to set persist-credentials: false so the token is
not persisted (add the persist-credentials: false key under the uses entry for
the checkout step).
- Around line 9-11: The workflow currently sets workflow-level permissions
("permissions" with "contents: write" and "pull-requests: write"); move these
permissions into each job that requires them to reduce blast radius—remove or
empty the top-level "permissions" block and add a job-level "permissions" map to
only the jobs that need "contents: write" or "pull-requests: write" (reference
the "permissions" key and the "contents" and "pull-requests" entries) so each
job explicitly declares the minimal permissions it requires.

In @.github/workflows/winget.yml:
- Around line 11-20: Add a GitHub Actions concurrency guard to the submit job to
prevent duplicate manual WinGet submissions: inside the job named "submit" add a
concurrency block (e.g. concurrency: group: "winget-${{ github.ref }}-${{
github.event.inputs.version || github.sha }}" cancel-in-progress: false) so runs
for the same ref/version are serialized instead of racing; place the block at
the top level of the submit job in .github/workflows/winget.yml.
- Line 45: The workflow is downloading a moving target via Invoke-WebRequest
-Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe and running
it without integrity checks; change this to download a pinned GitHub release
asset URL for winget-create (use a fixed tag/version in the URL instead of
/latest), also download the release's published SHA256 checksum file (e.g.,
wingetcreate.exe.txt), compute the SHA256 of the downloaded wingetcreate.exe in
the same step, compare it to the published checksum, and fail the job if they do
not match; update the Invoke-WebRequest invocations and add the checksum
verification logic so the pipeline only proceeds when the checksum comparison
succeeds.

In `@Dockerfile`:
- Around line 6-34: The container currently runs as root because there is no
USER instruction; add a non-root runtime user and switch to it before the
ENTRYPOINT/CMD so pythinker doesn't run as root. Create an unprivileged user
(e.g., pythinker or appuser) and group, chown any installed runtime
directories/files if needed, set HOME if required, then add a USER instruction
to switch to that user prior to ENTRYPOINT ["pythinker"] (ensure any files
created during image build are accessible to that user).

In `@packages/scoop-bucket/generate-manifest.py`:
- Around line 35-37: The HTTP fetch helpers _fetch_json and _fetch_text
currently call urllib.request.urlopen without an Authorization header which can
hit GitHub rate limits; update both functions to read an optional GITHUB_TOKEN
from the environment and, when present, add an "Authorization: token
<GITHUB_TOKEN>" header to the urllib.request.Request (preserve the existing
"Accept: application/vnd.github+json" for _fetch_json), then use that Request in
urlopen so authenticated requests are made when a token exists, falling back to
unauthenticated requests if not.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3c4755f4-6c34-49c6-b109-2714d0430408

📥 Commits

Reviewing files that changed from the base of the PR and between c1a90de and 3fb5983.

📒 Files selected for processing (13)
  • .dockerignore
  • .github/workflows/ci-pythinker-cli.yml
  • .github/workflows/docker.yml
  • .github/workflows/scoop-bucket.yml
  • .github/workflows/update-flake-lock.yml
  • .github/workflows/winget.yml
  • .gitignore
  • Dockerfile
  • README.md
  • flake.nix
  • packages/scoop-bucket/generate-manifest.py
  • packages/scoop-bucket/pythinker-code.json.tmpl
  • tests/test_scoop_manifest.py

Comment thread .github/workflows/ci-pythinker-cli.yml Outdated
Comment thread .github/workflows/docker.yml
Comment thread .github/workflows/docker.yml Outdated
Comment thread .github/workflows/scoop-bucket.yml
Comment thread .github/workflows/scoop-bucket.yml
Comment thread .github/workflows/update-flake-lock.yml
Comment thread .github/workflows/winget.yml
Comment thread .github/workflows/winget.yml Outdated
Comment thread Dockerfile
Comment thread packages/scoop-bucket/generate-manifest.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
.github/workflows/ci-pythinker-cli.yml (1)

338-344: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The "nix" (double-quote) match may not align with how the Nix wrapper actually writes the env var.

makeWrapper/wrapProgram typically emit export PYTHINKER_MANAGED='nix' with single quotes, so grep -q 'PYTHINKER_MANAGED.*"nix"' would fail to match and break this step even when flake.nix is correctly configured. The exact format depends on how the wrapper is built in flake.nix, which isn't in this diff.

If the wrapper uses single quotes, a quote-agnostic match is safer:

🔍 Quote-agnostic assertion
-          grep -q 'PYTHINKER_MANAGED.*"nix"' result/bin/pythinker
+          grep -qE "PYTHINKER_MANAGED[=[:space:]].*['\"]?nix['\"]?" result/bin/pythinker

Note: a makeBinaryWrapper (compiled) wrapper may not be grep-friendly at all; in that case, prefer running the wrapper and asserting the exported value at runtime.

Confirm how PYTHINKER_MANAGED is set in the wrapper so the grep pattern actually matches:

#!/bin/bash
# Inspect flake.nix for the wrapper mechanism and PYTHINKER_MANAGED quoting.
fd -t f 'flake.nix' --exec sh -c '
  echo "=== {} ==="
  rg -n -C3 "PYTHINKER_MANAGED|makeWrapper|wrapProgram|makeBinaryWrapper|setEnv|--set" "{}"
'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci-pythinker-cli.yml around lines 338 - 344, The grep
assertion using grep -q 'PYTHINKER_MANAGED.*"nix"' is brittle because wrappers
may use single quotes or produce non-grepable binaries; change the check so it
is quote-agnostic or verify the env at runtime: update the grep invocation that
references "PYTHINKER_MANAGED.*\"nix\"" to a pattern that matches either single
or double quotes (e.g., PYTHINKER_MANAGED.*['\"]nix['\"]) against
result/bin/pythinker, or instead run the wrapper (nix run .#default or
result/bin/pythinker) and assert the exported PYTHINKER_MANAGED value at runtime
by executing the binary and echoing/inspecting $PYTHINKER_MANAGED; ensure you
update the step name that currently runs nix run .#default and the grep line
accordingly.
.github/workflows/winget.yml (1)

25-36: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider verifying the installer asset exists.

The step confirms the release is published and non-prerelease but doesn't check whether PythinkerSetup-${VERSION}.exe exists. If the asset is missing or misnamed, wingetcreate will fail late with a less actionable error.

🔍 Suggested enhancement

Extend the verification to confirm the asset exists:

       run: |
         set -euo pipefail
         is_pre=$(gh release view "v${VERSION}" --repo "${GITHUB_REPOSITORY}" --json isPrerelease -q '.isPrerelease')
         if [ "$is_pre" != "false" ]; then
           echo "::error::Release v${VERSION} is not a promoted (non-prerelease) release; refusing to submit to WinGet." >&2
           exit 1
         fi
+        
+        # Verify the installer asset exists
+        asset_name="PythinkerSetup-${VERSION}.exe"
+        if ! gh release view "v${VERSION}" --repo "${GITHUB_REPOSITORY}" --json assets -q ".assets[].name" | grep -qx "$asset_name"; then
+          echo "::error::Installer asset $asset_name not found in release v${VERSION}." >&2
+          exit 1
+        fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/winget.yml around lines 25 - 36, Add an explicit check
that the release contains the expected installer asset
"PythinkerSetup-${VERSION}.exe" before calling wingetcreate: after using gh
release view to get isPrerelease, call gh release view "v${VERSION}" --json
assets -q '.assets[].name' (or equivalent) and verify one of the names equals
"PythinkerSetup-${VERSION}.exe"; if not, emit a clear ::error:: mentioning the
missing asset and exit 1. Ensure you reference the VERSION variable and keep the
check in the same step that currently uses is_pre so the workflow fails early
with an actionable message when the asset is missing.
packages/scoop-bucket/generate-manifest.py (1)

45-57: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider validating URL scheme to satisfy Ruff S310.

Both _fetch_json and _fetch_text trigger S310 because urlopen accepts file:// or custom schemes. In practice, URLs here come from hardcoded constants or GitHub API responses, so risk is low—but a simple guard would silence the linter and add defense-in-depth.

♻️ Optional scheme check
+def _assert_https(url: str) -> None:
+    if not url.startswith("https://"):
+        raise ValueError(f"URL must use https scheme: {url}")
+
+
 def _fetch_json(url: str) -> dict[str, Any]:
+    _assert_https(url)
     request = urllib.request.Request(url, headers=_github_headers(url))
     with urllib.request.urlopen(request, timeout=30) as resp:
         data = json.load(resp)
@@

 def _fetch_text(url: str) -> str:
+    _assert_https(url)
     request = urllib.request.Request(url, headers=_github_headers(url, accept="text/plain"))
     with urllib.request.urlopen(request, timeout=30) as resp:
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/scoop-bucket/generate-manifest.py` around lines 45 - 57, Add a
URL-scheme whitelist to both _fetch_json and _fetch_text to satisfy Ruff S310:
parse the supplied url with urllib.parse.urlparse and ensure the scheme is
"http" or "https" before calling urllib.request.urlopen; if the scheme is not
allowed, raise a clear exception (e.g., ValueError or RuntimeError) mentioning
the offending URL. Update both functions (_fetch_json and _fetch_text) to
perform this check at the top and then proceed to build the Request and call
urlopen as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/ci-pythinker-cli.yml:
- Around line 338-344: The grep assertion using grep -q
'PYTHINKER_MANAGED.*"nix"' is brittle because wrappers may use single quotes or
produce non-grepable binaries; change the check so it is quote-agnostic or
verify the env at runtime: update the grep invocation that references
"PYTHINKER_MANAGED.*\"nix\"" to a pattern that matches either single or double
quotes (e.g., PYTHINKER_MANAGED.*['\"]nix['\"]) against result/bin/pythinker, or
instead run the wrapper (nix run .#default or result/bin/pythinker) and assert
the exported PYTHINKER_MANAGED value at runtime by executing the binary and
echoing/inspecting $PYTHINKER_MANAGED; ensure you update the step name that
currently runs nix run .#default and the grep line accordingly.

In @.github/workflows/winget.yml:
- Around line 25-36: Add an explicit check that the release contains the
expected installer asset "PythinkerSetup-${VERSION}.exe" before calling
wingetcreate: after using gh release view to get isPrerelease, call gh release
view "v${VERSION}" --json assets -q '.assets[].name' (or equivalent) and verify
one of the names equals "PythinkerSetup-${VERSION}.exe"; if not, emit a clear
::error:: mentioning the missing asset and exit 1. Ensure you reference the
VERSION variable and keep the check in the same step that currently uses is_pre
so the workflow fails early with an actionable message when the asset is
missing.

In `@packages/scoop-bucket/generate-manifest.py`:
- Around line 45-57: Add a URL-scheme whitelist to both _fetch_json and
_fetch_text to satisfy Ruff S310: parse the supplied url with
urllib.parse.urlparse and ensure the scheme is "http" or "https" before calling
urllib.request.urlopen; if the scheme is not allowed, raise a clear exception
(e.g., ValueError or RuntimeError) mentioning the offending URL. Update both
functions (_fetch_json and _fetch_text) to perform this check at the top and
then proceed to build the Request and call urlopen as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d44ce1aa-551b-49fb-b2a2-5dcd21dc7da4

📥 Commits

Reviewing files that changed from the base of the PR and between 637b7ee and 2d1417f.

📒 Files selected for processing (7)
  • .github/workflows/ci-pythinker-cli.yml
  • .github/workflows/docker.yml
  • .github/workflows/scoop-bucket.yml
  • .github/workflows/update-flake-lock.yml
  • .github/workflows/winget.yml
  • Dockerfile
  • packages/scoop-bucket/generate-manifest.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
.github/workflows/ci-pythinker-cli.yml (1)

343-343: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the assertion exact for PYTHINKER_MANAGED=nix (not substring).

Line 343 still uses a substring match; it can pass on non-exact values. Use an assignment-aware pattern.

Suggested fix
-          grep -Eq 'PYTHINKER_MANAGED.*nix' result/bin/pythinker
+          grep -Eq '(^|[[:space:]])(export[[:space:]]+)?PYTHINKER_MANAGED="?nix"?([[:space:]]|$)' result/bin/pythinker
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci-pythinker-cli.yml at line 343, The grep check currently
uses a substring pattern 'PYTHINKER_MANAGED.*nix' which can match unintended
values; update the grep call in the line containing grep -Eq
'PYTHINKER_MANAGED.*nix' result/bin/pythinker to use an assignment-aware pattern
such as grep -Eq '^PYTHINKER_MANAGED=nix$' (or a more permissive
assignment-aware variant like grep -Eq
'(^|[[:space:]])PYTHINKER_MANAGED=nix($|[[:space:]]|;)' ) so it only matches the
exact assignment PYTHINKER_MANAGED=nix.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In @.github/workflows/ci-pythinker-cli.yml:
- Line 343: The grep check currently uses a substring pattern
'PYTHINKER_MANAGED.*nix' which can match unintended values; update the grep call
in the line containing grep -Eq 'PYTHINKER_MANAGED.*nix' result/bin/pythinker to
use an assignment-aware pattern such as grep -Eq '^PYTHINKER_MANAGED=nix$' (or a
more permissive assignment-aware variant like grep -Eq
'(^|[[:space:]])PYTHINKER_MANAGED=nix($|[[:space:]]|;)' ) so it only matches the
exact assignment PYTHINKER_MANAGED=nix.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7fa8240a-0cfb-4e9b-80d7-0eed9d169179

📥 Commits

Reviewing files that changed from the base of the PR and between 2d1417f and 7249629.

📒 Files selected for processing (1)
  • .github/workflows/ci-pythinker-cli.yml

@elkaix
elkaix merged commit 7d26d8b into main Jun 1, 2026
23 checks passed
@elkaix
elkaix deleted the feat/p2-distribution-channels branch July 17, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant