From b1ec14655a563111e7424007abcafeaa4924499f Mon Sep 17 00:00:00 2001 From: mohamed-elkholy95 Date: Sun, 31 May 2026 23:19:12 -0400 Subject: [PATCH] chore(release): prepare 0.28.0 Bundles the GitHub org migration (TechMatrix-labs -> Pythoughts-labs) with the 0.28.0 release prep. Org migration: - Repoint all GitHub URLs, install scripts, CI workflow targets (homebrew tap, scoop bucket, pythinker-home dispatch), and the default /feedback repository to github.com/Pythoughts-labs/pythinker-code. - Add the previous owner to the legacy feedback-repo migration set so existing configs auto-update to the new default (with a covering test). Release 0.28.0: - Bump version 0.27.0 -> 0.28.0 (pyproject.toml, uv.lock). - Promote the Unreleased changelog into a dated 0.28.0 block across CHANGELOG.md and docs, mirror the full bullet set, and record the org move; add the 0.28.0 breaking-changes entry (none). - Refresh the README "What's New" section and bump release-asset filenames / download URLs to 0.28.0. --- .github/CODEOWNERS | 26 ++--- .github/ISSUE_TEMPLATE/1-bug-report.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/pull_request_template.md | 4 +- .../dispatch-pythinker-home-sync.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/docs-pages.yml | 2 +- .github/workflows/homebrew-tap.yml | 8 +- .github/workflows/promote-release.yml | 6 +- .github/workflows/scoop-bucket.yml | 8 +- .github/workflows/winget.yml | 4 +- .gitignore | 2 + CHANGELOG.md | 17 +++- CONTRIBUTING.md | 2 +- README.md | 94 +++++++++---------- SECURITY.md | 2 +- docs/.vitepress/config.ts | 3 +- docs/en/customization/wire-mode.md | 81 ---------------- docs/en/guides/getting-started.md | 4 +- docs/en/index.md | 2 +- docs/en/release-notes/breaking-changes.md | 4 + docs/en/release-notes/changelog.md | 17 +++- docs/history/CHANGELOG-pre-0.8.0.md | 2 +- docs/public/install.ps1 | 2 +- docs/public/install.sh | 2 +- .../2026-05-20-pythinker-review-foundation.md | 6 +- .../2026-05-22-windows-native-installer.md | 14 +-- ...-31-release-orchestration-p0-quick-wins.md | 60 ++++++------ ...-orchestration-p2-distribution-channels.md | 82 ++++++++-------- ...6-05-22-windows-native-installer-design.md | 2 +- ...2026-05-31-release-orchestration-design.md | 20 ++-- examples/feedback-worker/wrangler.jsonc | 2 +- packages/homebrew-tap/README.md | 8 +- packages/homebrew-tap/generate-formula.py | 2 +- packages/linux-installer/README.md | 22 ++--- packages/linux-installer/build.sh | 2 +- packages/pythinker-core/CHANGELOG.md | 2 +- packages/pythinker-core/pyproject.toml | 8 +- .../contrib/chat_provider/openai_legacy.py | 2 +- .../api_snapshot_tests/test_openai_legacy.py | 2 +- packages/pythinker-host/pyproject.toml | 8 +- packages/pythinker-review/pyproject.toml | 4 +- .../src/pythinker_review/output/sarif.py | 2 +- packages/scoop-bucket/generate-manifest.py | 2 +- .../scoop-bucket/pythinker-code.json.tmpl | 4 +- packages/windows-installer/installer.iss | 4 +- pyproject.toml | 12 +-- scripts/install-native.sh | 2 +- scripts/install.ps1 | 2 +- sdks/pythinker-sdk/pyproject.toml | 8 +- src/pythinker_code/__main__.py | 4 +- src/pythinker_code/cli/__init__.py | 4 +- src/pythinker_code/feedback_repo.py | 3 +- src/pythinker_code/native.py | 2 +- .../skills/pythinker-code-help/SKILL.md | 8 +- src/pythinker_code/ui/shell/slash.py | 4 +- src/pythinker_code/ui/shell/update.py | 6 +- tasks/todo.md | 2 +- tests/core/test_config.py | 10 +- tests/core/test_simple_compaction.py | 4 +- tests/test_installation_docs.py | 6 +- tests/test_native.py | 2 +- tests/test_release_update_pipeline.py | 2 +- .../ui_and_conv/test_shell_feedback_slash.py | 12 +-- uv.lock | 2 +- web/public/install.ps1 | 2 +- web/public/install.sh | 2 +- 67 files changed, 303 insertions(+), 354 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5950c679..424c1032 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,23 +8,23 @@ # breaking-change regressions (e.g. pydantic 2.13 alias serialization). # Default fallback: project owner reviews everything not matched below. -* @TechMatrix-labs +* @Pythoughts-labs # Dependency surfaces: explicit owner. -pyproject.toml @TechMatrix-labs -uv.lock @TechMatrix-labs -**/pyproject.toml @TechMatrix-labs -**/uv.lock @TechMatrix-labs -package.json @TechMatrix-labs -package-lock.json @TechMatrix-labs -**/package.json @TechMatrix-labs -**/package-lock.json @TechMatrix-labs +pyproject.toml @Pythoughts-labs +uv.lock @Pythoughts-labs +**/pyproject.toml @Pythoughts-labs +**/uv.lock @Pythoughts-labs +package.json @Pythoughts-labs +package-lock.json @Pythoughts-labs +**/package.json @Pythoughts-labs +**/package-lock.json @Pythoughts-labs # Telemetry & monitoring config — contractual changes need a closer look. -src/pythinker_code/telemetry/ @TechMatrix-labs -docs/en/reference/telemetry.md @TechMatrix-labs +src/pythinker_code/telemetry/ @Pythoughts-labs +docs/en/reference/telemetry.md @Pythoughts-labs # CI workflows — branch protection / required-status-check changes shouldn't # slip in unnoticed. -.github/workflows/ @TechMatrix-labs -.github/CODEOWNERS @TechMatrix-labs +.github/workflows/ @Pythoughts-labs +.github/CODEOWNERS @Pythoughts-labs diff --git a/.github/ISSUE_TEMPLATE/1-bug-report.yml b/.github/ISSUE_TEMPLATE/1-bug-report.yml index 8c68e9f7..82d7d883 100644 --- a/.github/ISSUE_TEMPLATE/1-bug-report.yml +++ b/.github/ISSUE_TEMPLATE/1-bug-report.yml @@ -9,7 +9,7 @@ body: value: | Thank you for submitting a bug report! It helps make Pythinker Code better for everyone. - If you need help or support using Pythinker Code, and are not reporting a bug, please post on [pythinker-code/discussions](https://github.com/TechMatrix-labs/pythinker-code/discussions), where you can ask questions or engage with others on ideas for how to improve Pythinker Code. + If you need help or support using Pythinker Code, and are not reporting a bug, please post on [pythinker-code/discussions](https://github.com/Pythoughts-labs/pythinker-code/discussions), where you can ask questions or engage with others on ideas for how to improve Pythinker Code. Make sure you are running the latest version of Pythinker Code (`uv tool upgrade pythinker-code` to upgrade). The bug you are experiencing may already have been fixed. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d77f47c7..e6451805 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: true contact_links: - name: Questions and General Discussion - url: https://github.com/TechMatrix-labs/pythinker-code/discussions + url: https://github.com/Pythoughts-labs/pythinker-code/discussions about: Have questions? Welcome to open a discussion! diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4cf4f6f3..9beee5e5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -3,7 +3,7 @@ Thank you for your contribution to Pythinker Code! Please make sure you already discussed the feature or bugfix you are proposing in an issue with the maintainers. Please understand that if you have not gotten confirmation from the maintainers, your pull request may be closed or ignored without further review due to limited bandwidth. -See https://github.com/TechMatrix-labs/pythinker-code/blob/main/CONTRIBUTING.md for more. +See https://github.com/Pythoughts-labs/pythinker-code/blob/main/CONTRIBUTING.md for more. --> ## Related Issue @@ -18,7 +18,7 @@ Resolve #(issue_number) ## Checklist -- [ ] I have read the [CONTRIBUTING](https://github.com/TechMatrix-labs/pythinker-code/blob/main/CONTRIBUTING.md) document. +- [ ] I have read the [CONTRIBUTING](https://github.com/Pythoughts-labs/pythinker-code/blob/main/CONTRIBUTING.md) document. - [ ] I have linked the related issue, if any. - [ ] I have added tests that prove my fix is effective or that my feature works. - [ ] I have run `make gen-changelog` to update the changelog. diff --git a/.github/workflows/dispatch-pythinker-home-sync.yml b/.github/workflows/dispatch-pythinker-home-sync.yml index 9632666f..03f43636 100644 --- a/.github/workflows/dispatch-pythinker-home-sync.yml +++ b/.github/workflows/dispatch-pythinker-home-sync.yml @@ -23,7 +23,7 @@ jobs: permissions: contents: read env: - DISPATCH_OWNER: TechMatrix-labs + DISPATCH_OWNER: Pythoughts-labs DISPATCH_REPO: pythinker-home steps: # Mint a short-lived installation token for the org-owned diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2a7bd7ae..6f249ac6 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,7 +15,7 @@ permissions: contents: read env: - IMAGE_NAME: ghcr.io/techmatrix-labs/pythinker-code + IMAGE_NAME: ghcr.io/pythoughts-labs/pythinker-code FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" # One run per tag/ref; never cancel a tag/dispatch run because each one may diff --git a/.github/workflows/docs-pages.yml b/.github/workflows/docs-pages.yml index b122201c..8d953401 100644 --- a/.github/workflows/docs-pages.yml +++ b/.github/workflows/docs-pages.yml @@ -17,7 +17,7 @@ env: jobs: deploy: # Only run on the original repository, not on forks - if: github.repository == 'TechMatrix-labs/pythinker-code' + if: github.repository == 'Pythoughts-labs/pythinker-code' runs-on: ubuntu-latest environment: name: github-pages diff --git a/.github/workflows/homebrew-tap.yml b/.github/workflows/homebrew-tap.yml index 94bc563e..b4ddfb57 100644 --- a/.github/workflows/homebrew-tap.yml +++ b/.github/workflows/homebrew-tap.yml @@ -21,7 +21,7 @@ jobs: permissions: contents: read env: - TAP_OWNER: TechMatrix-labs + TAP_OWNER: Pythoughts-labs TAP_REPO: homebrew-pythinker steps: - name: Checkout source repo @@ -155,14 +155,14 @@ jobs: cat > README.md < README.md <<'EOF' # scoop-pythinker - Scoop bucket for [Pythinker Code](https://github.com/TechMatrix-labs/pythinker-code). + Scoop bucket for [Pythinker Code](https://github.com/Pythoughts-labs/pythinker-code). ```pwsh - scoop bucket add pythinker https://github.com/TechMatrix-labs/scoop-pythinker + scoop bucket add pythinker https://github.com/Pythoughts-labs/scoop-pythinker scoop install pythinker-code ``` This bucket is auto-updated by the - [scoop-bucket.yml](https://github.com/TechMatrix-labs/pythinker-code/blob/main/.github/workflows/scoop-bucket.yml) + [scoop-bucket.yml](https://github.com/Pythoughts-labs/pythinker-code/blob/main/.github/workflows/scoop-bucket.yml) workflow on every semver release tag. Do not hand-edit `bucket/*` — your edits will be overwritten on the next release. EOF diff --git a/.github/workflows/winget.yml b/.github/workflows/winget.yml index 4fce6bf1..e0365637 100644 --- a/.github/workflows/winget.yml +++ b/.github/workflows/winget.yml @@ -45,7 +45,7 @@ jobs: if (-not $env:WINGET_TOKEN) { throw "WINGET_SUBMIT_TOKEN is not configured" } - $installerUrl = "https://github.com/TechMatrix-labs/pythinker-code/releases/download/v$env:VERSION/PythinkerSetup-$env:VERSION.exe" + $installerUrl = "https://github.com/Pythoughts-labs/pythinker-code/releases/download/v$env:VERSION/PythinkerSetup-$env:VERSION.exe" $wingetCreateUrl = "https://github.com/microsoft/winget-create/releases/download/v1.12.8.0/wingetcreate.exe" $wingetCreateSha256 = "8BD738851B524885410112678E3771B341C5C716DE60FBBECB88AB0A363ED85D" Invoke-WebRequest -Uri $wingetCreateUrl -OutFile wingetcreate.exe @@ -55,7 +55,7 @@ jobs: } # PackageIdentifier must match the existing winget-pkgs entry; create it # once manually via `wingetcreate new` before the first automated update. - .\wingetcreate.exe update TechMatrixLabs.PythinkerCode ` + .\wingetcreate.exe update PythoughtsLabs.PythinkerCode ` --version $env:VERSION ` --urls "$installerUrl" ` --submit ` diff --git a/.gitignore b/.gitignore index 4507a64e..f07232cd 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,8 @@ src/pythinker_code/vis/static/ graphify-out/ graphify-out*/ src/pythinker_code/.understand-anything/ +# understand-anything knowledge graph (any location) +.understand-anything/ .graphify_*.json .graphify_*.txt tests_ai/report.json diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e9dfe1..6a4d2188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,14 +15,21 @@ GitHub Releases page; `0.8.0` is the new starting line. ## Unreleased +## 0.28.0 (2026-05-31) + +### What changed in this release + +- **Repository moved to the Pythoughts-labs GitHub org.** All GitHub URLs, install scripts, CI configuration, and the default `/feedback` repository now point to `github.com/Pythoughts-labs/pythinker-code`; existing configs that still reference the previous owner are auto-migrated to the new default. - **Broadened distribution channels for releases.** Releases now include best-effort Docker/GHCR, Scoop, Nix, and manual WinGet distribution plumbing with channel-native update markers where the installer format supports them. - **Release preparation now uses a version single source of truth.** `scripts/release.py` rewrites derived release files from `pyproject.toml`, verifies version lockstep on every PR, enforces the frozen `pythinker-review==0.1.0` pin, and managed-channel installs now show channel-native update guidance instead of trying to self-update. -- CI and release workflows now run on Node.js 24-backed GitHub Actions, pin action revisions to immutable commits, and preflight optional website/tap GitHub App credentials with clear errors or notices instead of opaque token failures. -- Release pipeline: migrate the pythinker-home website-sync dispatch to the org-owned `pythinker-release-bot` GitHub App and fail loud on an empty token; retire the dead pythinker-core API-docs gh-pages publish step; add exponential backoff to the native install scripts and fix the Windows installer's release-pagination cliff. +- **Node.js 24 CI with pinned, credential-checked workflows.** CI and release workflows now run on Node.js 24-backed GitHub Actions, pin action revisions to immutable commits, and preflight optional website/tap GitHub App credentials with clear errors or notices instead of opaque token failures. +- **Release pipeline hardening.** Migrate the pythinker-home website-sync dispatch to the org-owned `pythinker-release-bot` GitHub App and fail loud on an empty token; retire the dead pythinker-core API-docs gh-pages publish step; add exponential backoff to the native install scripts and fix the Windows installer's release-pagination cliff. - **Redesigned startup welcome banner.** The banner now uses a cleaner footer-chip layout: the "What's new / Update available" chip sits on the panel's bottom border, the headline/strapline/help lines align beside the robot logo, and the info grid drops its vertical separator. The robot art and palette are unchanged. - **Terminal-aware rendering for minimal and CI terminals.** The shell UI adapts to the terminal — ASCII glyph fallbacks for `TERM=dumb` and legacy Windows code pages, reduced-motion mode (`PYTHINKER_REDUCED_MOTION`), and `NO_COLOR`/`CLICOLOR` support that strips color cleanly — so output stays readable in CI logs, SSH panes, and bare terminals. - **Windows updates avoid encoded PowerShell.** Native updates now launch the signed Inno installer directly with Restart Manager flags instead of a `powershell.exe -EncodedCommand` helper, reducing antivirus command-line heuristic false positives. Windows bootstrap installs use visible `/SILENT` progress instead of fully suppressed setup, and the installer build signs bundled PE files plus Inno's setup/uninstaller/temp copies when signing credentials are configured. +Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.28.0`, or use the native installer for your OS (see the README install table). + ## 0.27.0 (2026-05-31) ### What changed in this release @@ -88,7 +95,7 @@ Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.25.0`, - **Complete native installer `Fetch` fix.** The 0.23.0 release bundled trafilatura's data files but missed `justext`'s stoplists directory, so the `Fetch` tool still crashed with `FileNotFoundError: ./_MEIxxxx/justext/stoplists` on `.exe`, `.deb`, and `.rpm` installs. All three installer specs now bundle both `trafilatura` and `justext` data files. PyPI / `pip install` was unaffected. - **Atomic "latest" release gating.** The GitHub Release is no longer marked "latest" until every platform asset (4 archives, 1 `.exe`, 4 `.deb`/`.rpm`) is attached. A dispatch workflow polls for completeness before flipping the flag, so `/releases/latest` and the in-app updater no longer serve a partially-built release during the publish window. - **Smarter `/update` command.** `run_update_prompt` now routes through `do_update(check_only=True)` to get a fresh PyPI version before showing the update modal, and verifies that the expected binary asset for your platform exists on the GitHub Release before initiating a native upgrade. -- **Repository transferred to TechMatrix-labs.** All GitHub URLs, install script references, and CI configuration now point to `github.com/TechMatrix-labs/pythinker-code`. +- **Repository transferred to Pythoughts-labs.** All GitHub URLs, install script references, and CI configuration now point to `github.com/Pythoughts-labs/pythinker-code`. Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.24.0`, or use the native installer for your OS (see the README install table). @@ -201,8 +208,8 @@ Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.14.0`, ### What changed in this release -- **Native installers for macOS and Linux.** `brew install TechMatrix-labs/pythinker/pythinker-code` (Homebrew tap) covers both macOS (Intel + Apple Silicon) and Linux brew installs from a single auto-generated formula. Debian/Ubuntu users get `pythinker-code_x.y.z_.deb` and Fedora/RHEL/openSUSE users get `pythinker-code-x.y.z..rpm`, both attached to every GitHub Release for `x86_64` and `aarch64`. Together with the Windows `PythinkerSetup-x.y.z.exe` shipped in 0.12.0, Pythinker now ships native installers for every supported platform — no Python, Node, or `uv` prerequisite. -- **Cross-OS curl-bash native installer.** `curl -fsSL https://raw.githubusercontent.com/TechMatrix-labs/pythinker-code/main/scripts/install-native.sh | bash` detects your OS + arch, downloads the matching PyInstaller-frozen tarball from the latest Release, verifies its SHA-256, and lands the binary at `~/.local/bin/pythinker`. Supports `linux-x86_64`, `linux-aarch64`, and `macos-arm64`. Honors `--version`, `--prefix`, and `NO_COLOR`. +- **Native installers for macOS and Linux.** `brew install Pythoughts-labs/pythinker/pythinker-code` (Homebrew tap) covers both macOS (Intel + Apple Silicon) and Linux brew installs from a single auto-generated formula. Debian/Ubuntu users get `pythinker-code_x.y.z_.deb` and Fedora/RHEL/openSUSE users get `pythinker-code-x.y.z..rpm`, both attached to every GitHub Release for `x86_64` and `aarch64`. Together with the Windows `PythinkerSetup-x.y.z.exe` shipped in 0.12.0, Pythinker now ships native installers for every supported platform — no Python, Node, or `uv` prerequisite. +- **Cross-OS curl-bash native installer.** `curl -fsSL https://raw.githubusercontent.com/Pythoughts-labs/pythinker-code/main/scripts/install-native.sh | bash` detects your OS + arch, downloads the matching PyInstaller-frozen tarball from the latest Release, verifies its SHA-256, and lands the binary at `~/.local/bin/pythinker`. Supports `linux-x86_64`, `linux-aarch64`, and `macos-arm64`. Honors `--version`, `--prefix`, and `NO_COLOR`. - **Homebrew tap auto-published on every release.** A new `.github/workflows/homebrew-tap.yml` waits for the PyPI publish to land, runs an in-tree formula generator (replaces the unmaintained `homebrew-pypi-poet` — see release notes for the why), and pushes `Formula/pythinker-code.rb` to the `homebrew-pythinker` tap repo. 132 transitive deps are enumerated automatically — no hand-curation per release. - **Tag-triggered Linux package pipeline.** A new `.github/workflows/linux-installer.yml` matrix-builds `.deb` and `.rpm` for `x86_64` and `aarch64` (the latter via QEMU on `ubuntu-latest`), then uploads all six artifacts to the GitHub Release via `softprops/action-gh-release@v2`. - **Frozen-binary data-files fix.** The PyInstaller specs for both the Windows and Linux pipelines now call `collect_data_files(pkg, include_py_files=False)` per package, so `pythinker_code/prompts/*.md`, `agents/default/*.yaml`, `tools/*/description.md`, `skills/*/SKILL.md`, and similar package resources are bundled into `_internal/`. Without this fix the frozen binary crashed the first time it tried to load `init.md` or an agent yaml. The Windows installer that shipped in 0.12.0 is affected; users on that build should upgrade to 0.13.0. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 111390a6..fe4ddbda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ Thank you for being interested in contributing to Pythinker CLI! We welcome all kinds of contributions, including bug fixes, features, document improvements, typo fixes, etc. To maintain a high-quality codebase and user experience, we provide the following guidelines for contributions: -1. We only merge pull requests that align with our roadmap. For any pull request that introduces changes larger than 100 lines of code, we highly recommend discussing with us by [raising an issue](https://github.com/TechMatrix-labs/pythinker-code/issues) or in an existing issue before you start working on it. Otherwise your pull request may be closed or ignored without review. +1. We only merge pull requests that align with our roadmap. For any pull request that introduces changes larger than 100 lines of code, we highly recommend discussing with us by [raising an issue](https://github.com/Pythoughts-labs/pythinker-code/issues) or in an existing issue before you start working on it. Otherwise your pull request may be closed or ignored without review. 2. We insist on high code quality. Please ensure your code is as good as, if not better than, the code written by frontier coding agents. Changes may be requested before your pull request can be merged. ## Prek hooks diff --git a/README.md b/README.md index 7aa33a1a..6a82683e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
-# Pythinker logo Pythinker Code +# Pythinker logo Pythinker Code ### *Think first, then code. Your terminal-native review-first AI engineering agent.* @@ -10,9 +10,9 @@
[![PyPI](https://img.shields.io/pypi/v/pythinker-code?style=for-the-badge&logo=pypi&logoColor=white&color=2563eb&label=pythinker-code&cacheSeconds=60)](https://pypi.org/project/pythinker-code/) -[![Python](https://img.shields.io/badge/Python-3.12%2B-3776ab?style=for-the-badge&logo=python&logoColor=white)](https://github.com/TechMatrix-labs/pythinker-code/blob/main/pyproject.toml) -[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-16a34a.svg?style=for-the-badge)](https://github.com/TechMatrix-labs/pythinker-code/blob/main/LICENSE) -[![CI](https://img.shields.io/github/actions/workflow/status/TechMatrix-labs/pythinker-code/ci-pythinker-cli.yml?branch=main&label=CI&style=for-the-badge&logo=githubactions&logoColor=white)](https://github.com/TechMatrix-labs/pythinker-code/actions/workflows/ci-pythinker-cli.yml?query=branch%3Amain) +[![Python](https://img.shields.io/badge/Python-3.12%2B-3776ab?style=for-the-badge&logo=python&logoColor=white)](https://github.com/Pythoughts-labs/pythinker-code/blob/main/pyproject.toml) +[![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-16a34a.svg?style=for-the-badge)](https://github.com/Pythoughts-labs/pythinker-code/blob/main/LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/Pythoughts-labs/pythinker-code/ci-pythinker-cli.yml?branch=main&label=CI&style=for-the-badge&logo=githubactions&logoColor=white)](https://github.com/Pythoughts-labs/pythinker-code/actions/workflows/ci-pythinker-cli.yml?query=branch%3Amain) [![PyPI downloads](https://assets.piptrends.com/get-last-month-downloads-badge/pythinker-code.svg)](https://piptrends.com/package/pythinker-code) [![Code style: Ruff](https://img.shields.io/badge/code%20style-ruff-f59e0b.svg?style=flat-square&logo=ruff&logoColor=white)](https://docs.astral.sh/ruff/) @@ -32,7 +32,7 @@

-Pythinker Code terminal demo +Pythinker Code terminal demo
@@ -50,15 +50,15 @@ It speaks the [**Agent Client Protocol (ACP)**](https://github.com/agentclientpr --- -## 🆕 What's New in 0.27.0 +## 🆕 What's New in 0.28.0 -- **`/feedback` submits structured reports with redacted session context.** A new `/feedback [bug|feature|ux|wrong] [message]` command collects recent session context, strips sensitive file contents before sending, shows a confirmation preview, and falls back to a prefilled GitHub issue when direct submission is unavailable. -- **Fresh releases surface in the startup update prompt immediately.** The pre-start update prompt revalidates a cached "already current" answer with a bounded conditional request instead of waiting for the 24-hour throttle, and release promotion now waits for the native assets, PyPI, and the Homebrew tap before marking a version latest — so clients never resolve a release before its install channel is ready. -- **Background agent recovery preserves terminal task state.** Recovery re-reads task runtime under the store update lock before marking orphaned agent work recoverable, so a stale snapshot can no longer clobber a task that already completed. -- **Shell prompt echoes and background todo rows are clearer.** Transcript echoes now show the resolved submitted text for pasted-content placeholders, and background todo rows align continuation icons with the first row. -- **StrReplaceFile refuses ambiguous single replacements.** A non-`replace_all` edit now errors when `old` matches more than once instead of silently editing the first match — add surrounding context to make it unique, or pass `replace_all=true` when every occurrence should change. +- **Redesigned startup welcome banner.** A cleaner footer-chip layout — the "What's new / Update available" chip now sits on the panel's bottom border, the headline/strapline/help lines align beside the robot logo, and the info grid drops its vertical separator. +- **Terminal-aware rendering for minimal and CI terminals.** The shell UI adapts to your terminal — ASCII glyph fallbacks for `TERM=dumb` and legacy Windows code pages, a reduced-motion mode (`PYTHINKER_REDUCED_MOTION`), and `NO_COLOR`/`CLICOLOR` support — so output stays readable in CI logs, SSH panes, and bare terminals. +- **Windows updates avoid encoded PowerShell.** Native updates launch the signed Inno installer directly with Restart Manager flags instead of a `powershell.exe -EncodedCommand` helper, reducing antivirus false positives, and bootstrap installs show visible `/SILENT` progress. +- **More distribution channels.** Releases now include best-effort Docker/GHCR, Scoop, Nix, and manual WinGet plumbing, with channel-native update guidance where the install format supports it. +- **Repository moved to the Pythoughts-labs GitHub org.** All GitHub URLs, install scripts, CI configuration, and the default `/feedback` repository now point to `github.com/Pythoughts-labs/pythinker-code`; configs that still reference the previous owner are auto-migrated. -Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.27.0`, or use the native installer for your platform from the [Releases page](https://github.com/TechMatrix-labs/pythinker-code/releases/latest). +Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.28.0`, or use the native installer for your platform from the [Releases page](https://github.com/Pythoughts-labs/pythinker-code/releases/latest). --- @@ -136,7 +136,7 @@ Swap providers and models per-session: `--model openai/gpt-5.5`, hosted Pythinke > Built-in shell commands such as `cd` are not yet supported in shell command mode.
-Shell command mode demo +Shell command mode demo
--- @@ -148,13 +148,13 @@ matches your OS — no Python, Node, or `uv` prerequisite. | Platform | Recommended install | Artifact source | |---|---|---| -| **🪟 Windows** | `irm https://pythinker.com/install.ps1 \| iex` | `PythinkerSetup-0.27.0.exe` from [Releases](https://github.com/TechMatrix-labs/pythinker-code/releases/latest) | -| **macOS / Linux** | `curl -fsSL https://pythinker.com/install.sh \| bash` | native tarball from [Releases](https://github.com/TechMatrix-labs/pythinker-code/releases/latest) | -| **macOS — Homebrew** | `brew install TechMatrix-labs/pythinker/pythinker-code` | auto-published Homebrew tap | -| **🐳 Docker** | `docker run --rm -it ghcr.io/techmatrix-labs/pythinker-code` | GHCR multi-arch image | -| **🪟 Windows — Scoop** | `scoop bucket add pythinker https://github.com/TechMatrix-labs/scoop-pythinker && scoop install pythinker-code` | auto-published Scoop bucket | -| **❄️ Nix** | `nix run github:TechMatrix-labs/pythinker-code` | flake `apps.default` | -| **Linux — system package** | Download the `.deb` or `.rpm` for your distro below | [Releases](https://github.com/TechMatrix-labs/pythinker-code/releases/latest) | +| **🪟 Windows** | `irm https://pythinker.com/install.ps1 \| iex` | `PythinkerSetup-0.28.0.exe` from [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) | +| **macOS / Linux** | `curl -fsSL https://pythinker.com/install.sh \| bash` | native tarball from [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) | +| **macOS — Homebrew** | `brew install Pythoughts-labs/pythinker/pythinker-code` | auto-published Homebrew tap | +| **🐳 Docker** | `docker run --rm -it ghcr.io/pythoughts-labs/pythinker-code` | GHCR multi-arch image | +| **🪟 Windows — Scoop** | `scoop bucket add pythinker https://github.com/Pythoughts-labs/scoop-pythinker && scoop install pythinker-code` | auto-published Scoop bucket | +| **❄️ Nix** | `nix run github:Pythoughts-labs/pythinker-code` | flake `apps.default` | +| **Linux — system package** | Download the `.deb` or `.rpm` for your distro below | [Releases](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) | | **🐍 Python fallback** | `pip install pythinker-code` | PyPI | Every artifact ships with a matching `.sha256` file — verify before install on @@ -176,7 +176,7 @@ pythinker # start the interactive TUI ### 🪟 Windows — native installer -`PythinkerSetup-0.27.0.exe` is a signed* Inno Setup wizard. Installs per-user +`PythinkerSetup-0.28.0.exe` is a signed* Inno Setup wizard. Installs per-user into `%LOCALAPPDATA%\Programs\Pythinker`, registers `pythinker` on your user PATH (`HKCU\Environment`), broadcasts `WM_SETTINGCHANGE` so new shells see the change. **No UAC prompt.** @@ -187,13 +187,13 @@ irm https://pythinker.com/install.ps1 | iex # Or manually download the installer + checksum from the Releases page, # verify with Get-FileHash, then run: -.\PythinkerSetup-0.27.0.exe +.\PythinkerSetup-0.28.0.exe # Open a fresh PowerShell pythinker --version ``` -**Per-machine install** (IT-managed boxes): `.\PythinkerSetup-0.27.0.exe /ALLUSERS` +**Per-machine install** (IT-managed boxes): `.\PythinkerSetup-0.28.0.exe /ALLUSERS` installs to `%ProgramFiles%\Pythinker` and writes PATH to HKLM (requires admin). **Upgrade:** `pythinker update` from inside the running app — it downloads @@ -214,7 +214,7 @@ the files and the PATH edit. ```sh # 1. Install -brew install TechMatrix-labs/pythinker/pythinker-code +brew install Pythoughts-labs/pythinker/pythinker-code # 2. Verify pythinker --version @@ -230,9 +230,9 @@ latest version. **Upgrade:** `brew upgrade pythinker-code` (Homebrew packages don't auto-update; run this whenever you want the latest). -**Uninstall:** `brew uninstall pythinker-code && brew untap TechMatrix-labs/pythinker`. +**Uninstall:** `brew uninstall pythinker-code && brew untap Pythoughts-labs/pythinker`. -> The tap repo is [TechMatrix-labs/homebrew-pythinker](https://github.com/TechMatrix-labs/homebrew-pythinker) +> The tap repo is [Pythoughts-labs/homebrew-pythinker](https://github.com/Pythoughts-labs/homebrew-pythinker) > — auto-maintained, do not hand-edit. --- @@ -244,26 +244,26 @@ attached to every GitHub Release. ```sh # Debian / Ubuntu (x86_64) -sudo dpkg -i pythinker-code_0.27.0_amd64.deb +sudo dpkg -i pythinker-code_0.28.0_amd64.deb sudo apt-get install -f # only if dpkg reports missing deps # Debian / Ubuntu (ARM64) -sudo dpkg -i pythinker-code_0.27.0_arm64.deb +sudo dpkg -i pythinker-code_0.28.0_arm64.deb # Fedora / RHEL / openSUSE (x86_64) -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.x86_64.rpm -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.x86_64.rpm.sha256 -sha256sum -c pythinker-code-0.27.0.x86_64.rpm.sha256 +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.x86_64.rpm +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.x86_64.rpm.sha256 +sha256sum -c pythinker-code-0.28.0.x86_64.rpm.sha256 # Fedora / RHEL: -sudo dnf install ./pythinker-code-0.27.0.x86_64.rpm +sudo dnf install ./pythinker-code-0.28.0.x86_64.rpm # openSUSE: -sudo zypper install ./pythinker-code-0.27.0.x86_64.rpm +sudo zypper install ./pythinker-code-0.28.0.x86_64.rpm # Fedora / RHEL (aarch64) -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.aarch64.rpm -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.aarch64.rpm.sha256 -sha256sum -c pythinker-code-0.27.0.aarch64.rpm.sha256 -sudo dnf install ./pythinker-code-0.27.0.aarch64.rpm +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.aarch64.rpm +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.aarch64.rpm.sha256 +sha256sum -c pythinker-code-0.28.0.aarch64.rpm.sha256 +sudo dnf install ./pythinker-code-0.28.0.aarch64.rpm ``` Both packages drop a small `/usr/bin/pythinker` launcher that execs the real @@ -272,8 +272,8 @@ binary under `/usr/lib/pythinker/`, so your `$PATH` stays tidy. **Verify before install:** ```sh -sha256sum -c pythinker-code_0.27.0_amd64.deb.sha256 # Debian/Ubuntu -sha256sum -c pythinker-code-0.27.0.x86_64.rpm.sha256 # Fedora/RHEL +sha256sum -c pythinker-code_0.28.0_amd64.deb.sha256 # Debian/Ubuntu +sha256sum -c pythinker-code-0.28.0.x86_64.rpm.sha256 # Fedora/RHEL ``` **Upgrade:** download the new `.deb`/`.rpm` from Releases and `dpkg -i` / @@ -544,7 +544,7 @@ The ACP server provides: | 🔄 **Hot model swap** | Change models for a running ACP session |
-ACP IDE integration demo +ACP IDE integration demo
--- @@ -619,7 +619,7 @@ Pythinker is a small, extensible runtime — not a monolith. Build on it. ## 🏗️ Architecture
-Pythinker Code architecture diagram +Pythinker Code architecture diagram
--- @@ -699,7 +699,7 @@ are used automatically unless you turn telemetry off. ### 🏁 Prepare the workspace ```sh -git clone https://github.com/TechMatrix-labs/pythinker-code.git +git clone https://github.com/Pythoughts-labs/pythinker-code.git cd pythinker-code make prepare ``` @@ -780,9 +780,9 @@ pythinker-code/ Contributions are warmly welcome — bug reports, PRs, plugins, skills, and docs all help. -- 📖 Start with [`CONTRIBUTING.md`](https://github.com/TechMatrix-labs/pythinker-code/blob/main/CONTRIBUTING.md) -- 🔐 See [`SECURITY.md`](https://github.com/TechMatrix-labs/pythinker-code/blob/main/SECURITY.md) for responsible disclosure -- 📜 Skim [`AGENTS.md`](https://github.com/TechMatrix-labs/pythinker-code/blob/main/AGENTS.md) for the agent design notes +- 📖 Start with [`CONTRIBUTING.md`](https://github.com/Pythoughts-labs/pythinker-code/blob/main/CONTRIBUTING.md) +- 🔐 See [`SECURITY.md`](https://github.com/Pythoughts-labs/pythinker-code/blob/main/SECURITY.md) for responsible disclosure +- 📜 Skim [`AGENTS.md`](https://github.com/Pythoughts-labs/pythinker-code/blob/main/AGENTS.md) for the agent design notes If Pythinker helps you, **a ⭐ on GitHub goes a long way.** @@ -790,7 +790,7 @@ If Pythinker helps you, **a ⭐ on GitHub goes a long way.** ## 📜 License -Distributed under the **Apache-2.0 License**. See [`LICENSE`](https://github.com/TechMatrix-labs/pythinker-code/blob/main/LICENSE) for the full text and [`NOTICE`](https://github.com/TechMatrix-labs/pythinker-code/blob/main/NOTICE) for attributions. +Distributed under the **Apache-2.0 License**. See [`LICENSE`](https://github.com/Pythoughts-labs/pythinker-code/blob/main/LICENSE) for the full text and [`NOTICE`](https://github.com/Pythoughts-labs/pythinker-code/blob/main/NOTICE) for attributions.
@@ -800,7 +800,7 @@ Distributed under the **Apache-2.0 License**. See [`LICENSE`](https://github.com [🌐 pythinker.com](https://pythinker.com)  ·  [📦 PyPI](https://pypi.org/project/pythinker-code/)  ·  -[🐙 GitHub](https://github.com/TechMatrix-labs/pythinker-code)  ·  +[🐙 GitHub](https://github.com/Pythoughts-labs/pythinker-code)  ·  [🧩 ACP](https://github.com/agentclientprotocol/agent-client-protocol)  ·  [🔌 MCP](https://modelcontextprotocol.io/) diff --git a/SECURITY.md b/SECURITY.md index ec193e64..10aabe71 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,4 +6,4 @@ Currently, Pythinker CLI only provides security support for the latest version. ## Reporting a Vulnerability -Please report a vulnerability via the [TechMatrix-labs/pythinker-code - Security](https://github.com/TechMatrix-labs/pythinker-code/security) page, or open an [issue](https://github.com/TechMatrix-labs/pythinker-code/issues) if it can be published publicly. +Please report a vulnerability via the [Pythoughts-labs/pythinker-code - Security](https://github.com/Pythoughts-labs/pythinker-code/security) page, or open an [issue](https://github.com/Pythoughts-labs/pythinker-code/issues) if it can be published publicly. diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 2811a566..1bd23c49 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -40,7 +40,6 @@ export default withMermaid(defineConfig({ { text: 'Interaction and Input', link: '/en/guides/interaction' }, { text: 'Sessions and Context', link: '/en/guides/sessions' }, { text: 'Using in IDEs', link: '/en/guides/ides' }, - { text: 'Integrations with Tools', link: '/en/guides/integrations' }, ], }, ], @@ -105,7 +104,7 @@ export default withMermaid(defineConfig({ outline: [2, 3], search: { provider: 'local' }, socialLinks: [ - { icon: 'github', link: 'https://github.com/TechMatrix-labs/pythinker-code' }, + { icon: 'github', link: 'https://github.com/Pythoughts-labs/pythinker-code' }, ], }, diff --git a/docs/en/customization/wire-mode.md b/docs/en/customization/wire-mode.md index a8892ff9..d890fdea 100644 --- a/docs/en/customization/wire-mode.md +++ b/docs/en/customization/wire-mode.md @@ -1146,84 +1146,3 @@ interface ShellDisplayBlock { command: string } ``` - -## Pythinker Agent (Rust) Wire server - -::: warning Note -Pythinker Agent is currently experimental. APIs and behavior may change in future releases. -::: - -Pythinker Agent (Rust) is the Rust implementation of the Pythinker Code kernel, designed specifically for Wire mode. If you only need the Wire protocol service, Pythinker Agent (Rust) offers a more lightweight alternative. The Rust implementation lives in [`mohamed-elkholy95/pythinker-agent-rs`](https://github.com/mohamed-elkholy95/pythinker-agent-rs). - -### Features - -- **Full Wire protocol compatibility**: Uses the same Wire protocol as Python's `pythinker --wire`, existing clients need no modifications -- **Smaller footprint**: Single statically-linked binary, no Python runtime required -- **Faster startup**: Native compilation provides faster startup times -- **Same configuration**: Uses the same config file (`~/.pythinker/config.toml`) and session directories - -### Limitations - -- **Wire mode only**: No Shell/Print/ACP UI -- **Pythinker provider only**: Does not support OpenAI, Anthropic, or other providers -- **No Pythinker account login**: No `login`/`logout` subcommands or `/login`, `/logout` slash commands; requires manual API key configuration -- **No `--prompt`/`--command`**: Wire server does not accept initial prompts -- **Local execution only**: No SSH Host support -- **Different MCP OAuth storage**: Pythinker Agent stores credentials in `~/.pythinker/credentials/mcp_auth.json`, while Python version uses `~/.fastmcp/oauth-mcp-client-cache/`; they are incompatible - -### Installation - -Download pre-built binaries from [GitHub Releases](https://github.com/mohamed-elkholy95/pythinker-agent-rs/releases): - -```sh -# macOS (Apple Silicon) -curl -L https://github.com/mohamed-elkholy95/pythinker-agent-rs/releases/latest/download/pythinker-agent-aarch64-apple-darwin.tar.gz | tar xz -sudo mv pythinker-agent /usr/local/bin/ - -# Linux (x86_64) -curl -L https://github.com/mohamed-elkholy95/pythinker-agent-rs/releases/latest/download/pythinker-agent-x86_64-unknown-linux-gnu.tar.gz | tar xz -sudo mv pythinker-agent /usr/local/bin/ -``` - -### Usage - -Pythinker Agent runs in Wire mode by default: - -```sh -pythinker-agent -``` - -Common options are the same as the `pythinker` command: - -```sh -# Specify work directory -pythinker-agent --work-dir /path/to/project - -# Continue previous session -pythinker-agent --continue - -# Use specific session -pythinker-agent --session - -# Use specific model -pythinker-agent --model k2 - -# YOLO mode (skip approvals) -pythinker-agent --yolo -``` - -Subcommands: - -```sh -# Show version and environment info -pythinker-agent info - -# Manage MCP servers -pythinker-agent mcp list -pythinker-agent mcp add [args...] -pythinker-agent mcp remove -``` - -### Version synchronization - -Pythinker Agent is released independently from Pythinker Code. See `mohamed-elkholy95/pythinker-agent-rs` release notes for compatibility and sync status. diff --git a/docs/en/guides/getting-started.md b/docs/en/guides/getting-started.md index 8bbeaf25..fe539e34 100644 --- a/docs/en/guides/getting-started.md +++ b/docs/en/guides/getting-started.md @@ -17,7 +17,7 @@ Pythinker Code supports the following usage modes: - **[Agent integration (`pythinker acp`)](../reference/pythinker-acp.md)**: Run as a service and integrate with [IDEs](./ides.md) and other local agent clients via the [Agent Client Protocol] ::: info Tip -If you encounter issues or have suggestions, please provide feedback on [GitHub Issues](https://github.com/TechMatrix-labs/pythinker-code/issues). +If you encounter issues or have suggestions, please provide feedback on [GitHub Issues](https://github.com/Pythoughts-labs/pythinker-code/issues). ::: [Agent Client Protocol]: https://agentclientprotocol.com/ @@ -44,7 +44,7 @@ On Windows, run the PowerShell bootstrap. It downloads the native installer, ver irm https://pythinker.com/install.ps1 | iex ``` -You can also download `PythinkerSetup-0.27.0.exe` manually from the [latest release](https://github.com/TechMatrix-labs/pythinker-code/releases/latest). +You can also download `PythinkerSetup-0.28.0.exe` manually from the [latest release](https://github.com/Pythoughts-labs/pythinker-code/releases/latest). Verify the installation: diff --git a/docs/en/index.md b/docs/en/index.md index 2f941a4f..c3a2273a 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -10,5 +10,5 @@ hero: link: /en/guides/getting-started - theme: alt text: GitHub - link: https://github.com/TechMatrix-labs/pythinker-code + link: https://github.com/Pythoughts-labs/pythinker-code --- diff --git a/docs/en/release-notes/breaking-changes.md b/docs/en/release-notes/breaking-changes.md index bd025f2d..fb9e872e 100644 --- a/docs/en/release-notes/breaking-changes.md +++ b/docs/en/release-notes/breaking-changes.md @@ -4,6 +4,10 @@ This page documents breaking changes in Pythinker Code releases and provides mig ## Unreleased +## 0.28.0 (2026-05-31) + +No breaking changes. This release is compatible with 0.27.0 user configuration, native installs, and session data. The repository's move to the Pythoughts-labs GitHub org is handled transparently — the default `/feedback` repository auto-migrates and download/update URLs resolve to the new org. + ## 0.27.0 (2026-05-31) No breaking changes. This release is compatible with 0.26.0 user configuration, native installs, and session data. diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index cef00ff4..45745662 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -17,10 +17,21 @@ GitHub Releases page; `0.8.0` is the new starting line. ## Unreleased +## 0.28.0 (2026-05-31) + +### What changed in this release + +- **Repository moved to the Pythoughts-labs GitHub org.** All GitHub URLs, install scripts, CI configuration, and the default `/feedback` repository now point to `github.com/Pythoughts-labs/pythinker-code`; existing configs that still reference the previous owner are auto-migrated to the new default. +- **Broadened distribution channels for releases.** Releases now include best-effort Docker/GHCR, Scoop, Nix, and manual WinGet distribution plumbing with channel-native update markers where the installer format supports them. +- **Release preparation now uses a version single source of truth.** `scripts/release.py` rewrites derived release files from `pyproject.toml`, verifies version lockstep on every PR, enforces the frozen `pythinker-review==0.1.0` pin, and managed-channel installs now show channel-native update guidance instead of trying to self-update. +- **Node.js 24 CI with pinned, credential-checked workflows.** CI and release workflows now run on Node.js 24-backed GitHub Actions, pin action revisions to immutable commits, and preflight optional website/tap GitHub App credentials with clear errors or notices instead of opaque token failures. +- **Release pipeline hardening.** Migrate the pythinker-home website-sync dispatch to the org-owned `pythinker-release-bot` GitHub App and fail loud on an empty token; retire the dead pythinker-core API-docs gh-pages publish step; add exponential backoff to the native install scripts and fix the Windows installer's release-pagination cliff. - **Redesigned startup welcome banner.** The banner now uses a cleaner footer-chip layout: the "What's new / Update available" chip sits on the panel's bottom border, the headline/strapline/help lines align beside the robot logo, and the info grid drops its vertical separator. The robot art and palette are unchanged. - **Terminal-aware rendering for minimal and CI terminals.** The shell UI adapts to the terminal — ASCII glyph fallbacks for `TERM=dumb` and legacy Windows code pages, reduced-motion mode (`PYTHINKER_REDUCED_MOTION`), and `NO_COLOR`/`CLICOLOR` support that strips color cleanly — so output stays readable in CI logs, SSH panes, and bare terminals. - **Windows updates avoid encoded PowerShell.** Native updates now launch the signed Inno installer directly with Restart Manager flags instead of a `powershell.exe -EncodedCommand` helper, reducing antivirus command-line heuristic false positives. Windows bootstrap installs use visible `/SILENT` progress instead of fully suppressed setup, and the installer build signs bundled PE files plus Inno's setup/uninstaller/temp copies when signing credentials are configured. +Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.28.0`, or use the native installer for your OS (see the README install table). + ## 0.27.0 (2026-05-31) ### What changed in this release @@ -86,7 +97,7 @@ Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.25.0`, - **Complete native installer `Fetch` fix.** The 0.23.0 release bundled trafilatura's data files but missed `justext`'s stoplists directory, so the `Fetch` tool still crashed with `FileNotFoundError: ./_MEIxxxx/justext/stoplists` on `.exe`, `.deb`, and `.rpm` installs. All three installer specs now bundle both `trafilatura` and `justext` data files. PyPI / `pip install` was unaffected. - **Atomic "latest" release gating.** The GitHub Release is no longer marked "latest" until every platform asset (4 archives, 1 `.exe`, 4 `.deb`/`.rpm`) is attached. A dispatch workflow polls for completeness before flipping the flag, so `/releases/latest` and the in-app updater no longer serve a partially-built release during the publish window. - **Smarter `/update` command.** `run_update_prompt` now routes through `do_update(check_only=True)` to get a fresh PyPI version before showing the update modal, and verifies that the expected binary asset for your platform exists on the GitHub Release before initiating a native upgrade. -- **Repository transferred to TechMatrix-labs.** All GitHub URLs, install script references, and CI configuration now point to `github.com/TechMatrix-labs/pythinker-code`. +- **Repository transferred to Pythoughts-labs.** All GitHub URLs, install script references, and CI configuration now point to `github.com/Pythoughts-labs/pythinker-code`. Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.24.0`, or use the native installer for your OS (see the README install table). @@ -199,8 +210,8 @@ Upgrade with `pythinker update`, `pip install --upgrade pythinker-code==0.14.0`, ### What changed in this release -- **Native installers for macOS and Linux.** `brew install TechMatrix-labs/pythinker/pythinker-code` (Homebrew tap) covers both macOS (Intel + Apple Silicon) and Linux brew installs from a single auto-generated formula. Debian/Ubuntu users get `pythinker-code_x.y.z_.deb` and Fedora/RHEL/openSUSE users get `pythinker-code-x.y.z..rpm`, both attached to every GitHub Release for `x86_64` and `aarch64`. Together with the Windows `PythinkerSetup-x.y.z.exe` shipped in 0.12.0, Pythinker now ships native installers for every supported platform — no Python, Node, or `uv` prerequisite. -- **Cross-OS curl-bash native installer.** `curl -fsSL https://raw.githubusercontent.com/TechMatrix-labs/pythinker-code/main/scripts/install-native.sh | bash` detects your OS + arch, downloads the matching PyInstaller-frozen tarball from the latest Release, verifies its SHA-256, and lands the binary at `~/.local/bin/pythinker`. Supports `linux-x86_64`, `linux-aarch64`, and `macos-arm64`. Honors `--version`, `--prefix`, and `NO_COLOR`. +- **Native installers for macOS and Linux.** `brew install Pythoughts-labs/pythinker/pythinker-code` (Homebrew tap) covers both macOS (Intel + Apple Silicon) and Linux brew installs from a single auto-generated formula. Debian/Ubuntu users get `pythinker-code_x.y.z_.deb` and Fedora/RHEL/openSUSE users get `pythinker-code-x.y.z..rpm`, both attached to every GitHub Release for `x86_64` and `aarch64`. Together with the Windows `PythinkerSetup-x.y.z.exe` shipped in 0.12.0, Pythinker now ships native installers for every supported platform — no Python, Node, or `uv` prerequisite. +- **Cross-OS curl-bash native installer.** `curl -fsSL https://raw.githubusercontent.com/Pythoughts-labs/pythinker-code/main/scripts/install-native.sh | bash` detects your OS + arch, downloads the matching PyInstaller-frozen tarball from the latest Release, verifies its SHA-256, and lands the binary at `~/.local/bin/pythinker`. Supports `linux-x86_64`, `linux-aarch64`, and `macos-arm64`. Honors `--version`, `--prefix`, and `NO_COLOR`. - **Homebrew tap auto-published on every release.** A new `.github/workflows/homebrew-tap.yml` waits for the PyPI publish to land, runs an in-tree formula generator (replaces the unmaintained `homebrew-pypi-poet` — see release notes for the why), and pushes `Formula/pythinker-code.rb` to the `homebrew-pythinker` tap repo. 132 transitive deps are enumerated automatically — no hand-curation per release. - **Tag-triggered Linux package pipeline.** A new `.github/workflows/linux-installer.yml` matrix-builds `.deb` and `.rpm` for `x86_64` and `aarch64` (the latter via QEMU on `ubuntu-latest`), then uploads all six artifacts to the GitHub Release via `softprops/action-gh-release@v2`. - **Frozen-binary data-files fix.** The PyInstaller specs for both the Windows and Linux pipelines now call `collect_data_files(pkg, include_py_files=False)` per package, so `pythinker_code/prompts/*.md`, `agents/default/*.yaml`, `tools/*/description.md`, `skills/*/SKILL.md`, and similar package resources are bundled into `_internal/`. Without this fix the frozen binary crashed the first time it tried to load `init.md` or an agent yaml. The Windows installer that shipped in 0.12.0 is affected; users on that build should upgrade to 0.13.0. diff --git a/docs/history/CHANGELOG-pre-0.8.0.md b/docs/history/CHANGELOG-pre-0.8.0.md index 955c8f9f..a5888387 100644 --- a/docs/history/CHANGELOG-pre-0.8.0.md +++ b/docs/history/CHANGELOG-pre-0.8.0.md @@ -22,7 +22,7 @@ Packaging fix: pin `pythinker-core[contrib]==1.1.0` so the Kimi K2.x / DeepSeek ### Why 2.6.0 lands the same day as 2.5.0 -The runtime fix for the strict-interleaved `thinking is enabled but reasoning_content is missing in assistant tool call message at index N` rejection landed in the `pythinker-core` source tree on 2026-05-11 (released in `pythinker-code` 2.4.0 source), but **the published `pythinker-core==1.0.0` on PyPI predates that change** (uploaded 2026-05-07). `pythinker-code` 2.4.0 and 2.5.0 both pinned `pythinker-core[contrib]==1.0.0`, so PyPI users on Kimi K2.5 / K2.6 / DeepSeek through OpenCode Go (and elsewhere) kept hitting the bug even on the latest CLI. Reported in [#37](https://github.com/TechMatrix-labs/pythinker-code/issues/37). +The runtime fix for the strict-interleaved `thinking is enabled but reasoning_content is missing in assistant tool call message at index N` rejection landed in the `pythinker-core` source tree on 2026-05-11 (released in `pythinker-code` 2.4.0 source), but **the published `pythinker-core==1.0.0` on PyPI predates that change** (uploaded 2026-05-07). `pythinker-code` 2.4.0 and 2.5.0 both pinned `pythinker-core[contrib]==1.0.0`, so PyPI users on Kimi K2.5 / K2.6 / DeepSeek through OpenCode Go (and elsewhere) kept hitting the bug even on the latest CLI. Reported in [#37](https://github.com/Pythoughts-labs/pythinker-code/issues/37). ### The fix diff --git a/docs/public/install.ps1 b/docs/public/install.ps1 index 2f5be920..146ded20 100644 --- a/docs/public/install.ps1 +++ b/docs/public/install.ps1 @@ -14,7 +14,7 @@ $ErrorActionPreference = "Stop" try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {} try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -$Repo = "TechMatrix-labs/pythinker-code" +$Repo = "Pythoughts-labs/pythinker-code" $Version = $env:PYTHINKER_VERSION $NoColor = $env:NO_COLOR diff --git a/docs/public/install.sh b/docs/public/install.sh index b918f6ba..88da02b5 100755 --- a/docs/public/install.sh +++ b/docs/public/install.sh @@ -38,7 +38,7 @@ while [[ $# -gt 0 ]]; do esac done -REPO="TechMatrix-labs/pythinker-code" +REPO="Pythoughts-labs/pythinker-code" if [ -t 1 ] && [ -z "$NO_COLOR" ] && [ "${TERM:-}" != "dumb" ]; then NAVY=$'\033[38;5;24m'; FACE=$'\033[38;5;255m' diff --git a/docs/superpowers/plans/2026-05-20-pythinker-review-foundation.md b/docs/superpowers/plans/2026-05-20-pythinker-review-foundation.md index c429b071..bfe17db2 100644 --- a/docs/superpowers/plans/2026-05-20-pythinker-review-foundation.md +++ b/docs/superpowers/plans/2026-05-20-pythinker-review-foundation.md @@ -300,8 +300,8 @@ pythinker-secscan = "pythinker_review.cli.secscan:app" pythinker-debug = "pythinker_review.cli.debug:app" [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" [dependency-groups] dev = [ @@ -3646,7 +3646,7 @@ def render_sarif(meta: RunMeta, findings: list[Finding]) -> str: "tool": { "driver": { "name": "pythinker-review", - "informationUri": "https://github.com/TechMatrix-labs/pythinker-code", + "informationUri": "https://github.com/Pythoughts-labs/pythinker-code", "rules": list(rules_seen.values()), } }, diff --git a/docs/superpowers/plans/2026-05-22-windows-native-installer.md b/docs/superpowers/plans/2026-05-22-windows-native-installer.md index 76cfcd06..f52d5e1d 100644 --- a/docs/superpowers/plans/2026-05-22-windows-native-installer.md +++ b/docs/superpowers/plans/2026-05-22-windows-native-installer.md @@ -279,8 +279,8 @@ AppName=Pythinker Code AppVersion={#AppVersion} AppPublisher=Pythinker AppPublisherURL=https://pythinker.com -AppSupportURL=https://github.com/TechMatrix-labs/pythinker-code/issues -AppUpdatesURL=https://github.com/TechMatrix-labs/pythinker-code/releases +AppSupportURL=https://github.com/Pythoughts-labs/pythinker-code/issues +AppUpdatesURL=https://github.com/Pythoughts-labs/pythinker-code/releases DefaultDirName={localappdata}\Programs\Pythinker DefaultGroupName=Pythinker DisableProgramGroupPage=yes @@ -756,7 +756,7 @@ def test_is_native_build_true_when_sentinel_present(tmp_path): def test_native_installer_release_url_latest(): url = native.native_installer_release_url(channel="latest") assert url == ( - "https://api.github.com/repos/TechMatrix-labs/" + "https://api.github.com/repos/Pythoughts-labs/" "pythinker-code/releases/latest" ) @@ -795,7 +795,7 @@ from __future__ import annotations import sys from pathlib import Path -GITHUB_REPO = "TechMatrix-labs/pythinker-code" +GITHUB_REPO = "Pythoughts-labs/pythinker-code" SENTINEL_FILENAME = ".pythinker-native" @@ -1043,7 +1043,7 @@ if upgrade_command == [NATIVE_INSTALLER_MARKER]: if native_result is UpdateResult.UPDATE_AVAILABLE: _print("[yellow]Auto-update disabled. " "Download the new installer manually from " - "https://github.com/TechMatrix-labs/pythinker-code/releases/latest[/yellow]") + "https://github.com/Pythoughts-labs/pythinker-code/releases/latest[/yellow]") return UpdateResult.UPDATE_AVAILABLE if native_result is UpdateResult.FAILED: _print("[red]Native update failed. " @@ -1225,7 +1225,7 @@ bundles Pythinker as a self-contained executable; **you do not need Python, Node or uv installed**. 1. Download the latest installer from the - [Releases page](https://github.com/TechMatrix-labs/pythinker-code/releases/latest) + [Releases page](https://github.com/Pythoughts-labs/pythinker-code/releases/latest) (`PythinkerSetup-x.y.z.exe`). 2. Run it. The wizard installs to `%LOCALAPPDATA%\Programs\Pythinker` and adds `pythinker` to your user PATH — no admin / UAC prompt. @@ -1238,7 +1238,7 @@ Set the env var `DISABLE_AUTOUPDATER=1` to opt out of automatic update prompts. > If you prefer a one-liner from PowerShell: > > ```powershell -> irm https://raw.githubusercontent.com/TechMatrix-labs/pythinker-code/main/scripts/install-native.ps1 | iex +> irm https://raw.githubusercontent.com/Pythoughts-labs/pythinker-code/main/scripts/install-native.ps1 | iex > ``` > > *(That helper script ships in a follow-up; for now download the `.exe` diff --git a/docs/superpowers/plans/2026-05-31-release-orchestration-p0-quick-wins.md b/docs/superpowers/plans/2026-05-31-release-orchestration-p0-quick-wins.md index 916d7cbd..4465e144 100644 --- a/docs/superpowers/plans/2026-05-31-release-orchestration-p0-quick-wins.md +++ b/docs/superpowers/plans/2026-05-31-release-orchestration-p0-quick-wins.md @@ -14,21 +14,21 @@ These touch admin/secrets/outward-facing services. They are **operator actions**, not code steps. Do them in this order; PR-code-1, PR-code-2 dispatch verification, and the PAT deletions depend on them. -- [ ] **OP-1 — Create the org-owned GitHub App `pythinker-release-bot`.** In the GitHub UI: `https://github.com/organizations/TechMatrix-labs/settings/apps/new`. Name `pythinker-release-bot`. Homepage URL `https://github.com/TechMatrix-labs/pythinker-code`. Uncheck "Webhook → Active". Repository permissions: **Contents: Read and write**, **Metadata: Read-only** (Metadata auto-selects). "Where can this GitHub App be installed?" → **Only on this account**. Create. On the App's page, **Generate a private key** (downloads a `.pem`) and note the numeric **App ID**. +- [ ] **OP-1 — Create the org-owned GitHub App `pythinker-release-bot`.** In the GitHub UI: `https://github.com/organizations/Pythoughts-labs/settings/apps/new`. Name `pythinker-release-bot`. Homepage URL `https://github.com/Pythoughts-labs/pythinker-code`. Uncheck "Webhook → Active". Repository permissions: **Contents: Read and write**, **Metadata: Read-only** (Metadata auto-selects). "Where can this GitHub App be installed?" → **Only on this account**. Create. On the App's page, **Generate a private key** (downloads a `.pem`) and note the numeric **App ID**. - *Why an App and not the PAT:* `homebrew-pythinker` is public, `pythinker-home` is private; a dedicated org App contains a leak to one trust domain, survives member/org changes, and mints ~1h tokens per run (§4). -- [ ] **OP-2 — Install the App on `pythinker-home` ONLY.** App page → **Install App** → TechMatrix-labs → **Only select repositories** → `pythinker-home` → Install. Verify it is NOT installed on any other repo. +- [ ] **OP-2 — Install the App on `pythinker-home` ONLY.** App page → **Install App** → Pythoughts-labs → **Only select repositories** → `pythinker-home` → Install. Verify it is NOT installed on any other repo. - [ ] **OP-3 — Set the org secrets** (run from a shell where `gh auth status` shows an org-admin token): ```bash - gh secret set PYTHINKER_RELEASE_BOT_APP_ID --org TechMatrix-labs --visibility selected --repos pythinker-code --body "" - gh secret set PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY --org TechMatrix-labs --visibility selected --repos pythinker-code < /path/to/pythinker-release-bot.private-key.pem + gh secret set PYTHINKER_RELEASE_BOT_APP_ID --org Pythoughts-labs --visibility selected --repos pythinker-code --body "" + gh secret set PYTHINKER_RELEASE_BOT_APP_PRIVATE_KEY --org Pythoughts-labs --visibility selected --repos pythinker-code < /path/to/pythinker-release-bot.private-key.pem ``` Expected: `✓ Set Organization secret PYTHINKER_RELEASE_BOT_APP_ID` (and `_PRIVATE_KEY`). Then `rm /path/to/pythinker-release-bot.private-key.pem` (the key lives only in the secret now). - [ ] **OP-4 — Confirm the live site host runs Dokploy build-from-source, not the Docker-Compose/Watchtower stack.** Required before Task 14 (deploy retirement). Check the Dokploy dashboard / server: the site is built from source via nixpacks (`bun run server.ts`), and there is no running `watchtower`/`traefik` compose stack for it. If you cannot confirm, **skip Task 14** and log it under "Out of scope / deferred" — it is reversible (`git rm`) and not on the release path. - [ ] **OP-5 — (DEFERRED, post-verification) Delete the retired PATs.** Do these only after the gated green cycle in "Phase verification": - - `PYTHINKER_HOME_REPO_DISPATCH_TOKEN` — delete after **both** dispatch files are migrated (PR-code-1 + PR-code-2) **and** one green release cycle dispatches via the App. `gh secret delete PYTHINKER_HOME_REPO_DISPATCH_TOKEN --repo TechMatrix-labs/pythinker-code` (it is a repo secret today, per `promote-release.yml:168`). - - `PYTHINKER_CORE_PAGES_TOKEN` — delete after PR-code-1 merges (the only consumer, `release-pythinker-core.yml:101`, is removed there). `gh secret delete PYTHINKER_CORE_PAGES_TOKEN --repo TechMatrix-labs/pythinker-code`. + - `PYTHINKER_HOME_REPO_DISPATCH_TOKEN` — delete after **both** dispatch files are migrated (PR-code-1 + PR-code-2) **and** one green release cycle dispatches via the App. `gh secret delete PYTHINKER_HOME_REPO_DISPATCH_TOKEN --repo Pythoughts-labs/pythinker-code` (it is a repo secret today, per `promote-release.yml:168`). + - `PYTHINKER_CORE_PAGES_TOKEN` — delete after PR-code-1 merges (the only consumer, `release-pythinker-core.yml:101`, is removed there). `gh secret delete PYTHINKER_CORE_PAGES_TOKEN --repo Pythoughts-labs/pythinker-code`. **Local tooling the executor needs** (install once; none are repo deps): ```bash @@ -113,7 +113,7 @@ This is CI-wiring: verify with `actionlint` locally, then `gh workflow run` post - [ ] 2.1 Replace the `dispatch` job's `steps:` block (current lines 25-47, where the single `Trigger pythinker-home sync` step reads DISPATCH_TOKEN: ${{ secrets.PYTHINKER_HOME_REPO_DISPATCH_TOKEN }} and silently `exit 0` on empty) with a job-level `env:` + a mint step + a dispatch step. The exact replacement for lines 25-47: ```yaml env: - DISPATCH_OWNER: TechMatrix-labs + DISPATCH_OWNER: Pythoughts-labs DISPATCH_REPO: pythinker-home steps: # Mint a short-lived installation token for the org-owned @@ -322,30 +322,30 @@ The current `Get-LatestVersion` (lines 136-164) scans `releases?per_page=20` and - [ ] 6.1 Push and open the PR: ```bash git -C /home/ai/Projects/pythinker-code-main push -u origin release-orch/p0-dispatch-and-installers - gh pr create --repo TechMatrix-labs/pythinker-code --base main \ + gh pr create --repo Pythoughts-labs/pythinker-code --base main \ --title "ci: dispatch App migration + retire dead docs step + installer hardening" \ --body "P0 (1/2): migrate dispatch-pythinker-home-sync.yml to the pythinker-release-bot App token with fail-loud-on-empty; remove the dead pythinker-core pdoc gh-pages step (404 target); install-native.sh exponential backoff; install.ps1 /releases/latest-first with paginated fallback and backoff. No agent runtime deps. Sequencing note: promote-release.yml gate changes ship in PR-code-2 with the reconcile backstop." ``` Expected: prints the new PR URL. - [ ] 6.2 Wait for required checks (including `changelog`) to pass and CodeRabbit commit status on the head SHA to be `success` (C2). Verify before merge: ```bash - gh pr checks --repo TechMatrix-labs/pythinker-code - gh api repos/TechMatrix-labs/pythinker-code/commits/$(gh pr view --repo TechMatrix-labs/pythinker-code --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' + gh pr checks --repo Pythoughts-labs/pythinker-code + gh api repos/Pythoughts-labs/pythinker-code/commits/$(gh pr view --repo Pythoughts-labs/pythinker-code --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' ``` Expected: all checks `pass`; the CodeRabbit line prints `success`. Do not merge until then (C2). - [ ] 6.3 Merge (after CodeRabbit `success`): ```bash - gh pr merge --repo TechMatrix-labs/pythinker-code --squash + gh pr merge --repo Pythoughts-labs/pythinker-code --squash ``` Expected: `✓ Squashed and merged pull request #`. - [ ] 6.4 **Post-merge dispatch smoke test** (needs OP-1..OP-3 done): trigger the dispatch workflow manually and confirm the App-token path fires: ```bash - gh workflow run dispatch-pythinker-home-sync.yml --repo TechMatrix-labs/pythinker-code - gh run watch --repo TechMatrix-labs/pythinker-code $(gh run list --repo TechMatrix-labs/pythinker-code --workflow dispatch-pythinker-home-sync.yml -L1 --json databaseId -q '.[0].databaseId') + gh workflow run dispatch-pythinker-home-sync.yml --repo Pythoughts-labs/pythinker-code + gh run watch --repo Pythoughts-labs/pythinker-code $(gh run list --repo Pythoughts-labs/pythinker-code --workflow dispatch-pythinker-home-sync.yml -L1 --json databaseId -q '.[0].databaseId') ``` Expected: the run is green; the "Mint GitHub App token" step succeeds and the dispatch POST returns 204. Then confirm pythinker-home received it: ```bash - gh run list --repo TechMatrix-labs/pythinker-home --workflow sync-upstream-products.yml -L1 + gh run list --repo Pythoughts-labs/pythinker-home --workflow sync-upstream-products.yml -L1 ``` Expected: a fresh `repository_dispatch` run is listed. @@ -541,7 +541,7 @@ Branch: `release-orch/p0-promote-reconcile`. Touches `promote-release.yml` and a permissions: contents: read env: - DISPATCH_OWNER: TechMatrix-labs + DISPATCH_OWNER: Pythoughts-labs DISPATCH_REPO: pythinker-home steps: - name: Mint GitHub App token for pythinker-home @@ -651,7 +651,7 @@ Detects drift (tap formula version != `/releases/latest` OR served `public/versi cancel-in-progress: false env: - DISPATCH_OWNER: TechMatrix-labs + DISPATCH_OWNER: Pythoughts-labs DISPATCH_REPO: pythinker-home jobs: @@ -672,7 +672,7 @@ Detects drift (tap formula version != `/releases/latest` OR served `public/versi latest="${latest_tag#v}" echo "Latest published release: $latest_tag ($latest)" drift="" - tap_url="https://raw.githubusercontent.com/TechMatrix-labs/homebrew-pythinker/main/Formula/pythinker-code.rb" + tap_url="https://raw.githubusercontent.com/Pythoughts-labs/homebrew-pythinker/main/Formula/pythinker-code.rb" tap_text=$(curl -fsSL --retry 2 --retry-delay 2 "$tap_url" 2>/dev/null || true) if ! grep -qF "version \"${latest}\"" <<<"$tap_text"; then drift="$drift tap" @@ -798,17 +798,17 @@ Detects drift (tap formula version != `/releases/latest` OR served `public/versi - [ ] 11b.1 Push + PR: ```bash git -C /home/ai/Projects/pythinker-code-main push -u origin release-orch/p0-promote-reconcile - gh pr create --repo TechMatrix-labs/pythinker-code --base main \ + gh pr create --repo Pythoughts-labs/pythinker-code --base main \ --title "ci(promote): fail-loud sub-pkg PyPI gate + drift reconcile backstop" \ --body "P0 (2/2): block prerelease->latest until all pinned sub-packages resolve on PyPI; remove Homebrew from the gate; per-channel bottleneck Slack; release-readiness issue (issues:write) whose rows tick as channels go ready; separate App-authed needs:promote dispatch job with fail-loud token; asset URLs from API tag_name. Ships release-readiness-reconcile.yml in the SAME PR so the §5 sequencing rule (reconcile before/with gate removal) holds; reconcile auto-closes only OLDER-than-latest readiness issues (semver). Depends on PR-code-1 (dispatch App migration) for the full PAT retirement." ``` Expected: prints the new PR URL. - [ ] 11b.2 Wait for checks + CodeRabbit `success` on the head SHA (C2), as in Task 6.2: ```bash - gh pr checks --repo TechMatrix-labs/pythinker-code - gh api repos/TechMatrix-labs/pythinker-code/commits/$(gh pr view --repo TechMatrix-labs/pythinker-code --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' + gh pr checks --repo Pythoughts-labs/pythinker-code + gh api repos/Pythoughts-labs/pythinker-code/commits/$(gh pr view --repo Pythoughts-labs/pythinker-code --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' ``` - Expected: all checks `pass`; CodeRabbit `success`. Merge with `gh pr merge --repo TechMatrix-labs/pythinker-code --squash` only after `success`. + Expected: all checks `pass`; CodeRabbit `success`. Merge with `gh pr merge --repo Pythoughts-labs/pythinker-code --squash` only after `success`. --- @@ -853,7 +853,7 @@ Branch: `release-orch/p0-site`, in `/home/ai/Projects/pythinker-site/site`. This const codeRelease = { tag_name: "v0.27.0", - html_url: "https://github.com/TechMatrix-labs/pythinker-code/releases/tag/v0.27.0", + html_url: "https://github.com/Pythoughts-labs/pythinker-code/releases/tag/v0.27.0", assets: [ { name: "PythinkerSetup-0.27.0.exe", browser_download_url: "" }, { name: "PythinkerSetup-0.27.0.exe.sha256", browser_download_url: "" }, @@ -1026,7 +1026,7 @@ Branch: `release-orch/p0-site`, in `/home/ai/Projects/pythinker-site/site`. This - [ ] 13.1 Add the job-level receiver gate to `sync-upstream-products.yml`. The gate must let cron/manual through (no payload) and only restrict `repository_dispatch`. Add to the `sync` job after `runs-on: ubuntu-latest` (current line 20): ```yaml - if: github.event_name != 'repository_dispatch' || github.event.client_payload.source_repo == 'TechMatrix-labs/pythinker-code' + if: github.event_name != 'repository_dispatch' || github.event.client_payload.source_repo == 'Pythoughts-labs/pythinker-code' ``` - [ ] 13.2 Thread the dispatched ref into the sync via `env:` (NEVER into a `run:` line — injection, §4). Edit the `Sync public upstream products` step (current lines 30-33): ```yaml @@ -1125,15 +1125,15 @@ Only do this if **OP-4** confirmed the live host runs Dokploy build-from-source. - [ ] 15.1 Push + PR: ```bash git -C /home/ai/Projects/pythinker-site/site push -u origin release-orch/p0-site - gh pr create --repo TechMatrix-labs/pythinker-home --base main \ + gh pr create --repo Pythoughts-labs/pythinker-home --base main \ --title "P0: receiver source-repo gate, version.json, Mode-B fix, dead mirrors, deploy retire" \ --body "P0 site half: job-level receiver if: on client_payload.source_repo (cron/manual carry no payload -> allowed); ref passed via env, validated in TS, never into a run: shell; emit public/version.json {pythinkerCode,tag}; fix the line-366 hardcoded literal to derive from per-product owner/repo config; pin raw-source fetch to the dispatched ref (tag or 40-char sha) while asset URLs stay from API tag_name; git rm the 3 dead tracked install.ps1 mirrors (canonical = public/install.{sh,ps1}); retire orphaned GHCR+Watchtower+Traefik compose (Dokploy build-from-source is canonical). New bun:test unit tests (incl. §7 config lockstep) for the TS logic." ``` Expected: prints the new PR URL. - [ ] 15.2 Wait for checks + CodeRabbit `success` on the head SHA (C2): ```bash - gh pr checks --repo TechMatrix-labs/pythinker-home - gh api repos/TechMatrix-labs/pythinker-home/commits/$(gh pr view --repo TechMatrix-labs/pythinker-home --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' + gh pr checks --repo Pythoughts-labs/pythinker-home + gh api repos/Pythoughts-labs/pythinker-home/commits/$(gh pr view --repo Pythoughts-labs/pythinker-home --json headRefOid -q .headRefOid)/status --jq '.statuses[] | select(.context=="CodeRabbit") | .state' ``` Expected: checks `pass`; CodeRabbit `success`. Merge `--squash` only after `success`. (pythinker-home `main` must stay unprotected for the deploy chain — do not enable protection.) @@ -1143,16 +1143,16 @@ Only do this if **OP-4** confirmed the live host runs Dokploy build-from-source. **Done = all three PRs merged (each past CodeRabbit `success`, C2), the App fully replaces both PAT dispatch sites, the next release flips only when every pinned sub-package resolves on PyPI, the readiness issue ticks rows then closes on success, and the site serves a correct `public/version.json` with the reconcile backstop live.** Prove it with one rehearsal + one real cycle: -1. **App dispatch (post PR-code-1):** `gh workflow run dispatch-pythinker-home-sync.yml --repo TechMatrix-labs/pythinker-code` → `gh run watch` green; the mint step succeeds; pythinker-home shows a fresh `repository_dispatch` sync run that **passes the receiver gate** (source_repo matches). This proves the App token + receiver gate end-to-end. (Confirms OP-1..OP-3.) +1. **App dispatch (post PR-code-1):** `gh workflow run dispatch-pythinker-home-sync.yml --repo Pythoughts-labs/pythinker-code` → `gh run watch` green; the mint step succeeds; pythinker-home shows a fresh `repository_dispatch` sync run that **passes the receiver gate** (source_repo matches). This proves the App token + receiver gate end-to-end. (Confirms OP-1..OP-3.) -2. **Reconcile dry-run (post PR-code-2 + PR-home-3):** `gh workflow run release-readiness-reconcile.yml --repo TechMatrix-labs/pythinker-code` → `gh run watch`. With the site already at latest, expect **no drift** (`drift=` empty), the stale-issue close step runs cleanly (closing only older-than-latest issues, leaving any newer in-progress issue open), `notify-drift` does NOT run. To prove the drift path, the run's "Detect drift" log shows the served `pythinkerCode` vs latest comparison; the `notify-drift` job's `if:` (drift present AND not re-dispatched this run) confirms a normal re-dispatch run does not page. +2. **Reconcile dry-run (post PR-code-2 + PR-home-3):** `gh workflow run release-readiness-reconcile.yml --repo Pythoughts-labs/pythinker-code` → `gh run watch`. With the site already at latest, expect **no drift** (`drift=` empty), the stale-issue close step runs cleanly (closing only older-than-latest issues, leaving any newer in-progress issue open), `notify-drift` does NOT run. To prove the drift path, the run's "Detect drift" log shows the served `pythinkerCode` vs latest comparison; the `notify-drift` job's `if:` (drift present AND not re-dispatched this run) confirms a normal re-dispatch run does not page. -3. **promote rehearsal (no real tag):** after a real release tag exists, `gh workflow run promote-release.yml --repo TechMatrix-labs/pythinker-code -f tag=v` re-enters CHECKING; with all four PyPI URLs already 200 and assets present, it PROMOTES idempotently (PATCH is a no-op), the `release-readiness` issue is upserted, its rows ticked, then closed, and the `dispatch-site` job mints the App token and fires. The Slack `notify-failure` job does NOT run (no failure). This exercises the new blocking-PyPI check and the separated dispatch job without waiting on a fresh build. +3. **promote rehearsal (no real tag):** after a real release tag exists, `gh workflow run promote-release.yml --repo Pythoughts-labs/pythinker-code -f tag=v` re-enters CHECKING; with all four PyPI URLs already 200 and assets present, it PROMOTES idempotently (PATCH is a no-op), the `release-readiness` issue is upserted, its rows ticked, then closed, and the `dispatch-site` job mints the App token and fires. The Slack `notify-failure` job does NOT run (no failure). This exercises the new blocking-PyPI check and the separated dispatch job without waiting on a fresh build. 4. **First real release** (the true end-to-end): maintainer tags `vX.Y.Z`; `promote-release` waits for assets + all four PyPI pins; on ready it flips `prerelease=false, make_latest=true`, ticks+closes the readiness issue, and the `needs: promote` dispatch job updates pythinker-home → Dokploy redeploys → `https://pythinker.com/version.json` returns `{"pythinkerCode":"X.Y.Z","tag":"vX.Y.Z"}`. Confirm: ```bash curl -fsSL https://pythinker.com/version.json - gh release view vX.Y.Z --repo TechMatrix-labs/pythinker-code --json isLatest,isPrerelease + gh release view vX.Y.Z --repo Pythoughts-labs/pythinker-code --json isLatest,isPrerelease pip index versions pythinker-code # or: pip install pythinker-code==X.Y.Z --dry-run ``` Expected: `version.json` == X.Y.Z; release `isLatest=true, isPrerelease=false`; `pip install` resolves all transitive pins (no 500 on a lagging sub-package). diff --git a/docs/superpowers/plans/2026-05-31-release-orchestration-p2-distribution-channels.md b/docs/superpowers/plans/2026-05-31-release-orchestration-p2-distribution-channels.md index b0c6ab62..19efc5e0 100644 --- a/docs/superpowers/plans/2026-05-31-release-orchestration-p2-distribution-channels.md +++ b/docs/superpowers/plans/2026-05-31-release-orchestration-p2-distribution-channels.md @@ -4,7 +4,7 @@ **Goal:** Ship four best-effort distribution channels (Docker/GHCR, Scoop, Nix `apps.default`, manual WinGet) that all set `PYTHINKER_MANAGED` for channel-native upgrades, never gate `promote-release`, and carry version-less README snippets so they never enter the version-sprawl set. -**Architecture:** All four channels are additive workflows in `pythinker-code` (the source of truth). Docker builds a thin `python:3.14-slim` image that `pip install`s the already-published wheel (zero new runtime deps, C3), built multi-arch native (amd64 + ubuntu-24.04-arm), pushed by digest, stitched with `buildx imagetools`, `:latest` advanced only for a promoted (non-prerelease) release with an ancestor-check. Scoop mirrors the trusted Homebrew tap pattern exactly: a generator (`packages/scoop-bucket/generate-manifest.py`) polls the EXISTING Windows onedir zip from the release, and `scoop-bucket.yml` (in pythinker-code) mints the `pythinker-scoop-publisher` App token and git-pushes the manifest to the org repo `TechMatrix-labs/scoop-pythinker`. Nix gains an `apps.default` plus a `PYTHINKER_MANAGED=nix` wrapper env and a monthly `update-flake-lock` PR. WinGet is a manual `workflow_dispatch` using an isolated fine-grained PAT. +**Architecture:** All four channels are additive workflows in `pythinker-code` (the source of truth). Docker builds a thin `python:3.14-slim` image that `pip install`s the already-published wheel (zero new runtime deps, C3), built multi-arch native (amd64 + ubuntu-24.04-arm), pushed by digest, stitched with `buildx imagetools`, `:latest` advanced only for a promoted (non-prerelease) release with an ancestor-check. Scoop mirrors the trusted Homebrew tap pattern exactly: a generator (`packages/scoop-bucket/generate-manifest.py`) polls the EXISTING Windows onedir zip from the release, and `scoop-bucket.yml` (in pythinker-code) mints the `pythinker-scoop-publisher` App token and git-pushes the manifest to the org repo `Pythoughts-labs/scoop-pythinker`. Nix gains an `apps.default` plus a `PYTHINKER_MANAGED=nix` wrapper env and a monthly `update-flake-lock` PR. WinGet is a manual `workflow_dispatch` using an isolated fine-grained PAT. **Tech Stack:** GitHub Actions, `docker/build-push-action` + `buildx imagetools` (GHCR), `actions/create-github-app-token` (Scoop App), stdlib Python generator (`urllib`, mirrors `generate-formula.py`), `uv run pytest` (generator test), Nix flakes (`uv2nix`), `wingetcreate`. @@ -27,14 +27,14 @@ This phase **depends on P1** for the `PYTHINKER_MANAGED=` env read at t These touch org admin, secrets, and an external repo — they are **operator actions**, not code steps. Do them before the Scoop/WinGet tasks. Verify each with the `gh` command shown. -### OP-1 — Create the public org repo `TechMatrix-labs/scoop-pythinker` +### OP-1 — Create the public org repo `Pythoughts-labs/scoop-pythinker` ```bash -gh repo create TechMatrix-labs/scoop-pythinker \ +gh repo create Pythoughts-labs/scoop-pythinker \ --public \ --description "Scoop bucket for Pythinker Code. Auto-updated by pythinker-code/.github/workflows/scoop-bucket.yml on every semver release tag. Do not hand-edit bucket/*." \ --disable-wiki # Verify: -gh repo view TechMatrix-labs/scoop-pythinker --json visibility,name -q '.name + " " + .visibility' +gh repo view Pythoughts-labs/scoop-pythinker --json visibility,name -q '.name + " " + .visibility' # Expected: scoop-pythinker public ``` Leave it empty — `scoop-bucket.yml`'s first run initializes `main` exactly like `homebrew-tap.yml:98-145` does for the empty tap. @@ -42,41 +42,41 @@ Leave it empty — `scoop-bucket.yml`'s first run initializes `main` exactly lik ### OP-2 — Create + install the `pythinker-scoop-publisher` GitHub App In the org **Settings → Developer settings → GitHub Apps → New GitHub App** (UI; cannot be scripted): - **Name:** `pythinker-scoop-publisher` -- **Homepage URL:** `https://github.com/TechMatrix-labs/scoop-pythinker` +- **Homepage URL:** `https://github.com/Pythoughts-labs/scoop-pythinker` - **Webhook:** uncheck Active. - **Repository permissions:** `Contents: Read and write`, `Metadata: Read-only` (mandatory). Nothing else. - Create, then **Generate a private key** (downloads a `.pem`). Note the **App ID**. -- **Install App** → choose **Only select repositories** → select **only** `TechMatrix-labs/scoop-pythinker`. +- **Install App** → choose **Only select repositories** → select **only** `Pythoughts-labs/scoop-pythinker`. Verify the installation is scoped to exactly one repo: ```bash -gh api /orgs/TechMatrix-labs/installations --jq '.installations[] | select(.app_slug=="pythinker-scoop-publisher") | {app_id, repository_selection}' +gh api /orgs/Pythoughts-labs/installations --jq '.installations[] | select(.app_slug=="pythinker-scoop-publisher") | {app_id, repository_selection}' # Expected: repository_selection "selected" ``` ### OP-3 — Add the App credentials as ORG secrets (visible to pythinker-code) ```bash # App ID (numeric, from OP-2): -gh secret set SCOOP_BUCKET_APP_ID --org TechMatrix-labs --visibility selected --repos pythinker-code --body "" +gh secret set SCOOP_BUCKET_APP_ID --org Pythoughts-labs --visibility selected --repos pythinker-code --body "" # Private key (the .pem downloaded in OP-2): -gh secret set SCOOP_BUCKET_APP_PRIVATE_KEY --org TechMatrix-labs --visibility selected --repos pythinker-code < /path/to/pythinker-scoop-publisher.private-key.pem +gh secret set SCOOP_BUCKET_APP_PRIVATE_KEY --org Pythoughts-labs --visibility selected --repos pythinker-code < /path/to/pythinker-scoop-publisher.private-key.pem # Verify both exist: -gh secret list --org TechMatrix-labs | grep SCOOP_BUCKET_APP +gh secret list --org Pythoughts-labs | grep SCOOP_BUCKET_APP # Expected: SCOOP_BUCKET_APP_ID and SCOOP_BUCKET_APP_PRIVATE_KEY listed ``` ### OP-4 — (WinGet, Task 4.1 only) Create the isolated fine-grained PAT `WINGET_SUBMIT_TOKEN` A GitHub App **cannot** open PRs against the external `microsoft/winget-pkgs`, so WinGet needs a classic/fine-grained PAT on a fork. Create a fine-grained PAT (UI: **Settings → Developer settings → Fine-grained tokens**) scoped to your `microsoft/winget-pkgs` fork with `Contents: Read and write` + `Pull requests: Read and write`, short expiry. Then: ```bash -gh secret set WINGET_SUBMIT_TOKEN --repo TechMatrix-labs/pythinker-code --body "" -gh secret list --repo TechMatrix-labs/pythinker-code | grep WINGET_SUBMIT_TOKEN +gh secret set WINGET_SUBMIT_TOKEN --repo Pythoughts-labs/pythinker-code --body "" +gh secret list --repo Pythoughts-labs/pythinker-code | grep WINGET_SUBMIT_TOKEN # Expected: WINGET_SUBMIT_TOKEN listed ``` ### OP-5 — Confirm GHCR is enabled for the org GHCR (`ghcr.io`) needs no secret (uses `GITHUB_TOKEN` + `packages: write`), but the org must allow Actions to create packages. Verify after the first Docker run that the package exists: ```bash -gh api /orgs/TechMatrix-labs/packages?package_type=container --jq '.[].name' +gh api /orgs/Pythoughts-labs/packages?package_type=container --jq '.[].name' # After first successful docker.yml run, expect: pythinker-code ``` @@ -88,7 +88,7 @@ gh api /orgs/TechMatrix-labs/packages?package_type=container --jq '.[].name' |---|---|---| | Create | `Dockerfile` | Thin `python:3.14-slim` image; `pip install pythinker-code==${V}` from PyPI; sets `PYTHINKER_MANAGED=docker`; entrypoint `pythinker`. | | Create | `.dockerignore` | Keep the build context tiny (the wheel comes from PyPI, not the repo). | -| Create | `.github/workflows/docker.yml` | On semver release tags (`v+([0-9]).+([0-9]).+([0-9])`): wait-for-PyPI, build amd64 + arm64 by digest, stitch manifest to `ghcr.io/techmatrix-labs/pythinker-code:`, advance `:latest` only when the release is promoted (non-prerelease) + ancestor-check. Best-effort. | +| Create | `.github/workflows/docker.yml` | On semver release tags (`v+([0-9]).+([0-9]).+([0-9])`): wait-for-PyPI, build amd64 + arm64 by digest, stitch manifest to `ghcr.io/pythoughts-labs/pythinker-code:`, advance `:latest` only when the release is promoted (non-prerelease) + ancestor-check. Best-effort. | | Create | `packages/scoop-bucket/generate-manifest.py` | Stdlib generator: poll the release, read the EXISTING Windows onedir zip + `.sha256`, render `bucket/pythinker-code.json`. Mirrors `packages/homebrew-tap/generate-formula.py`. | | Create | `packages/scoop-bucket/pythinker-code.json.tmpl` | Scoop manifest template with `__VERSION__`/`__URL__`/`__SHA256__` placeholders; `bin: pythinker\pythinker.exe`; `env_set: PYTHINKER_MANAGED=scoop`; version-less `autoupdate`. | | Create | `.github/workflows/scoop-bucket.yml` | On semver release tags (`v+([0-9]).+([0-9]).+([0-9])`) + `workflow_dispatch`: generate the manifest, mint `pythinker-scoop-publisher` token, git-push `bucket/pythinker-code.json` into `scoop-pythinker`. Mirrors `homebrew-tap.yml`. | @@ -204,7 +204,7 @@ permissions: packages: write env: - IMAGE_NAME: ghcr.io/techmatrix-labs/pythinker-code + IMAGE_NAME: ghcr.io/pythoughts-labs/pythinker-code FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" # One run per tag; never cancel a tag/dispatch run (each must publish its digest). @@ -488,22 +488,22 @@ gh pr create --base main --title "feat(docker): GHCR distribution channel" \ gh workflow run docker.yml --ref feat/p2-docker-ghcr -f version=0.27.0 gh run watch "$(gh run list --workflow=docker.yml --limit 1 --json databaseId -q '.[0].databaseId')" ``` -Expected observable result: `resolve` passes the PyPI-wait (0.27.0 is already live), `build-amd64` + `build-arm64` push digests, `merge` creates `ghcr.io/techmatrix-labs/pythinker-code:0.27.0`. **`move-latest` reports `move=true` and DOES advance `:latest` to `0.27.0`.** The gate keys on the GitHub Release's `isPrerelease` field, **not** on the branch the dispatch ran from: `v0.27.0` is an already-promoted (non-prerelease) release, so `is_pre=false` and (on a first run with no existing `:latest`) `move=true`. This is benign — `0.27.0` is the current released version, so `:latest` is simply re-pointed at the artifact it already represents; the wheel installed is the published PyPI artifact regardless of which branch built the image. The `move=false` skip path is exercised only against a still-prerelease tag (see Phase-verification step 5), which is the real tag-push behavior. Confirm the image: +Expected observable result: `resolve` passes the PyPI-wait (0.27.0 is already live), `build-amd64` + `build-arm64` push digests, `merge` creates `ghcr.io/pythoughts-labs/pythinker-code:0.27.0`. **`move-latest` reports `move=true` and DOES advance `:latest` to `0.27.0`.** The gate keys on the GitHub Release's `isPrerelease` field, **not** on the branch the dispatch ran from: `v0.27.0` is an already-promoted (non-prerelease) release, so `is_pre=false` and (on a first run with no existing `:latest`) `move=true`. This is benign — `0.27.0` is the current released version, so `:latest` is simply re-pointed at the artifact it already represents; the wheel installed is the published PyPI artifact regardless of which branch built the image. The `move=false` skip path is exercised only against a still-prerelease tag (see Phase-verification step 5), which is the real tag-push behavior. Confirm the image: ```bash -docker buildx imagetools inspect ghcr.io/techmatrix-labs/pythinker-code:0.27.0 +docker buildx imagetools inspect ghcr.io/pythoughts-labs/pythinker-code:0.27.0 ``` Expected: a manifest list with `linux/amd64` and `linux/arm64`. - [ ] 3. Confirm the channel marker survives into the published image: ```bash -docker run --rm ghcr.io/techmatrix-labs/pythinker-code:0.27.0 env | grep PYTHINKER_MANAGED +docker run --rm ghcr.io/pythoughts-labs/pythinker-code:0.27.0 env | grep PYTHINKER_MANAGED ``` Expected: `PYTHINKER_MANAGED=docker` (verified in CI/locally against the pulled image — NOT a pytest; this is an integration check). - [ ] 4. **CodeRabbit gate (C2):** confirm the `CodeRabbit` commit status on the PR head SHA is `success` before merging: ```bash gh pr view --json statusCheckRollup,commits -q '.commits[-1].oid' -gh api "/repos/TechMatrix-labs/pythinker-code/commits//status" --jq '.statuses[] | select(.context=="CodeRabbit") | .state' +gh api "/repos/Pythoughts-labs/pythinker-code/commits//status" --jq '.statuses[] | select(.context=="CodeRabbit") | .state' ``` Expected: `success`. Read its summary + any "Actionable comments posted: N" before merging. Then merge via the UI/`gh pr merge --squash` only after green. @@ -538,12 +538,12 @@ Expected: `success`. Read its summary + any "Actionable comments posted: N" befo "PYTHINKER_MANAGED": "scoop" }, "checkver": { - "github": "https://github.com/TechMatrix-labs/pythinker-code" + "github": "https://github.com/Pythoughts-labs/pythinker-code" }, "autoupdate": { "architecture": { "64bit": { - "url": "https://github.com/TechMatrix-labs/pythinker-code/releases/download/v$version/pythinker-$version-x86_64-pc-windows-msvc-onedir.zip" + "url": "https://github.com/Pythoughts-labs/pythinker-code/releases/download/v$version/pythinker-$version-x86_64-pc-windows-msvc-onedir.zip" } }, "hash": { @@ -684,7 +684,7 @@ import urllib.request from pathlib import Path from typing import Any -GITHUB_REPO = "TechMatrix-labs/pythinker-code" +GITHUB_REPO = "Pythoughts-labs/pythinker-code" GITHUB_RELEASE_API = f"https://api.github.com/repos/{GITHUB_REPO}/releases/tags/v{{version}}" @@ -847,7 +847,7 @@ jobs: permissions: contents: read env: - BUCKET_OWNER: TechMatrix-labs + BUCKET_OWNER: Pythoughts-labs BUCKET_REPO: scoop-pythinker steps: - name: Checkout source repo @@ -936,15 +936,15 @@ jobs: cat > README.md < **Honesty note — what is and is NOT test-verified.** The Task 2.2 pytest only asserts the manifest *shape* (`bin`, `env_set`, url, hash), and this dry-run only confirms the manifest *file lands* in scoop-pythinker with the right `version`/`env_set`. Neither runs `scoop install` on a Windows host, so true shim/install correctness (that `bin: pythinker\pythinker.exe` resolves against the extracted `pythinker/` root and Scoop creates a working `pythinker` shim) is **outside this plan's automated checks**. It is therefore NOT claimed as test-verified — only the manifest shape and the cross-repo publish are. Real install verification requires a Windows host running `scoop bucket add pythinker https://github.com/TechMatrix-labs/scoop-pythinker && scoop install pythinker-code`; do that once manually after the first publish. +> **Honesty note — what is and is NOT test-verified.** The Task 2.2 pytest only asserts the manifest *shape* (`bin`, `env_set`, url, hash), and this dry-run only confirms the manifest *file lands* in scoop-pythinker with the right `version`/`env_set`. Neither runs `scoop install` on a Windows host, so true shim/install correctness (that `bin: pythinker\pythinker.exe` resolves against the extracted `pythinker/` root and Scoop creates a working `pythinker` shim) is **outside this plan's automated checks**. It is therefore NOT claimed as test-verified — only the manifest shape and the cross-repo publish are. Real install verification requires a Windows host running `scoop bucket add pythinker https://github.com/Pythoughts-labs/scoop-pythinker && scoop install pythinker-code`; do that once manually after the first publish. - [ ] 3. CodeRabbit gate (C2) as in Task 1.3 step 4, then merge. @@ -1243,11 +1243,11 @@ jobs: VERSION: ${{ inputs.version }} run: | $ErrorActionPreference = "Stop" - $installerUrl = "https://github.com/TechMatrix-labs/pythinker-code/releases/download/v$env:VERSION/PythinkerSetup-$env:VERSION.exe" + $installerUrl = "https://github.com/Pythoughts-labs/pythinker-code/releases/download/v$env:VERSION/PythinkerSetup-$env:VERSION.exe" Invoke-WebRequest -Uri "https://aka.ms/wingetcreate/latest" -OutFile wingetcreate.exe # PackageIdentifier must match the existing winget-pkgs entry; create it # once manually via `wingetcreate new` before the first automated update. - .\wingetcreate.exe update TechMatrixLabs.PythinkerCode ` + .\wingetcreate.exe update PythoughtsLabs.PythinkerCode ` --version $env:VERSION ` --urls "$installerUrl" ` --submit ` @@ -1257,7 +1257,7 @@ jobs: > **WinGet does NOT set `PYTHINKER_MANAGED` — accepted limitation, not an oversight.** Unlike Docker (`ENV`), Scoop (`env_set`), and Nix (`makeWrapper --set`), WinGet installs the *identical* `PythinkerSetup-.exe` that a direct `/releases/download` grab installs, and a WinGet manifest has **no `env_set` equivalent** to inject a process env var. So a WinGet install is byte-for-byte a native install and the in-app updater cannot distinguish the two. This is fine: that installer drops the `.pythinker-native` sentinel (`src/pythinker_code/native.py:17`), so `is_native_build()` returns `True` and `_detect_upgrade_command()` (`src/pythinker_code/ui/shell/update.py:100`) routes WinGet users to the **native-installer upgrade hint** — a correct, if not WinGet-specific, message. A genuinely WinGet-native upgrade hint would require a marker or wrapper that does not exist today; that is a documented **follow-up**, deliberately out of P2 scope. (The contract's "Scoop/WinGet manifests set it" is honored for Scoop; for WinGet there is no manifest mechanism to honor it, hence the documented fallback.) -> **WinGet README snippet is intentionally DEFERRED (see Task 5.1).** No version-less WinGet row is added to the README in this phase. The `TechMatrixLabs.PythinkerCode` PackageIdentifier does not exist in `microsoft/winget-pkgs` until a human runs this workflow on a real release (and a maintainer first creates it via `wingetcreate new`). Advertising `winget install TechMatrixLabs.PythinkerCode` before that manifest is merged would point users at a non-existent package. The README row is therefore added only after the first WinGet manifest is live — tracked as a follow-up, not a silent omission. +> **WinGet README snippet is intentionally DEFERRED (see Task 5.1).** No version-less WinGet row is added to the README in this phase. The `PythoughtsLabs.PythinkerCode` PackageIdentifier does not exist in `microsoft/winget-pkgs` until a human runs this workflow on a real release (and a maintainer first creates it via `wingetcreate new`). Advertising `winget install PythoughtsLabs.PythinkerCode` before that manifest is merged would point users at a non-existent package. The README row is therefore added only after the first WinGet manifest is live — tracked as a follow-up, not a silent omission. - [ ] 2. Lint: ```bash @@ -1303,13 +1303,13 @@ git switch -c docs/p2-install-snippets - [ ] 2. Add three **version-less** rows to the platform install table. After the Homebrew row (`README.md:153`), insert: ```markdown -| **🐳 Docker** | `docker run --rm -it ghcr.io/techmatrix-labs/pythinker-code` | GHCR multi-arch image | -| **🪟 Windows — Scoop** | `scoop bucket add pythinker https://github.com/TechMatrix-labs/scoop-pythinker && scoop install pythinker-code` | auto-published Scoop bucket | -| **❄️ Nix** | `nix run github:TechMatrix-labs/pythinker-code` | flake `apps.default` | +| **🐳 Docker** | `docker run --rm -it ghcr.io/pythoughts-labs/pythinker-code` | GHCR multi-arch image | +| **🪟 Windows — Scoop** | `scoop bucket add pythinker https://github.com/Pythoughts-labs/scoop-pythinker && scoop install pythinker-code` | auto-published Scoop bucket | +| **❄️ Nix** | `nix run github:Pythoughts-labs/pythinker-code` | flake `apps.default` | ``` > Every command is version-less (`scoop install pythinker-code`, `docker run ghcr.io/...`, `nix run github:...`) per spec §6 "C4 for new channels" — they never enter the F3 sprawl set, so the lockstep test (which only asserts version-bearing strings) is unaffected. > -> **WinGet row is intentionally omitted here (deferral, not oversight).** Three rows are added — Docker, Scoop, Nix — and **no** WinGet row. The `TechMatrixLabs.PythinkerCode` PackageIdentifier does not exist in `microsoft/winget-pkgs` until the manual `winget.yml` workflow (Task 4.1) submits it on a real release, so advertising `winget install TechMatrixLabs.PythinkerCode` now would point users at an unpublished package. Add the version-less WinGet row (`winget install TechMatrixLabs.PythinkerCode`) in a follow-up once the first manifest is merged upstream. This deferral is also recorded in Task 4.1. +> **WinGet row is intentionally omitted here (deferral, not oversight).** Three rows are added — Docker, Scoop, Nix — and **no** WinGet row. The `PythoughtsLabs.PythinkerCode` PackageIdentifier does not exist in `microsoft/winget-pkgs` until the manual `winget.yml` workflow (Task 4.1) submits it on a real release, so advertising `winget install PythoughtsLabs.PythinkerCode` now would point users at an unpublished package. Add the version-less WinGet row (`winget install PythoughtsLabs.PythinkerCode`) in a follow-up once the first manifest is merged upstream. This deferral is also recorded in Task 4.1. - [ ] 3. Sanity check that you introduced no `==` or `PythinkerSetup-` strings (would break the P1 lockstep test): ```bash @@ -1340,7 +1340,7 @@ gh pr create --base main --title "docs(p2): version-less install snippets for ne **Done means:** the next real `vX.Y.Z` tag publishes all four channels best-effort, none of them gate `promote-release`, and each non-self-updating channel sets `PYTHINKER_MANAGED`. -1. **Pre-flight (before the next real release):** all four PRs merged; OP-1..OP-5 confirmed (`gh secret list --org TechMatrix-labs | grep SCOOP_BUCKET_APP` shows both; `gh repo view TechMatrix-labs/scoop-pythinker` is public). P1 merged (the `PYTHINKER_MANAGED` env read exists in `update.py`) — otherwise the markers are set but unread. +1. **Pre-flight (before the next real release):** all four PRs merged; OP-1..OP-5 confirmed (`gh secret list --org Pythoughts-labs | grep SCOOP_BUCKET_APP` shows both; `gh repo view Pythoughts-labs/scoop-pythinker` is public). P1 merged (the `PYTHINKER_MANAGED` env read exists in `update.py`) — otherwise the markers are set but unread. 2. **First real release rehearsal:** on the next maintainer release, after the human pushes `vX.Y.Z`, watch the four channel workflows fire from the tag: ```bash @@ -1357,9 +1357,9 @@ grep -n "docker\|scoop\|ghcr\|nix" .github/workflows/promote-release.yml || echo Expected: `GOOD: no P2 channel referenced in promote gate`. 4. **Channel-live checks after the release:** - - Docker: `docker run --rm ghcr.io/techmatrix-labs/pythinker-code: --version` prints `X.Y.Z`; `docker run --rm ... env | grep PYTHINKER_MANAGED` → `docker`. **`:latest` does NOT auto-advance** — `docker.yml` has no `release:` trigger and promote flips the prerelease flag via a release edit that does not re-fire it (see Task 1.2 runbook note). After promotion the maintainer MUST run `gh workflow run docker.yml -f version=X.Y.Z`; only after that re-dispatch does `:latest` resolve to `X.Y.Z` (verify with `docker buildx imagetools inspect ghcr.io/techmatrix-labs/pythinker-code:latest`). - - Scoop: `gh api /repos/TechMatrix-labs/scoop-pythinker/contents/bucket/pythinker-code.json` shows `version == X.Y.Z` and `env_set.PYTHINKER_MANAGED == scoop`. - - Nix: the `nix-test` CI job on main is green and its log shows the `PYTHINKER_MANAGED` assertion passing; `nix run github:TechMatrix-labs/pythinker-code -- --version` (on a Nix host) prints `X.Y.Z`. + - Docker: `docker run --rm ghcr.io/pythoughts-labs/pythinker-code: --version` prints `X.Y.Z`; `docker run --rm ... env | grep PYTHINKER_MANAGED` → `docker`. **`:latest` does NOT auto-advance** — `docker.yml` has no `release:` trigger and promote flips the prerelease flag via a release edit that does not re-fire it (see Task 1.2 runbook note). After promotion the maintainer MUST run `gh workflow run docker.yml -f version=X.Y.Z`; only after that re-dispatch does `:latest` resolve to `X.Y.Z` (verify with `docker buildx imagetools inspect ghcr.io/pythoughts-labs/pythinker-code:latest`). + - Scoop: `gh api /repos/Pythoughts-labs/scoop-pythinker/contents/bucket/pythinker-code.json` shows `version == X.Y.Z` and `env_set.PYTHINKER_MANAGED == scoop`. + - Nix: the `nix-test` CI job on main is green and its log shows the `PYTHINKER_MANAGED` assertion passing; `nix run github:Pythoughts-labs/pythinker-code -- --version` (on a Nix host) prints `X.Y.Z`. - WinGet: a human runs `gh workflow run winget.yml -f version=X.Y.Z` only after promotion; it opens a PR on the winget-pkgs fork. 5. **Best-effort proof:** intentionally re-run `docker.yml` against a still-prerelease tag (e.g. immediately after a tag, before promote flips it) — `move-latest` must report `move=false` and skip, while the version tag still publishes. This proves a channel failure/lag can never advance `:latest` ahead of `/releases/latest` and can never block the release. diff --git a/docs/superpowers/specs/2026-05-22-windows-native-installer-design.md b/docs/superpowers/specs/2026-05-22-windows-native-installer-design.md index 29b0443c..ad837f9a 100644 --- a/docs/superpowers/specs/2026-05-22-windows-native-installer-design.md +++ b/docs/superpowers/specs/2026-05-22-windows-native-installer-design.md @@ -1,7 +1,7 @@ # Pythinker Native Windows Installer — Design **Status:** Approved (2026-05-22) -**Owner:** TechMatrix-labs +**Owner:** Pythoughts-labs **Tracking:** Brings parity with Claude Code's native installer for the Windows distribution surface. --- diff --git a/docs/superpowers/specs/2026-05-31-release-orchestration-design.md b/docs/superpowers/specs/2026-05-31-release-orchestration-design.md index bdd5f996..888c59ad 100644 --- a/docs/superpowers/specs/2026-05-31-release-orchestration-design.md +++ b/docs/superpowers/specs/2026-05-31-release-orchestration-design.md @@ -2,13 +2,13 @@ title: Release & Distribution Orchestration — Design Spec status: approved-design date: 2026-05-31 -scope: TechMatrix-labs/{pythinker-code, homebrew-pythinker, pythinker-home} +scope: Pythoughts-labs/{pythinker-code, homebrew-pythinker, pythinker-home} provenance: multi-agent design workflow wf_620b356a-d6e (5 subsystem designs -> adversarial stress-tests -> synthesis -> completeness critic -> final merge); ground-truthed against live repos + PyPI on 2026-05-31 --- # Pythinker-code 3-Repo Release & Distribution Orchestration — Final Design Spec -**Scope:** TechMatrix-labs/{pythinker-code, homebrew-pythinker, pythinker-home}. Coherent evolution — no consolidation, no churn. Respects C1–C5. This is the approval-ready architecture; every punch-list item from the completeness critique is resolved inline (fixed, or justified out-of-scope in one line). Ground-truthed against the live repos on 2026-05-31. +**Scope:** Pythoughts-labs/{pythinker-code, homebrew-pythinker, pythinker-home}. Coherent evolution — no consolidation, no churn. Respects C1–C5. This is the approval-ready architecture; every punch-list item from the completeness critique is resolved inline (fixed, or justified out-of-scope in one line). Ground-truthed against the live repos on 2026-05-31. --- @@ -23,7 +23,7 @@ provenance: multi-agent design workflow wf_620b356a-d6e (5 subsystem designs -> │ merge (CodeRabbit status=success, C2) │ then human pushes tag(s): sub-pkg tags first, then vX.Y.Z ┌──────────────────────────────────────────────────────────▼───────────────────────────────────────────┐ - │ TechMatrix-labs/pythinker-code (PUBLIC, source of truth) │ + │ Pythoughts-labs/pythinker-code (PUBLIC, source of truth) │ │ │ │ on tag v* : release-cli ┃ linux-installer ┃ windows-installer ┃ homebrew-tap ┃ docker(P2) ┃ promote │ └───┬──────────────┬──────────────┬───────────────┬───────────────────┬─────────────────────┬───────────┘ @@ -51,7 +51,7 @@ provenance: multi-agent design workflow wf_620b356a-d6e (5 subsystem designs -> ▲ daily cron 04:17 + drift reconcile (backstops) - Nix: nix run github:TechMatrix-labs/pythinker-code (P2: needs apps.default — currently UNVERIFIED; auth=none) + Nix: nix run github:Pythoughts-labs/pythinker-code (P2: needs apps.default — currently UNVERIFIED; auth=none) AUTH EDGE SUMMARY (every cross-repo / privileged write): PyPI/TestPyPI ............ OIDC trusted publishing (no token) [unchanged, GOOD] @@ -146,9 +146,9 @@ pyproject.toml:3 ─(release.py rewrite)→ release PR ─(check_version_tag gat **PATs eliminated:** - `PYTHINKER_HOME_REPO_DISPATCH_TOKEN` → `pythinker-release-bot` (replaces it in **both** `promote-release.yml:168` AND `dispatch-pythinker-home-sync.yml:28`). Delete only after both files migrate + one green cycle. -- `PYTHINKER_CORE_PAGES_TOKEN` → **retired**. Target `PythinkerAI/pythinker-core` is a genuine 404 post-migration (and `TechMatrix-labs/pythinker-core` is also 404 — core exists only as a monorepo sub-package). **Drop the pdoc gh-pages step entirely** (`release-pythinker-core.yml:99-127`, including the PAT-skip swallow at lines 104-105) — Auth Option A. The VitePress docs are the docs surface and nothing user-facing has rendered there since the migration. (Option B is rejected: pdoc runs on core tags but `docs-pages.yml` deploys only on push-to-main, so it would silently deploy nothing.) +- `PYTHINKER_CORE_PAGES_TOKEN` → **retired**. Target `PythinkerAI/pythinker-core` is a genuine 404 post-migration (and `Pythoughts-labs/pythinker-core` is also 404 — core exists only as a monorepo sub-package). **Drop the pdoc gh-pages step entirely** (`release-pythinker-core.yml:99-127`, including the PAT-skip swallow at lines 104-105) — Auth Option A. The VitePress docs are the docs surface and nothing user-facing has rendered there since the migration. (Option B is rejected: pdoc runs on core tags but `docs-pages.yml` deploys only on push-to-main, so it would silently deploy nothing.) -**Residual blast radius (stated honestly):** `contents:write` is the floor for `POST /dispatches` (there is no narrower fine-grained permission). A leaked ~1h `pythinker-release-bot` token could push commits to the private site, not merely dispatch. Mitigated by single-repo install + ~1h TTL + per-run minting. Receiver-side defense: `sync-upstream-products.yml` adds a job-level `if:` gating on `client_payload.source_repo == 'TechMatrix-labs/pythinker-code'` (cron/manual carry no payload → allowed; the sync workflow currently has only `if: failure()` on notify and no payload gate — this is genuinely net-new); payload fields are **never** interpolated into a `run:` shell line (injection vector — the sync derives everything from the live API by repo name). +**Residual blast radius (stated honestly):** `contents:write` is the floor for `POST /dispatches` (there is no narrower fine-grained permission). A leaked ~1h `pythinker-release-bot` token could push commits to the private site, not merely dispatch. Mitigated by single-repo install + ~1h TTL + per-run minting. Receiver-side defense: `sync-upstream-products.yml` adds a job-level `if:` gating on `client_payload.source_repo == 'Pythoughts-labs/pythinker-code'` (cron/manual carry no payload → allowed; the sync workflow currently has only `if: failure()` on notify and no payload gate — this is genuinely net-new); payload fields are **never** interpolated into a `run:` shell line (injection vector — the sync derives everything from the live API by repo name). --- @@ -201,15 +201,15 @@ tag push → PRERELEASE (/latest = last good) | **GitHub Release** | PyInstaller ×5 + installers + .sha256 | repo releases | tag CI | GITHUB_TOKEN | **BLOCKING** | | **Homebrew tap** | `generate-formula.py` polls onedir tarballs | homebrew-pythinker | `homebrew-tap.yml` poll | App tap-publisher | best-effort | | **Website** | sync.ts pulls latest+raw@tag | pythinker.com (Dokploy) | dispatch + cron + reconcile | App release-bot | best-effort | -| **Docker (GHCR)** P2 | `python:3.14-slim` + `pip install pythinker-code==${V}` (reuses PyPI wheel, C3-safe), multi-arch native amd64+arm64, push-by-digest, imagetools stitch, **ancestor-check** before `:latest` (`fetch-depth:0` + refuse-on-unknown-:latest) | `ghcr.io/TechMatrix-labs/pythinker-code` | `push: tags: v*` | GITHUB_TOKEN packages:write (**zero new secrets, best auth fit**) | best-effort | -| **Scoop** P2 | NEW `packages/scoop-bucket/generate-manifest.py` points at the **EXISTING** `pythinker-{v}-x86_64-pc-windows-msvc-onedir.zip` + its `.sha256` (verified produced by `release-pythinker-cli.yml`); `bin: pythinker\pythinker.exe`. Generator polls the **windows zip specifically** (NOT a clone of generate-formula.py's mac/linux NATIVE_TARGETS) | `TechMatrix-labs/scoop-pythinker` (PUBLIC, **org-owned**) `bucket/pythinker-code.json` | `scoop-bucket.yml` poll | App scoop-publisher (**org-owned**) | best-effort | +| **Docker (GHCR)** P2 | `python:3.14-slim` + `pip install pythinker-code==${V}` (reuses PyPI wheel, C3-safe), multi-arch native amd64+arm64, push-by-digest, imagetools stitch, **ancestor-check** before `:latest` (`fetch-depth:0` + refuse-on-unknown-:latest) | `ghcr.io/Pythoughts-labs/pythinker-code` | `push: tags: v*` | GITHUB_TOKEN packages:write (**zero new secrets, best auth fit**) | best-effort | +| **Scoop** P2 | NEW `packages/scoop-bucket/generate-manifest.py` points at the **EXISTING** `pythinker-{v}-x86_64-pc-windows-msvc-onedir.zip` + its `.sha256` (verified produced by `release-pythinker-cli.yml`); `bin: pythinker\pythinker.exe`. Generator polls the **windows zip specifically** (NOT a clone of generate-formula.py's mac/linux NATIVE_TARGETS) | `Pythoughts-labs/scoop-pythinker` (PUBLIC, **org-owned**) `bucket/pythinker-code.json` | `scoop-bucket.yml` poll | App scoop-publisher (**org-owned**) | best-effort | | **Nix** P2 | flake builds via uv2nix with `packages.default = pythinker-code` (`flake.nix:129`) — **but there is NO `apps` stanza** (verified), so `apps.default` + `nix build .#default`/`nix run` CI check is genuine net-new; `nix run github:…` working is **UNVERIFIED** until `apps.default` exists; monthly `update-flake-lock` PR | git repo (no artifact store); version from `pyproject.toml` | flake.lock cron PR | none | build-time CI gate | | **WinGet** P2-late | `wingetcreate update ... --submit` | `microsoft/winget-pkgs` fork | **MANUAL `workflow_dispatch` only** (hard gate) | fine-grained PAT `WINGET_SUBMIT_TOKEN` (isolated; can't be an App for external-repo PRs) | never | | **AUR** | DEFER | — | — | SSH key (re-introduces non-App secret) | — | **Required code change (don't ship supported non-self-updating channels without it):** `src/pythinker_code/ui/shell/update.py` — add a `PYTHINKER_MANAGED=` env read at the top of `_detect_upgrade_command()` (mirrors hermes `HERMES_MANAGED`); Docker/Nix set it and Scoop manifests set it → channel-native upgrade hint. **WinGet does not set `PYTHINKER_MANAGED`** because its workflow submits installer metadata only and the WinGet manifest cannot inject a process env var, so it uses the generic native-updater path. **Brew must NOT set `PYTHINKER_MANAGED`** (keep its existing path-sniff so behavior is unchanged); **mandatory regression test** that brew still maps to `['brew','upgrade','pythinker-code']` (the `.pythinker-native` marker means brew also trips `is_native_build()`; precedence is load-bearing). This change ships in P1 as prep so P2 channels are not released non-self-updating where markers are supported. -**C4 for new channels:** README install snippets MUST be **version-less** (`scoop install pythinker-code`, `docker run ghcr.io/techmatrix-labs/pythinker-code`, `nix run github:TechMatrix-labs/pythinker-code`) so they never enter the F3 sprawl set. +**C4 for new channels:** README install snippets MUST be **version-less** (`scoop install pythinker-code`, `docker run ghcr.io/pythoughts-labs/pythinker-code`, `nix run github:Pythoughts-labs/pythinker-code`) so they never enter the F3 sprawl set. **Recommended adoption order:** **Docker (GHCR)** → **Scoop** → **Nix polish** → WinGet (manual) → defer AUR. Rationale: Docker = highest reach-per-fragility (OIDC auth, reuses wheel, self-protecting ancestor-check); Scoop = closes the Windows gap as a mechanical clone of the trusted tap pattern; Nix needs the `apps.default` net-new but the package build already works. @@ -245,7 +245,7 @@ release → promote → dispatch → sync-upstream-products.ts writes files → - **Code repo (KEEP — they are dispatch triggers):** `scripts/install.ps1` + `scripts/install-native.sh` are the **source** scripts; `dispatch-pythinker-home-sync.yml` watches them (`paths:` lines 16-17). Do **not** delete these. - **Site repo (`git rm` the dead mirrors):** the canonical served pair is **`public/install.sh` + `public/install.ps1`** (the sole Vite-served dir, confirmed kept). The 3 dead, git-tracked mirrors — `scripts/install.ps1`, `web/public/install.ps1`, `docs/public/install.ps1` (all verified tracked + byte-identical) — get `git rm`'d and dropped from `installMirrors[].targetPaths`. -**0.24.0 root-cause fix (Mode B) — re-scoped to what is actually net-new (critique item 4):** the per-product `owner`/`repo` config block **already exists** in `sync-upstream-products.ts` (lines 82-83 for the AI product `owner:"mohamed-elkholy95", repo:"Pythinker-ai"`; lines 98-99 for `TechMatrix-labs/pythinker-code`). Do **NOT** "create the config block" (overstated) and do **NOT** collapse to a single `ORG` const (would break the AI product, owner `mohamed-elkholy95`, a different org from code's `TechMatrix-labs`). The real residual risk is two things the config block does not cover: +**0.24.0 root-cause fix (Mode B) — re-scoped to what is actually net-new (critique item 4):** the per-product `owner`/`repo` config block **already exists** in `sync-upstream-products.ts` (lines 82-83 for the AI product `owner:"mohamed-elkholy95", repo:"Pythinker-ai"`; lines 98-99 for `Pythoughts-labs/pythinker-code`). Do **NOT** "create the config block" (overstated) and do **NOT** collapse to a single `ORG` const (would break the AI product, owner `mohamed-elkholy95`, a different org from code's `Pythoughts-labs`). The real residual risk is two things the config block does not cover: 1. A **hardcoded literal at line 366**: `readme.replaceAll("github.com/mohamed-elkholy95/Pythinker/releases", "github.com/mohamed-elkholy95/Pythinker-ai/releases")` — bypasses the config block. **Fix:** derive both sides from the product's `owner`/`repo` config, or drop the rewrite if it's a migration vestige. 2. **No assertion** that each product's `owner`/`repo`/derived URLs/`brewCommand` agree. **Fix:** add a lockstep/typecheck assertion over the existing config so a stale literal fails loudly. diff --git a/examples/feedback-worker/wrangler.jsonc b/examples/feedback-worker/wrangler.jsonc index 513e20d6..39880062 100644 --- a/examples/feedback-worker/wrangler.jsonc +++ b/examples/feedback-worker/wrangler.jsonc @@ -10,7 +10,7 @@ } ], "vars": { - "GITHUB_REPO": "TechMatrix-labs/pythinker-code", + "GITHUB_REPO": "Pythoughts-labs/pythinker-code", "GITHUB_LABELS": "feedback,pythinker-cli", "SUPPORT_EMAIL": "support@pythinker.com", "FROM_EMAIL": "Pythinker Feedback " diff --git a/packages/homebrew-tap/README.md b/packages/homebrew-tap/README.md index 22a77260..3e420c3e 100644 --- a/packages/homebrew-tap/README.md +++ b/packages/homebrew-tap/README.md @@ -11,7 +11,7 @@ auto-regenerates the formula and pushes it to the tap repo. ## End-user install (post-setup) ```sh -brew install TechMatrix-labs/pythinker/pythinker-code +brew install Pythoughts-labs/pythinker/pythinker-code ``` Works on macOS (Intel + Apple Silicon) and Linux (x86_64 + aarch64) — same @@ -32,10 +32,10 @@ matches Anthropic's published advice for Claude Code's Homebrew cask.) 1. **Create the tap repo.** Create a new empty GitHub repo named `homebrew-pythinker` under your account. The `homebrew-` prefix is required by Homebrew; the part after the dash becomes the tap name - (so `brew tap TechMatrix-labs/pythinker`). + (so `brew tap Pythoughts-labs/pythinker`). ```sh - gh repo create TechMatrix-labs/homebrew-pythinker \ + gh repo create Pythoughts-labs/homebrew-pythinker \ --public \ --description "Homebrew tap for Pythinker Code" \ --enable-issues=false @@ -56,7 +56,7 @@ That's it. The next `v*.*.*` tag push to `Pythinker-Code` will: 1. Wait for native GitHub Release tarballs to be attached. 2. Render `Formula/pythinker-code.rb` from `pythinker-code.rb.tmpl` with the release URLs and SHA-256 digests. -3. Commit + push the formula to `TechMatrix-labs/homebrew-pythinker` on +3. Commit + push the formula to `Pythoughts-labs/homebrew-pythinker` on `main` (creating the inaugural commit on first run). 4. Brew users get the new release via `brew upgrade pythinker-code`. diff --git a/packages/homebrew-tap/generate-formula.py b/packages/homebrew-tap/generate-formula.py index 5d6fabe0..566a8547 100644 --- a/packages/homebrew-tap/generate-formula.py +++ b/packages/homebrew-tap/generate-formula.py @@ -24,7 +24,7 @@ from pathlib import Path from typing import Any -GITHUB_REPO = "TechMatrix-labs/pythinker-code" +GITHUB_REPO = "Pythoughts-labs/pythinker-code" GITHUB_RELEASE_API = f"https://api.github.com/repos/{GITHUB_REPO}/releases/tags/v{{version}}" diff --git a/packages/linux-installer/README.md b/packages/linux-installer/README.md index db9c3665..c245d7d5 100644 --- a/packages/linux-installer/README.md +++ b/packages/linux-installer/README.md @@ -8,19 +8,19 @@ End-user install from the current GitHub Release: ```sh # Debian / Ubuntu -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code_0.27.0_amd64.deb -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code_0.27.0_amd64.deb.sha256 -sha256sum -c pythinker-code_0.27.0_amd64.deb.sha256 -sudo dpkg -i pythinker-code_0.27.0_amd64.deb +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code_0.28.0_amd64.deb +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code_0.28.0_amd64.deb.sha256 +sha256sum -c pythinker-code_0.28.0_amd64.deb.sha256 +sudo dpkg -i pythinker-code_0.28.0_amd64.deb sudo apt-get install -f # only needed if dependencies fail to resolve # Fedora / RHEL / openSUSE -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.x86_64.rpm -curl -LO https://github.com/TechMatrix-labs/pythinker-code/releases/download/v0.27.0/pythinker-code-0.27.0.x86_64.rpm.sha256 -sha256sum -c pythinker-code-0.27.0.x86_64.rpm.sha256 -sudo dnf install ./pythinker-code-0.27.0.x86_64.rpm +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.x86_64.rpm +curl -LO https://github.com/Pythoughts-labs/pythinker-code/releases/download/v0.28.0/pythinker-code-0.28.0.x86_64.rpm.sha256 +sha256sum -c pythinker-code-0.28.0.x86_64.rpm.sha256 +sudo dnf install ./pythinker-code-0.28.0.x86_64.rpm # or, on openSUSE: -sudo zypper install ./pythinker-code-0.27.0.x86_64.rpm +sudo zypper install ./pythinker-code-0.28.0.x86_64.rpm ``` The package drops a single executable at `/usr/bin/pythinker` and a license @@ -41,8 +41,8 @@ bash packages/linux-installer/build.sh 0.27.0 Outputs to `dist/`: -- `pythinker-code_0.27.0_amd64.deb` -- `pythinker-code-0.27.0.x86_64.rpm` +- `pythinker-code_0.28.0_amd64.deb` +- `pythinker-code-0.28.0.x86_64.rpm` The portable tarball used by `scripts/install-native.sh` is published by the existing `release-pythinker-cli.yml` workflow under the cargo-dist diff --git a/packages/linux-installer/build.sh b/packages/linux-installer/build.sh index 2aac2cbb..fc367263 100755 --- a/packages/linux-installer/build.sh +++ b/packages/linux-installer/build.sh @@ -87,7 +87,7 @@ FPM_COMMON=( -v "$VERSION" --license "Apache-2.0" --maintainer "Pythinker " - --url "https://github.com/TechMatrix-labs/pythinker-code" + --url "https://github.com/Pythoughts-labs/pythinker-code" --description "Pythinker Code: terminal-native review-first AI engineering agent." --vendor "Pythinker" ) diff --git a/packages/pythinker-core/CHANGELOG.md b/packages/pythinker-core/CHANGELOG.md index 0df11236..70c8353b 100644 --- a/packages/pythinker-core/CHANGELOG.md +++ b/packages/pythinker-core/CHANGELOG.md @@ -16,7 +16,7 @@ pythinker-core 1.1.0 depends on mcp<1.17 and >=1 Strict-interleaved reasoning replay for Kimi K2.x and DeepSeek, plus the SDK 0.101 anthropic compat fix. -- **`contrib.chat_provider.openai_legacy._convert_message`** — for strict-interleaved providers (`kimi-k2*`, `deepseek*`) now **always** emits `reasoning_content` on assistant turns, even when no `ThinkPart` was captured. Falls back to the assistant text, then to `"[reasoning unavailable]"` so Kimi-style "thinking is enabled but reasoning_content is missing in assistant tool call message at index N" rejections no longer trip multi-step tool flows. Fixes pythinker-code [#37](https://github.com/TechMatrix-labs/pythinker-code/issues/37). +- **`contrib.chat_provider.openai_legacy._convert_message`** — for strict-interleaved providers (`kimi-k2*`, `deepseek*`) now **always** emits `reasoning_content` on assistant turns, even when no `ThinkPart` was captured. Falls back to the assistant text, then to `"[reasoning unavailable]"` so Kimi-style "thinking is enabled but reasoning_content is missing in assistant tool call message at index N" rejections no longer trip multi-step tool flows. Fixes pythinker-code [#37](https://github.com/Pythoughts-labs/pythinker-code/issues/37). - **`chat_provider.pythinker`** — same `reasoning_content` replay guarantee on the native pythinker provider for parity. - **`contrib.chat_provider.anthropic`** — added `case _:` fallbacks at the prompt-cache-injection site and the streaming content-block start site so the six new tool-result block types in anthropic SDK 0.101 (`web_fetch_tool_result`, `code_execution_tool_result`, `bash_code_execution_tool_result`, `text_editor_code_execution_tool_result`, `tool_search_tool_result`, `container_upload`) don't trip `pyright`'s exhaustive-match check. - No public API changes; minor patch contract — drop-in upgrade. diff --git a/packages/pythinker-core/pyproject.toml b/packages/pythinker-core/pyproject.toml index 55b5f76b..38175ca1 100644 --- a/packages/pythinker-core/pyproject.toml +++ b/packages/pythinker-core/pyproject.toml @@ -38,10 +38,10 @@ contrib = [ ] [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" -Issues = "https://github.com/TechMatrix-labs/pythinker-code/issues" -Changelog = "https://github.com/TechMatrix-labs/pythinker-code/blob/main/packages/pythinker-core/CHANGELOG.md" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" +Issues = "https://github.com/Pythoughts-labs/pythinker-code/issues" +Changelog = "https://github.com/Pythoughts-labs/pythinker-code/blob/main/packages/pythinker-core/CHANGELOG.md" [dependency-groups] dev = [ diff --git a/packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_legacy.py b/packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_legacy.py index dec0ee29..35c612c8 100644 --- a/packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_legacy.py +++ b/packages/pythinker-core/src/pythinker_core/contrib/chat_provider/openai_legacy.py @@ -130,7 +130,7 @@ async def generate( # Auto-enable reasoning_effort when the history contains ThinkPart but reasoning # was not explicitly configured. This prevents server validation errors from APIs # (e.g. One API) that require reasoning_effort when messages contain reasoning_content. - # See: https://github.com/TechMatrix-labs/pythinker-code/issues/1616 + # See: https://github.com/Pythoughts-labs/pythinker-code/issues/1616 if isinstance(reasoning_effort, Omit) and self._reasoning_key: has_think_part = any( isinstance(part, ThinkPart) for message in history for part in message.content diff --git a/packages/pythinker-core/tests/api_snapshot_tests/test_openai_legacy.py b/packages/pythinker-core/tests/api_snapshot_tests/test_openai_legacy.py index 495968e9..c5868625 100644 --- a/packages/pythinker-core/tests/api_snapshot_tests/test_openai_legacy.py +++ b/packages/pythinker-core/tests/api_snapshot_tests/test_openai_legacy.py @@ -312,7 +312,7 @@ async def test_openai_legacy_auto_reasoning_effort_when_history_has_think_part() """When reasoning_effort is not set but history contains ThinkPart and reasoning_key is configured, reasoning_effort should be auto-set to avoid server validation errors. - Reproduces: https://github.com/TechMatrix-labs/pythinker-code/issues/1616 + Reproduces: https://github.com/Pythoughts-labs/pythinker-code/issues/1616 """ with respx.mock(base_url="https://api.openai.com") as mock: mock.post("/v1/chat/completions").mock( diff --git a/packages/pythinker-host/pyproject.toml b/packages/pythinker-host/pyproject.toml index be282a3b..a2bafd8a 100644 --- a/packages/pythinker-host/pyproject.toml +++ b/packages/pythinker-host/pyproject.toml @@ -26,10 +26,10 @@ dependencies = [ ] [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" -Issues = "https://github.com/TechMatrix-labs/pythinker-code/issues" -Changelog = "https://github.com/TechMatrix-labs/pythinker-code/blob/main/packages/pythinker-host/CHANGELOG.md" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" +Issues = "https://github.com/Pythoughts-labs/pythinker-code/issues" +Changelog = "https://github.com/Pythoughts-labs/pythinker-code/blob/main/packages/pythinker-host/CHANGELOG.md" [dependency-groups] dev = [ diff --git a/packages/pythinker-review/pyproject.toml b/packages/pythinker-review/pyproject.toml index d294612c..0d55ddc8 100644 --- a/packages/pythinker-review/pyproject.toml +++ b/packages/pythinker-review/pyproject.toml @@ -33,8 +33,8 @@ pythinker-debug = "pythinker_review.cli.debug:app" pythinker-security-scan = "pythinker_review.cli.security_scan:app" [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" [dependency-groups] dev = [ diff --git a/packages/pythinker-review/src/pythinker_review/output/sarif.py b/packages/pythinker-review/src/pythinker_review/output/sarif.py index 150feaf0..c55bdc3c 100644 --- a/packages/pythinker-review/src/pythinker_review/output/sarif.py +++ b/packages/pythinker-review/src/pythinker_review/output/sarif.py @@ -68,7 +68,7 @@ def render_sarif(meta: RunMeta, findings: list[Finding]) -> str: "tool": { "driver": { "name": "pythinker-review", - "informationUri": "https://github.com/TechMatrix-labs/pythinker-code", + "informationUri": "https://github.com/Pythoughts-labs/pythinker-code", "rules": list(rules_seen.values()), } }, diff --git a/packages/scoop-bucket/generate-manifest.py b/packages/scoop-bucket/generate-manifest.py index b2d3a4c1..3c186c56 100644 --- a/packages/scoop-bucket/generate-manifest.py +++ b/packages/scoop-bucket/generate-manifest.py @@ -25,7 +25,7 @@ from pathlib import Path from typing import Any -GITHUB_REPO = "TechMatrix-labs/pythinker-code" +GITHUB_REPO = "Pythoughts-labs/pythinker-code" GITHUB_RELEASE_API = f"https://api.github.com/repos/{GITHUB_REPO}/releases/tags/v{{version}}" diff --git a/packages/scoop-bucket/pythinker-code.json.tmpl b/packages/scoop-bucket/pythinker-code.json.tmpl index 5f544b33..0ba1e767 100644 --- a/packages/scoop-bucket/pythinker-code.json.tmpl +++ b/packages/scoop-bucket/pythinker-code.json.tmpl @@ -14,12 +14,12 @@ "PYTHINKER_MANAGED": "scoop" }, "checkver": { - "github": "https://github.com/TechMatrix-labs/pythinker-code" + "github": "https://github.com/Pythoughts-labs/pythinker-code" }, "autoupdate": { "architecture": { "64bit": { - "url": "https://github.com/TechMatrix-labs/pythinker-code/releases/download/v$version/pythinker-$version-x86_64-pc-windows-msvc-onedir.zip" + "url": "https://github.com/Pythoughts-labs/pythinker-code/releases/download/v$version/pythinker-$version-x86_64-pc-windows-msvc-onedir.zip" } }, "hash": { diff --git a/packages/windows-installer/installer.iss b/packages/windows-installer/installer.iss index 83aa3224..4b1473ce 100644 --- a/packages/windows-installer/installer.iss +++ b/packages/windows-installer/installer.iss @@ -11,8 +11,8 @@ AppName=Pythinker Code AppVersion={#AppVersion} AppPublisher=Pythinker AppPublisherURL=https://pythinker.com -AppSupportURL=https://github.com/TechMatrix-labs/pythinker-code/issues -AppUpdatesURL=https://github.com/TechMatrix-labs/pythinker-code/releases +AppSupportURL=https://github.com/Pythoughts-labs/pythinker-code/issues +AppUpdatesURL=https://github.com/Pythoughts-labs/pythinker-code/releases DefaultDirName={localappdata}\Programs\Pythinker DefaultGroupName=Pythinker DisableProgramGroupPage=yes diff --git a/pyproject.toml b/pyproject.toml index 523905fd..1fe0c359 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "pythinker-code" -version = "0.27.0" +version = "0.28.0" description = "Pythinker Code is your next CLI agent." readme = "README.md" requires-python = ">=3.12" @@ -102,11 +102,11 @@ pythinker = "pythinker_code.__main__:main" pythinker-code = "pythinker_code.__main__:main" [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" -Issues = "https://github.com/TechMatrix-labs/pythinker-code/issues" -Changelog = "https://github.com/TechMatrix-labs/pythinker-code/blob/main/CHANGELOG.md" -Documentation = "https://github.com/TechMatrix-labs/pythinker-code#readme" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" +Issues = "https://github.com/Pythoughts-labs/pythinker-code/issues" +Changelog = "https://github.com/Pythoughts-labs/pythinker-code/blob/main/CHANGELOG.md" +Documentation = "https://github.com/Pythoughts-labs/pythinker-code#readme" [tool.ruff] line-length = 100 diff --git a/scripts/install-native.sh b/scripts/install-native.sh index b918f6ba..88da02b5 100755 --- a/scripts/install-native.sh +++ b/scripts/install-native.sh @@ -38,7 +38,7 @@ while [[ $# -gt 0 ]]; do esac done -REPO="TechMatrix-labs/pythinker-code" +REPO="Pythoughts-labs/pythinker-code" if [ -t 1 ] && [ -z "$NO_COLOR" ] && [ "${TERM:-}" != "dumb" ]; then NAVY=$'\033[38;5;24m'; FACE=$'\033[38;5;255m' diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 2f5be920..146ded20 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -14,7 +14,7 @@ $ErrorActionPreference = "Stop" try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {} try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -$Repo = "TechMatrix-labs/pythinker-code" +$Repo = "Pythoughts-labs/pythinker-code" $Version = $env:PYTHINKER_VERSION $NoColor = $env:NO_COLOR diff --git a/sdks/pythinker-sdk/pyproject.toml b/sdks/pythinker-sdk/pyproject.toml index fcd270e4..2e45e8dc 100644 --- a/sdks/pythinker-sdk/pyproject.toml +++ b/sdks/pythinker-sdk/pyproject.toml @@ -22,10 +22,10 @@ classifiers = [ dependencies = ["pythinker-core==1.1.1", "mcp>=1.23,<2", "httpx>=0.28.1"] [project.urls] -Homepage = "https://github.com/TechMatrix-labs/pythinker-code" -Repository = "https://github.com/TechMatrix-labs/pythinker-code" -Issues = "https://github.com/TechMatrix-labs/pythinker-code/issues" -Changelog = "https://github.com/TechMatrix-labs/pythinker-code/blob/main/sdks/pythinker-sdk/CHANGELOG.md" +Homepage = "https://github.com/Pythoughts-labs/pythinker-code" +Repository = "https://github.com/Pythoughts-labs/pythinker-code" +Issues = "https://github.com/Pythoughts-labs/pythinker-code/issues" +Changelog = "https://github.com/Pythoughts-labs/pythinker-code/blob/main/sdks/pythinker-sdk/CHANGELOG.md" [dependency-groups] dev = [ diff --git a/src/pythinker_code/__main__.py b/src/pythinker_code/__main__.py index 115c3ffc..adf054f4 100644 --- a/src/pythinker_code/__main__.py +++ b/src/pythinker_code/__main__.py @@ -54,8 +54,8 @@ vis Run Pythinker Agent Tracing Visualizer. web Run Pythinker CLI web interface. -Documentation: https://techmatrix-labs.github.io/pythinker-code/ -LLM friendly version: https://techmatrix-labs.github.io/pythinker-code/llms.txt +Documentation: https://pythoughts-labs.github.io/pythinker-code/ +LLM friendly version: https://pythoughts-labs.github.io/pythinker-code/llms.txt """ diff --git a/src/pythinker_code/cli/__init__.py b/src/pythinker_code/cli/__init__.py index b72322a1..23bf1371 100644 --- a/src/pythinker_code/cli/__init__.py +++ b/src/pythinker_code/cli/__init__.py @@ -157,8 +157,8 @@ def logout_openrouter(*args: Any, **kwargs: Any) -> Any: cli = typer.Typer( cls=LazySubcommandGroup, epilog="""\b\ -Documentation: https://techmatrix-labs.github.io/pythinker-code/\n -LLM friendly version: https://techmatrix-labs.github.io/pythinker-code/llms.txt""", +Documentation: https://pythoughts-labs.github.io/pythinker-code/\n +LLM friendly version: https://pythoughts-labs.github.io/pythinker-code/llms.txt""", add_completion=False, context_settings={"help_option_names": ["-h", "--help"]}, help="Pythinker, your next CLI agent.", diff --git a/src/pythinker_code/feedback_repo.py b/src/pythinker_code/feedback_repo.py index 24696af1..bb9a9779 100644 --- a/src/pythinker_code/feedback_repo.py +++ b/src/pythinker_code/feedback_repo.py @@ -1,11 +1,12 @@ from __future__ import annotations -DEFAULT_FEEDBACK_GITHUB_REPO = "TechMatrix-labs/pythinker-code" +DEFAULT_FEEDBACK_GITHUB_REPO = "Pythoughts-labs/pythinker-code" _LEGACY_FEEDBACK_GITHUB_OWNER = "mohamed-elkholy95" _LEGACY_DEFAULT_FEEDBACK_GITHUB_REPOS = { _LEGACY_FEEDBACK_GITHUB_OWNER + "/Pythinker-Code", _LEGACY_FEEDBACK_GITHUB_OWNER + "/pythinker-code", + "TechMatrix-labs/pythinker-code", } _LEGACY_DEFAULT_FEEDBACK_GITHUB_REPOS_LOWER = { repo.lower() for repo in _LEGACY_DEFAULT_FEEDBACK_GITHUB_REPOS diff --git a/src/pythinker_code/native.py b/src/pythinker_code/native.py index 3b1134d6..b8d9ec94 100644 --- a/src/pythinker_code/native.py +++ b/src/pythinker_code/native.py @@ -13,7 +13,7 @@ import sys from pathlib import Path -GITHUB_REPO = "TechMatrix-labs/pythinker-code" +GITHUB_REPO = "Pythoughts-labs/pythinker-code" SENTINEL_FILENAME = ".pythinker-native" diff --git a/src/pythinker_code/skills/pythinker-code-help/SKILL.md b/src/pythinker_code/skills/pythinker-code-help/SKILL.md index 16a76011..24e66102 100644 --- a/src/pythinker_code/skills/pythinker-code-help/SKILL.md +++ b/src/pythinker_code/skills/pythinker-code-help/SKILL.md @@ -15,17 +15,17 @@ Help users with Pythinker CLI questions by consulting documentation and source c ## Documentation -Base URL: `https://techmatrix-labs.github.io/pythinker-code/` +Base URL: `https://pythoughts-labs.github.io/pythinker-code/` Fetch documentation index to find relevant pages: ``` -https://techmatrix-labs.github.io/pythinker-code/llms.txt +https://pythoughts-labs.github.io/pythinker-code/llms.txt ``` ### Page URL Pattern -- Pages: `https://techmatrix-labs.github.io/pythinker-code/en/...` +- Pages: `https://pythoughts-labs.github.io/pythinker-code/en/...` ### Topic Mapping @@ -45,7 +45,7 @@ https://techmatrix-labs.github.io/pythinker-code/llms.txt ## Source Code -Repository: `https://github.com/TechMatrix-labs/pythinker-code` +Repository: `https://github.com/Pythoughts-labs/pythinker-code` When to read source: diff --git a/src/pythinker_code/ui/shell/slash.py b/src/pythinker_code/ui/shell/slash.py index f06e0a00..ed5bec9b 100644 --- a/src/pythinker_code/ui/shell/slash.py +++ b/src/pythinker_code/ui/shell/slash.py @@ -606,7 +606,7 @@ def _fallback_to_issue(payload: dict[str, Any] | None = None) -> None: issue_url = ( build_feedback_issue_url(payload, soul.runtime.config.feedback.github_repo) if payload is not None and soul is not None - else "https://github.com/TechMatrix-labs/pythinker-code/issues/new/choose" + else "https://github.com/Pythoughts-labs/pythinker-code/issues/new/choose" ) if open_url_in_browser(issue_url): console.print(f"[{_t_fb.success}]Opening GitHub feedback in your browser...[/]") @@ -733,7 +733,7 @@ async def report_error(app: Shell, args: str): _t_re = _get_tok_re() - ISSUE_URL = "https://github.com/TechMatrix-labs/pythinker-code/issues" + ISSUE_URL = "https://github.com/Pythoughts-labs/pythinker-code/issues" def _fallback_to_issues() -> None: if not open_url_in_browser(ISSUE_URL): diff --git a/src/pythinker_code/ui/shell/update.py b/src/pythinker_code/ui/shell/update.py index 71a1f0ba..af9caf17 100644 --- a/src/pythinker_code/ui/shell/update.py +++ b/src/pythinker_code/ui/shell/update.py @@ -36,10 +36,10 @@ from pythinker_code.utils.logging import logger from pythinker_code.utils.subprocess_env import get_clean_env -CHANGELOG_URL_EN = "https://github.com/TechMatrix-labs/pythinker-code/blob/main/CHANGELOG.md" +CHANGELOG_URL_EN = "https://github.com/Pythoughts-labs/pythinker-code/blob/main/CHANGELOG.md" PYPI_VERSION_URL = "https://pypi.org/pypi/pythinker-code/{version}/json" HOMEBREW_FORMULA_URL = ( - "https://raw.githubusercontent.com/TechMatrix-labs/homebrew-pythinker/" + "https://raw.githubusercontent.com/Pythoughts-labs/homebrew-pythinker/" "main/Formula/pythinker-code.rb" ) @@ -1293,7 +1293,7 @@ def _print(message: str) -> None: _print( f"[{_t.warning}]Auto-update disabled. " "Download the new installer manually from " - "https://github.com/TechMatrix-labs/pythinker-code/releases/latest[/]" + "https://github.com/Pythoughts-labs/pythinker-code/releases/latest[/]" ) return UpdateResult.UPDATE_AVAILABLE if native_result is UpdateResult.FAILED: diff --git a/tasks/todo.md b/tasks/todo.md index e9ff38a6..214918d0 100644 --- a/tasks/todo.md +++ b/tasks/todo.md @@ -421,7 +421,7 @@ To do later, in a separate PR after we know 1.1.0 is healthy: ## Out of scope - Renaming `pythinker-core`, `pythinker-host`, `pythinker-sdk` packages (their names are already fine) -- Renaming the GitHub repo itself (`TechMatrix-labs/pythinker-code`) — name is already correct +- Renaming the GitHub repo itself (`Pythoughts-labs/pythinker-code`) — name is already correct - Breaking the public Python API (we're keeping `import pythinker_code` ergonomic; the *internal* import path changes but the module's public API surface stays the same) - Migrating user data directories (the rename creates a new path, but no existing user data exists yet — by user statement) diff --git a/tests/core/test_config.py b/tests/core/test_config.py index 55d56cf4..d14ad016 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -74,7 +74,7 @@ def test_default_config_dump(): "api_key": None, "custom_headers": None, "github_client_id": "", - "github_repo": "TechMatrix-labs/pythinker-code", + "github_repo": "Pythoughts-labs/pythinker-code", }, "hooks": [], "merge_all_available_skills": True, @@ -100,7 +100,13 @@ def test_load_config_migrates_legacy_feedback_repo_default(): old_owner = "mohamed-elkholy95" config = load_config_from_string(f'[feedback]\ngithub_repo = "{old_owner}/Pythinker-Code"\n') - assert config.feedback.github_repo == "TechMatrix-labs/pythinker-code" + assert config.feedback.github_repo == "Pythoughts-labs/pythinker-code" + + +def test_load_config_migrates_legacy_org_feedback_repo_default(): + config = load_config_from_string('[feedback]\ngithub_repo = "TechMatrix-labs/pythinker-code"\n') + + assert config.feedback.github_repo == "Pythoughts-labs/pythinker-code" def test_agent_execution_profile_autonomous_sets_autonomy_defaults(): diff --git a/tests/core/test_simple_compaction.py b/tests/core/test_simple_compaction.py index e0fe3f6a..37176150 100644 --- a/tests/core/test_simple_compaction.py +++ b/tests/core/test_simple_compaction.py @@ -221,8 +221,8 @@ def test_prepare_only_keeps_text_parts_in_compaction(): Non-text parts (media, think, etc.) are filtered out because the compaction API endpoint only supports text content. - Fixes: https://github.com/TechMatrix-labs/pythinker-code/issues/1395 - Fixes: https://github.com/TechMatrix-labs/pythinker-code/issues/1390 + Fixes: https://github.com/Pythoughts-labs/pythinker-code/issues/1395 + Fixes: https://github.com/Pythoughts-labs/pythinker-code/issues/1390 """ messages = [ Message( diff --git a/tests/test_installation_docs.py b/tests/test_installation_docs.py index 0f43ee27..e0f3ef4b 100644 --- a/tests/test_installation_docs.py +++ b/tests/test_installation_docs.py @@ -24,7 +24,7 @@ def test_windows_readme_documents_powershell_one_liner() -> None: assert "irm https://pythinker.com/install.ps1 \\| iex" in readme assert ( - "raw.githubusercontent.com/TechMatrix-labs/pythinker-code/main/scripts/install.ps1" + "raw.githubusercontent.com/Pythoughts-labs/pythinker-code/main/scripts/install.ps1" not in readme ) assert "-File $installer" not in readme @@ -38,7 +38,7 @@ def test_getting_started_uses_canonical_native_installer_url() -> None: assert "curl -fsSL https://pythinker.com/install.sh | bash" in guide assert "irm https://pythinker.com/install.ps1 | iex" in guide assert ( - "https://raw.githubusercontent.com/TechMatrix-labs/pythinker-code/main/scripts/install.ps1" + "https://raw.githubusercontent.com/Pythoughts-labs/pythinker-code/main/scripts/install.ps1" ) not in guide @@ -62,7 +62,7 @@ def test_readme_downloads_rpm_before_local_install() -> None: rpm = f"pythinker-code-{version}.x86_64.rpm" checksum = f"{rpm}.sha256" - release_url = f"https://github.com/TechMatrix-labs/pythinker-code/releases/download/v{version}" + release_url = f"https://github.com/Pythoughts-labs/pythinker-code/releases/download/v{version}" assert f"curl -LO {release_url}/{rpm}" in readme assert f"curl -LO {release_url}/{checksum}" in readme diff --git a/tests/test_native.py b/tests/test_native.py index 961efcfa..129a960a 100644 --- a/tests/test_native.py +++ b/tests/test_native.py @@ -55,7 +55,7 @@ def test_is_native_build_true_when_sentinel_present_without_frozen_flag(tmp_path def test_native_installer_release_url_latest(): url = native.native_installer_release_url(channel="latest") - assert url == ("https://api.github.com/repos/TechMatrix-labs/pythinker-code/releases/latest") + assert url == ("https://api.github.com/repos/Pythoughts-labs/pythinker-code/releases/latest") def test_native_installer_release_url_stable(): diff --git a/tests/test_release_update_pipeline.py b/tests/test_release_update_pipeline.py index d6853b4b..67622be7 100644 --- a/tests/test_release_update_pipeline.py +++ b/tests/test_release_update_pipeline.py @@ -122,7 +122,7 @@ def test_release_asset_wait_covers_all_updater_channels() -> None: "pythinker-${version}-aarch64-apple-darwin-onedir.tar.gz.sha256", "pythinker-${version}-x86_64-apple-darwin-onedir.tar.gz.sha256", "https://pypi.org/pypi/pythinker-code/${version}/json", - "raw.githubusercontent.com/TechMatrix-labs/homebrew-pythinker", + "raw.githubusercontent.com/Pythoughts-labs/homebrew-pythinker", 'version \\"${version}\\"', ): assert expected_readiness_marker in promote_workflow diff --git a/tests/ui_and_conv/test_shell_feedback_slash.py b/tests/ui_and_conv/test_shell_feedback_slash.py index 1433a609..ec8a98ac 100644 --- a/tests/ui_and_conv/test_shell_feedback_slash.py +++ b/tests/ui_and_conv/test_shell_feedback_slash.py @@ -50,7 +50,7 @@ async def test_opens_new_issue_url_when_no_soul(self, monkeypatch) -> None: open_mock.assert_called_once() url = open_mock.call_args.args[0] - assert "TechMatrix-labs/pythinker-code" in url + assert "Pythoughts-labs/pythinker-code" in url assert "new" in url async def test_prints_success_when_browser_opens(self, monkeypatch) -> None: @@ -75,7 +75,7 @@ async def test_prints_url_when_browser_fails(self, monkeypatch) -> None: await _run_feedback(Mock(), "ux confusing prompt") output = " ".join(str(c) for c in print_mock.call_args_list) - assert "TechMatrix-labs/pythinker-code" in output + assert "Pythoughts-labs/pythinker-code" in output async def test_invalid_args_without_soul_still_offer_github_fallback(self, monkeypatch) -> None: open_mock = Mock(return_value=True) @@ -146,7 +146,7 @@ async def test_submits_structured_payload(self, tmp_path: Path, monkeypatch) -> soul.runtime.session.subagents_dir = tmp_path / "subagents" soul.runtime.session.subagents_dir.mkdir() soul.runtime.role = "root" - soul.runtime.config.feedback.github_repo = "TechMatrix-labs/pythinker-code" + soul.runtime.config.feedback.github_repo = "Pythoughts-labs/pythinker-code" soul.name = "default" soul.context.history = [ Message(role="user", content=[TextPart(text="please fix this")]), @@ -200,7 +200,7 @@ async def test_prints_follow_up_issue_url_when_endpoint_returns_no_link( soul = Mock(spec=PythinkerSoul) soul.runtime.session.id = "sess-123" - soul.runtime.config.feedback.github_repo = "TechMatrix-labs/pythinker-code" + soul.runtime.config.feedback.github_repo = "Pythoughts-labs/pythinker-code" app = Mock() app.soul = soul payload = { @@ -225,7 +225,7 @@ async def test_prints_follow_up_issue_url_when_endpoint_returns_no_link( output = " ".join(str(c) for c in print_mock.call_args_list) assert "No report link was returned" in output - assert "github.com/TechMatrix-labs/pythinker-code" in output + assert "github.com/Pythoughts-labs/pythinker-code" in output async def test_prompts_before_submitting_by_default(self, monkeypatch) -> None: from pythinker_code.soul.pythinkersoul import PythinkerSoul @@ -302,7 +302,7 @@ def test_feedback_issue_url_migrates_legacy_default_repo(self) -> None: url = build_feedback_issue_url(payload, old_owner + "/Pythinker-Code") - assert "github.com/TechMatrix-labs/pythinker-code/issues/new" in url + assert "github.com/Pythoughts-labs/pythinker-code/issues/new" in url assert old_owner not in url def test_feedback_issue_url_uses_compact_body_for_large_payload(self) -> None: diff --git a/uv.lock b/uv.lock index 6cfcd13a..3c4249ba 100644 --- a/uv.lock +++ b/uv.lock @@ -2402,7 +2402,7 @@ wheels = [ [[package]] name = "pythinker-code" -version = "0.27.0" +version = "0.28.0" source = { editable = "." } dependencies = [ { name = "agent-client-protocol" }, diff --git a/web/public/install.ps1 b/web/public/install.ps1 index 2f5be920..146ded20 100644 --- a/web/public/install.ps1 +++ b/web/public/install.ps1 @@ -14,7 +14,7 @@ $ErrorActionPreference = "Stop" try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {} try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} -$Repo = "TechMatrix-labs/pythinker-code" +$Repo = "Pythoughts-labs/pythinker-code" $Version = $env:PYTHINKER_VERSION $NoColor = $env:NO_COLOR diff --git a/web/public/install.sh b/web/public/install.sh index b918f6ba..88da02b5 100755 --- a/web/public/install.sh +++ b/web/public/install.sh @@ -38,7 +38,7 @@ while [[ $# -gt 0 ]]; do esac done -REPO="TechMatrix-labs/pythinker-code" +REPO="Pythoughts-labs/pythinker-code" if [ -t 1 ] && [ -z "$NO_COLOR" ] && [ "${TERM:-}" != "dumb" ]; then NAVY=$'\033[38;5;24m'; FACE=$'\033[38;5;255m'