diff --git a/.agents/skills/gen-rust/SKILL.md b/.agents/skills/gen-rust/SKILL.md deleted file mode 100644 index 0a7210ee..00000000 --- a/.agents/skills/gen-rust/SKILL.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -name: gen-rust -description: Sync Rust implementation with Python changes (exclude UI/login) by reviewing recent changes, mapping modules, porting logic, and updating tests. ---- - -# gen-rust - -Use this skill when the user wants Rust (kagent/pythinker-core/pythinker-host) to stay logically identical to Python (pythinker_code/pythinker_core/pythinker_host), excluding UI and login/auth. This includes code and tests: Rust behavior and tests must be fully synchronized with Python changes. - -Note: The Rust binary is named `kagent`. User-facing CLI/output text in Rust must use `kagent` -instead of `pythinker` to match the Rust command name. - -## Quick workflow - -1) **Build a complete change inventory** - -Review recent changes to understand what needs syncing: - -```sh -# Check staged changes -git diff --cached --name-only -git diff --cached -- src packages - -# Check recent commits -git log --oneline -20 -- src packages -git diff HEAD~20..HEAD -- src packages - -# Review CHANGELOG.md for context -head -50 CHANGELOG.md -``` - -2) **Classify changes** - -- Exclude UI and login/auth changes (Shell/Print/ACP UI, login/logout commands). -- Everything else must be mirrored in Rust. -- Keep a small checklist: file -> change summary -> Rust target -> status. - -3) **Map Python -> Rust** - -Common mappings: -- `src/pythinker_code/llm.py` -> `rust/kagent/src/llm.rs` -- `src/pythinker_code/soul/*` -> `rust/kagent/src/soul/*` -- `src/pythinker_code/tools/*` -> `rust/kagent/src/tools/*` -- `src/pythinker_code/utils/*` -> `rust/kagent/src/utils/*` -- `src/pythinker_code/wire/*` -> `rust/kagent/src/wire/*` -- `packages/pythinker-core/*` -> `rust/pythinker-core/*` -- `packages/pythinker-host/*` -> `rust/pythinker-host/*` - -4) **Port logic carefully** - -- Match error messages and tool output text exactly (tests often assert strings). -- Preserve output types (text vs parts) and ordering. -- For media/tool outputs, verify ContentPart wrapping and serialization. -- If Python adds new helper modules, mirror minimal Rust utilities. -- Use `rg` to find existing analogs and references. - -5) **Update tests** - -- Update Rust tests that assert content/strings/parts. -- Mirror Python unit and integration tests when they exist; add missing Rust tests so coverage matches intent. -- Ensure E2E parity: use the existing Python E2E suite against the Rust binary by setting - `PYTHINKER_E2E_WIRE_CMD` (do not rewrite E2E in Rust). All E2E cases must pass or the gap must be documented. -- Prefer targeted tests first (`cargo test -p kagent --test `), then full suite if asked. - -6) **Verification is mandatory** - -- Run the full Rust test suite and ensure all Rust tests pass. -- Run E2E tests with the wire command swapped to Rust (set `PYTHINKER_E2E_WIRE_CMD`), and ensure they pass. - -7) **Final report** - -- List synced files and logic. -- Call out intentionally skipped UI/login changes. -- List tests run and results (must include full Rust tests and Rust E2E with wire command override). - -## Pitfalls to avoid - -- Skipping `llm.py`: it often changes model capability logic. -- Using commit message filtering instead of full diff. -- Forgetting to update Rust tests when output text/parts change. -- Mixing UI/login changes into core sync. -- Leaving test parity ambiguous; always state unit/integration/E2E status. - -## Minimal diff checklist (template) - -- [ ] Recent changes reviewed (staged, commits, changelog) -- [ ] Python diffs inspected for core logic -- [ ] Rust mappings applied -- [ ] Tests updated -- [ ] Targeted tests run -- [ ] Full Rust test suite passed -- [ ] Rust E2E passed with `PYTHINKER_E2E_WIRE_CMD` diff --git a/.agents/skills/release/SKILL.md b/.agents/skills/release/SKILL.md deleted file mode 100644 index b79ece1d..00000000 --- a/.agents/skills/release/SKILL.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -name: release -description: Execute the release workflow for Pythinker CLI packages. -type: flow ---- - -```d2 -understand: |md - Understand the release automation by reading AGENTS.md and - .github/workflows/release*.yml. -| -check_changes: |md - Check each package under packages/, sdks/, and repo root for changes since the - last release (by tag). Note packages/pythinker-code is a thin wrapper and must stay - version-synced with pythinker-code. -| -has_changes: "Any packages changed?" -confirm_versions: |md - For each changed package, confirm the new version with the user. Follow the - project versioning policy: patch is always 0, bump minor for any change, - major only changes by explicit manual decision. -| -update_files: |md - Run `uv run python scripts/release.py --set-version X.Y.Z [--bump-core A.B.C --bump-host A.B.C]`. - It rewrites pyproject.toml:3, the sub-package pins, uv.lock, all three changelog files - (preserving the authored Unreleased body), and the README/asset names from the single - source of truth, then runs the local gates and opens the `release/X.Y.Z` PR. - There is no `--bump-review` (review is frozen at 0.1.0). -| -root_change: "Is the root package version changing?" -sync_pythinker_code: |md - Sync packages/pythinker-code/pyproject.toml version and dependency - `pythinker-code==`. -| -sync_kagent: |md - Sync rust/Cargo.toml workspace version to match the root package version. -| -uv_sync: "release.py already runs `uv lock` + `uv sync --frozen --all-extras --all-packages` as Phase-2/3 steps; no separate uv sync needed." -gen_docs: |md - Follow the gen-docs skill instructions to ensure docs are up to date. -| - -new_branch: |md - Create a new branch `bump--` (multiple packages can share - one branch; name it appropriately). -| -open_pr: |md - Commit all changes, push to remote, and open a PR with gh describing the - updates. -| -monitor_pr: "Monitor the PR until it is merged." -post_merge: |md - After merge, switch to main, pull latest changes, and tell the user the git - tag command needed for the final release tag (they will tag + push tags). Note: - a single numeric tag releases pythinker-code, pythinker-code, and kagent together. -| - -BEGIN -> understand -> check_changes -> has_changes -has_changes -> END: no -has_changes -> confirm_versions: yes -confirm_versions -> update_files -> root_change -root_change -> sync_pythinker_code: yes -root_change -> uv_sync: no -sync_pythinker_code -> sync_kagent -sync_kagent -> uv_sync -uv_sync -> gen_docs -> new_branch -> open_pr -> monitor_pr -> post_merge -> END -``` diff --git a/.agents/skills/worktree-status/SKILL.md b/.agents/skills/worktree-status/SKILL.md deleted file mode 100644 index 2f15f8a7..00000000 --- a/.agents/skills/worktree-status/SKILL.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -name: worktree-status -description: Audit all git worktrees in the current project. Use when the user asks about worktree status, which branches are merged, which have uncommitted changes, or which worktrees can be safely cleaned up. ---- - -# worktree-status - -Report the status of every git worktree for the current project, covering -dirty state and merge status. - -## When to use - -- User asks "which worktrees can I clean up?" -- User asks "what's the status of my worktrees / branches?" -- Before batch-cleaning worktrees, to avoid losing uncommitted work - -## Procedure - -### 1. Pull latest main (MANDATORY) - -You MUST pull latest main before any status checks. Without this, merge -detection (both ancestry and content diff) will produce stale results and -you may mistakenly conclude a branch is not merged. - -```bash -cd "$(git rev-parse --show-toplevel)" && git pull origin main -``` - -### 2. Collect worktree info - -```bash -PROJECT_DIR="$(git rev-parse --show-toplevel)" - -for wt in $(git worktree list --porcelain | grep "^worktree " | sed 's/^worktree //' | grep -v "$PROJECT_DIR$"); do - branch=$(git -C "$wt" branch --show-current 2>/dev/null) - [ -z "$branch" ] && branch="(detached)" - name=$(basename "$wt") - - # dirty? - if [ -z "$(git -C "$wt" status --short 2>/dev/null)" ]; then - dirty="clean" - else - dirty="DIRTY" - fi - - # merged into origin/main? - # NOTE: This project uses squash merges exclusively. `git merge-base - # --is-ancestor` does NOT detect squash-merged branches. Always follow - # up with a content diff (step 3) for branches that appear "not merged". - if [ "$branch" != "(detached)" ]; then - if git merge-base --is-ancestor "$branch" origin/main 2>/dev/null; then - merged="merged" - else - merged="not merged (verify with content diff)" - fi - else - merged="n/a" - fi - - echo "" - echo "[$name] branch=$branch $dirty $merged" - if [ "$dirty" = "DIRTY" ]; then - git -C "$wt" status --short 2>/dev/null | sed 's/^/ /' - fi -done -``` - -### 3. Detect squash-merged branches (content diff) - -For any branch that shows "not merged", check whether the branch's -changes are already in main. The correct method is: - -1. Find the files the branch actually changed (relative to merge-base). -2. For each changed file, compare the branch version with main. - If all files are identical, the branch was squash-merged. - -**⚠️ Do NOT use `git diff origin/main `** — that compares the -two tips directly, so commits added to main *after* the branch diverged -will show up as false differences. - -```bash -BRANCH="" -BASE=$(git merge-base origin/main "$BRANCH") - -# List files the branch touched -FILES=$(git diff --name-only "$BASE" "$BRANCH") - -# Compare each file between branch and current main -for f in $FILES; do - d=$(git diff "$BRANCH" origin/main -- "$f" | wc -l) - if [ "$d" != "0" ]; then - echo "❌ $f — differs" - else - echo "✅ $f — identical in main" - fi -done -# All ✅ = squash-merged -``` - -### 4. (Optional) Check for associated tmux sessions - -Only run this if `tmux` is available and relevant (e.g. worktrees were -created by codex-worker or similar tooling). Skip if not applicable. - -```bash -tmux ls 2>/dev/null | grep -E 'codex-worker|' || true -``` - -### 5. Present results - -**Always present results as a Markdown table.** Every worktree must appear -as a row. Never use abbreviated or prose-only summaries. - -| Worktree | Branch | Dirty | Merged | Can clean? | -|---|---|---|---|---| -| `example-wt` | `feat-foo` | ✅ clean | ✅ squash-merged | ✅ | -| `another-wt` | `fix-bar` | ⚠️ 3 files | ❌ not merged | ❌ dirty + not merged | -| `detached-wt` | (detached) | ⚠️ 14 files | n/a | ❌ has uncommitted changes | - -Column definitions: - -- **Dirty**: `✅ clean` or `⚠️ N files` -- **Merged**: `✅ merged` / `✅ squash-merged` (confirmed via content diff) / `❌ not merged` / `n/a` -- **Can clean?**: `✅` only when merged (or squash-merged) AND clean - -Add extra columns (e.g. tmux session, notes) only when relevant. - -### 6. Cleanup (only when asked) - -Only clean worktrees the user explicitly approves. For each: - -```bash -NAME="" -git worktree remove "/path/to/$NAME" -git branch -D "" # only if the branch is no longer needed -``` diff --git a/.gitignore b/.gitignore index bf8285ba..48e2cdbd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ wheels/ # Project files .vscode +/.agents/ .env .env.local AGENTS.local diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b6d0911..ba6850b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ GitHub Releases page; `0.8.0` is the new starting line. ## Unreleased +- Treat the repository-root `.agents/` directory as local agent configuration and keep it out of version control. - Show an update notice when a newer Pythinker version becomes available mid-session. ## 0.61.0 (2026-07-22)