Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
c106791
Scaffold DDD/hexagonal package and domain layer (Phase A + B)
May 4, 2026
bbaf6a7
Phase C: infrastructure adapter layer (DDD migration epic panvex-enp)
May 5, 2026
f238c3a
Phase D: application layer (event bus, throttle, handlers, orchestrator)
May 5, 2026
4617079
Phase E: Typer CLI + composition root
May 5, 2026
76ba67e
Phase F: PyInstaller spec + bundled-asset test + cold-start benchmark
May 5, 2026
b4fa4f0
Phase G: cutover prep — catalog wiring + regex sample test + docs
May 5, 2026
ee1ce10
docs(readme): add Russian and Ukrainian translations + language switcher
May 5, 2026
6c8d881
chore: fix all ruff lint errors + bump deprecated GitHub Actions
May 5, 2026
fcc50b6
fix(deps): declare httpx as runtime dependency
May 5, 2026
6a1b9bc
ci(workflow): hoist FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 to workflow env
May 5, 2026
aeb081a
ci(actions): bump to latest major versions per context7 docs
May 5, 2026
142e745
feat(detector): support official PoE2 client (PathOfExile.exe) alongs…
PrEvIeS May 5, 2026
e006c53
feat(owner): auto-pin local player via area-entered + level-event sta…
PrEvIeS May 5, 2026
8ff71f3
feat(afk): publish AFK/DND status with [AFK] suffix and small-image o…
PrEvIeS May 5, 2026
c44ec74
feat(tray,autostart): background launcher (pystray + Windows Startup)
PrEvIeS May 5, 2026
4dd9b55
docs: mark all 4 README to-do items done; document campaign features …
PrEvIeS May 5, 2026
44e446e
docs(agents): refresh hierarchical AGENTS.md after hexagonal migration
PrEvIeS May 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-04 | Updated: 2026-05-04 -->

# .github

## Purpose
GitHub-specific configuration: the CI/CD pipeline that builds and releases the Windows `.exe`, and the issue templates surfaced in the repository's "New Issue" UI.

## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `workflows/` | GitHub Actions workflows (see `workflows/AGENTS.md`) |
| `ISSUE_TEMPLATE/` | Issue form templates (see `ISSUE_TEMPLATE/AGENTS.md`) |

## For AI Agents

### Working In This Directory
- Changes here only take effect when pushed to `main` (or merged via PR).
- The build workflow is path-filtered to `main.py` — adding new source files means updating both `paths:` in `build.yml` and the PyInstaller invocation.

<!-- MANUAL: -->
23 changes: 23 additions & 0 deletions .github/ISSUE_TEMPLATE/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-04 | Updated: 2026-05-04 -->

# ISSUE_TEMPLATE

## Purpose
GitHub issue form templates surfaced when a user opens "New Issue" on the repository.

## Key Files
| File | Description |
|------|-------------|
| `config.yml` | Sets `blank_issues_enabled: true` (users can still open a free-form issue alongside the templates). |
| `help-wanted.yml` | Form template titled `[HELP] ` with a game-version dropdown (Steam / Official / Epic), a "What happened?" textarea, and an optional log file textarea. Auto-assigns to `ezbooz` and applies the `help wanted` label. |

## For AI Agents

### Working In This Directory
- Files use GitHub's [Issue Forms YAML schema](https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms). Validate locally before pushing — broken templates silently fall back to the blank issue UI.
- The default game-version dropdown index is `0` (Steam). If you reorder the options, update the `default:` field accordingly.
- Don't put log file uploads inside the form — GitHub Issue Forms can't accept attachments. The current template asks the user to attach manually after creation, which is the correct workaround.
- Auto-assignment to `ezbooz` is intentional (project owner). Don't reassign without coordinating.

<!-- MANUAL: -->
35 changes: 35 additions & 0 deletions .github/workflows/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-05-04 | Updated: 2026-05-04 -->

# workflows

## Purpose
GitHub Actions workflow definitions. Currently a single pipeline that builds the Windows executable and publishes a tagged GitHub Release.

## Key Files
| File | Description |
|------|-------------|
| `build.yml` | Build-and-release pipeline. Triggers on push to `main` when `main.py` changes (or `workflow_dispatch`). Two jobs: `build` (PyInstaller `--onefile`, uploads artifact, creates timestamp tag `vYYYYMMDD-HHMMSS` and pushes it) and `release` (downloads artifact, creates GitHub Release, uploads `.exe` asset). |

## For AI Agents

### Working In This Directory
- The workflow runs on `windows-latest` because PyInstaller produces a native binary; do not switch to `ubuntu-latest`.
- The `paths:` filter is `main.py` — if the project ever splits into multiple source files, broaden the filter (e.g. `'**/*.py'`) or the build will silently stop running on relevant changes.
- The PyInstaller command (`pyinstaller --onefile --name PathOfExile2DiscordRPC main.py`) hardcodes the entrypoint and output name. Renaming `main.py` requires updating this line.
- The release uses the deprecated `actions/create-release@v1` and `actions/upload-release-asset@v1`. If migrating, prefer `softprops/action-gh-release` and verify the tag-creation step still pushes the tag before the release job runs (the `release` job depends on `needs.build.outputs.tag_name`).
- Tags are auto-generated from the build timestamp via PowerShell (`Get-Date -Format yyyyMMdd-HHmmss`). Don't switch to semver without also updating release tooling.
- `permissions: contents: write` is required for both pushing the tag and creating the release.

### Testing Requirements
- Trigger via `workflow_dispatch` from the Actions tab to dry-run without a `main.py` commit.
- Verify the artifact `PathOfExile2DiscordRPC.exe` appears under both the workflow run's artifacts and the new GitHub Release.

## Dependencies

### External
- `actions/checkout@v4`, `actions/setup-python@v4`, `actions/upload-artifact@v4`, `actions/download-artifact@v4`
- `actions/create-release@v1`, `actions/upload-release-asset@v1` (deprecated; see note above)
- `pyinstaller` (installed at job runtime, not pinned)

<!-- MANUAL: -->
200 changes: 129 additions & 71 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,152 @@ on:
branches:
- main
paths:
- 'main.py'
- 'src/**'
- 'tests/**'
- 'pyproject.toml'
- 'locations.json'
- 'PathOfExile2DiscordRPC.spec'
- '.github/workflows/build.yml'
workflow_dispatch:

permissions:
contents: write

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
changes:
runs-on: ubuntu-latest
outputs:
build_relevant: ${{ steps.filter.outputs.build_relevant }}
steps:
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v4
id: filter
with:
filters: |
build_relevant:
- 'src/**'
- 'pyproject.toml'
- 'locations.json'
- 'PathOfExile2DiscordRPC.spec'
- '.github/workflows/build.yml'

lint-and-test:
runs-on: ubuntu-latest
needs: changes
steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Ruff lint
run: ruff check src tests

- name: Ruff format check
run: ruff format --check src tests

- name: Mypy strict typecheck
run: mypy --strict src/poe2_rpc

- name: Import-linter (layered architecture)
run: lint-imports

- name: Pytest unit + integration
run: pytest tests -ra

build:
runs-on: windows-latest
needs: [changes, lint-and-test]
if: needs.changes.outputs.build_relevant == 'true'

outputs:
tag_name: ${{ steps.tag.outputs.tag }}
release_body: ${{ steps.notes.outputs.body }}

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller

- name: Build executable
run: pyinstaller --onefile --name PathOfExile2DiscordRPC main.py

- name: Archive executable
uses: actions/upload-artifact@v4
with:
name: executable
path: dist/PathOfExile2DiscordRPC.exe

- name: Generate release notes
id: notes
run: |
echo "body=$(git log -1 --pretty=format:'%h - %s')" >> $GITHUB_OUTPUT

- name: Create and push tag
id: tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$TAG = "v$(Get-Date -Format yyyyMMdd-HHmmss)"
echo "tag=$TAG" >> $env:GITHUB_OUTPUT
git config --global user.name "github-actions"
git config --global user.email "github-actions@github.com"
git remote set-url origin "https://x-access-token:$env:GITHUB_TOKEN@github.com/${{ github.repository }}.git"
git tag $TAG
git push origin $TAG
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
cache: 'pip'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Build executable
run: pyinstaller PathOfExile2DiscordRPC.spec

- name: Smoke-test executable (validate-config --no-discord)
run: dist\PathOfExile2DiscordRPC.exe validate-config --no-discord

- name: Cold-start benchmark (5x validate-config --no-discord)
run: pytest tests/integration/test_cold_start.py -ra
continue-on-error: true

- name: Archive executable
uses: actions/upload-artifact@v4
with:
name: executable
path: dist/PathOfExile2DiscordRPC.exe

- name: Generate release notes
id: notes
shell: bash
run: |
echo "body=$(git log -1 --pretty=format:'%h - %s')" >> $GITHUB_OUTPUT

- name: Create and push tag
id: tag
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$TAG = "v$(Get-Date -Format yyyyMMdd-HHmmss)"
echo "tag=$TAG" >> $env:GITHUB_OUTPUT
git config --global user.name "github-actions"
git config --global user.email "github-actions@github.com"
git remote set-url origin "https://x-access-token:$env:GITHUB_TOKEN@github.com/${{ github.repository }}.git"
git tag $TAG
git push origin $TAG

release:
needs: build
runs-on: windows-latest
if: needs.build.outputs.tag_name != ''

steps:
- name: Download executable
uses: actions/download-artifact@v4
with:
name: executable
path: dist

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.build.outputs.tag_name }}
release_name: Release ${{ needs.build.outputs.tag_name }}
body: ${{ needs.build.outputs.release_body }}
draft: false
prerelease: false

- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: dist/PathOfExile2DiscordRPC.exe
asset_name: PathOfExile2DiscordRPC.exe
asset_content_type: application/octet-stream
- name: Download executable
uses: actions/download-artifact@v5
with:
name: executable
path: dist

- name: Create Release and upload asset
uses: softprops/action-gh-release@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ needs.build.outputs.tag_name }}
name: Release ${{ needs.build.outputs.tag_name }}
body: ${{ needs.build.outputs.release_body }}
draft: false
prerelease: false
files: dist/PathOfExile2DiscordRPC.exe
28 changes: 27 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,28 @@
.idea/
__pycache__/
__pycache__/
.DS_Store

# Build artifacts (PyInstaller + setuptools)
dist/
build/
*.egg-info/
*.spec.bak

# Tooling caches
.mypy_cache/
.pytest_cache/
.ruff_cache/

# Beads / Dolt files (added by bd init)
.dolt/
*.db
.beads-credential-key

# Local Claude Code config
.claude/

# OMC runtime artifacts (specs/plans are tracked separately)
.omc/sessions/
.omc/state/
.omc/project-memory.json
.omc/notepad.md
8 changes: 8 additions & 0 deletions .omc/plans/open-questions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Open Questions

## ralplan-architecture-libraries — 2026-05-04

- [ ] **`LevelInfo.ascension_class` type — `str | None` vs `"Unknown"` literal?** — Plan assumes `None` for type-safety; presence-handler omits the `| {ascension}` segment when None. Current `main.py` uses the literal string `"Unknown"`. Confirm before closing task **B-2**. Matters because every downstream handler needs a single typed shape; mixing the two creates a runtime `if x == "Unknown"` smell.
- [ ] **Bundled `locations.json` location in source tree — `src/poe2_rpc/locations.json` or root-level + `[tool.setuptools.package-data]` mapping?** — Plan assumes the latter (single source of truth at repo root, mapped into the package via package-data). Confirm before closing task **F-2**. Matters because `importlib.resources.files("poe2_rpc")` resolution must work both in dev-install (`pip install -e .`) and inside the PyInstaller `.exe` bundle, and the wrong choice causes one of the two environments to silently miss the file.
- [ ] **`--debug-watchdog` CLI flag — keep in v1 or defer?** — Plan assumes keep, as PM-1 triage aid (prints every `FileSystemEvent`). Cost is small at task **E-1**. Confirm before closing E-1. Matters because if watchdog stalls in the wild (PM-1), users have no other lever to produce a useful issue report.
- [ ] **Live-game smoke run owner and timing for task G-4** — Who runs the .exe against a real PoE2 client + Discord, and at what point in the cutover (before or after `main.py` deletion in G-2)? Plan assumes G-4 follows G-3, but a pre-deletion smoke run would let us roll back without resurrecting `main.py` from git. Matters for de-risking cutover.
Loading