Skip to main content

Python CLI for wx-ipad automation.

Project description

wxflywheel

Python CLI for wx-ipad automation.

Install

Requirement: Python 3.10+

Published package:

pip install wxflywheel

Local development:

cd cli
make install-dev

Authentication

export WXFLYWHEEL_KEY=your-api-key
export WXFLYWHEEL_HOST=http://host:8011

WXFLYWHEEL_KEY is required for API commands. Help output never requires a key.

Usage

wxflywheel --help
wxflywheel login --help
wxflywheel login status
wxflywheel search article --keyword "微信"
wxflywheel search article --keyword "微信" --sort hot
wxflywheel search article --cursor "<next_cursor>"
wxflywheel related aggregate --keyword "社群运营"
wxflywheel search related --seed "社群运营"
wxflywheel wxindex related --keyword "社群运营"
python -m wxflywheel login status

Current Command Surface

Curated commands are intentionally published one by one. The current public command surface is:

  • wxflywheel login status
  • wxflywheel search article --keyword "<关键词>" [--sort default|newest|hot]
  • wxflywheel search article --cursor "<next_cursor>"
  • wxflywheel related aggregate --keyword "<关键词>"
  • wxflywheel search related --seed "<种子词>"
  • wxflywheel wxindex related --keyword "<关键词>"
  • wxflywheel version / wxflywheel version show / wxflywheel version check
  • wxflywheel self update

WeChat Article Search

wxflywheel search article is a read-only official-account article-list command for AI Agents.

  • First page: wxflywheel search article --keyword "微信" [--sort default|newest|hot]
  • Next page: wxflywheel search article --cursor "<next_cursor>"

The command intentionally returns only:

  • keyword
  • sort
  • has_more
  • next_cursor (only when another page exists)
  • items[]

Each article item keeps only:

  • article_id
  • title
  • summary
  • source_name
  • published_at_ts
  • url
  • cover_url
  • read_count_text (only when the live response includes reading-hotness text)
  • read_count (only when a numeric reading count can be parsed from the live response)

The command does not fetch article bodies, comments, like/share/comment counts, or raw backend fields such as report_extinfo_str.

Output Contract

Command execution emits JSON. Help output remains plain text.

  • Success: stdout, exit code 0
  • Command/runtime errors: stderr, exit code 1
  • Click argument errors: stderr, exit code 2

Schema:

{
  "code": 200,
  "data": {},
  "message": "",
  "meta": {
    "cli": {
      "current_version": "0.3.0",
      "latest_version": "0.3.1",
      "update_available": true,
      "update_severity": "patch",
      "update_command": "pip install --upgrade wxflywheel",
      "self_update_command": "wxflywheel self update",
      "changelog_url": "https://pypi.org/project/wxflywheel/0.3.1/",
      "latest_release_date": "2026-04-10T12:00:00Z",
      "days_behind": 4,
      "cache_age_seconds": 120,
      "has_breaking": false,
      "python_version": "3.11.5"
    }
  }
}

Version Notifications for AI Agents

This CLI's primary users are AI Agents, not humans. Every successful command response carries a meta.cli field with 12 version-related signals so Agents can autonomously detect and decide on upgrades without any out-of-band monitoring.

How it works

  1. Every command emits meta.cli — no special flag needed, it's always there.
  2. 24-hour local cache — version info is cached at ~/.cache/wxflywheel/version_check.json to avoid hitting PyPI on every invocation.
  3. Background refresh — when the cache is stale, a fire-and-forget subprocess worker refreshes it without blocking the current command. If subprocess spawning fails (sandboxed environments), falls back to an inline 500ms-timeout sync refresh.
  4. Breaking-change detection — when a new version is found, the worker parses the CHANGELOG embedded in the PyPI info.description field (the release workflow splices CHANGELOG.md into README.md at build time so PyPI's long_description carries both). It marks update_severity = "breaking" if the new version's section contains ### Breaking, BREAKING CHANGE, or BREAKING: markers. Otherwise severity is SemVer-derived: patch / minor / major. This is a single-request design: version lookup and CHANGELOG parsing share the same PyPI JSON API call — no second network round-trip, and no dependency on GitHub raw (the upstream repository is private and would return 404 to anonymous fetches).
  5. Stable schema — even when offline or cache-empty, the meta.cli object has the same 12 keys with null for unknown values. Agents never need key-exists branches.

Agent upgrade workflow

# Pseudo-code for an Agent using wxflywheel
response = run_cli("wxflywheel login status")
cli_meta = response["meta"]["cli"]

if cli_meta["update_available"]:
    severity = cli_meta["update_severity"]
    if severity == "breaking":
        # Agent should read changelog first before auto-upgrading
        notify_user(
            f"wxflywheel has a BREAKING update to {cli_meta['latest_version']}. "
            f"See {cli_meta['changelog_url']}"
        )
    elif severity in ("patch", "minor"):
        # Safe to auto-upgrade
        run_cli(cli_meta["self_update_command"])  # == "wxflywheel self update"
        # NOTE: the new version only takes effect on the NEXT invocation;
        # the currently running Agent Python process keeps the old code in memory

Manual version check

# Read from cache (fast, offline-OK)
wxflywheel version
wxflywheel version show

# Force refresh from PyPI (may take 1-10s)
wxflywheel version check

Self-update

wxflywheel self update

Invokes python -m pip install --upgrade wxflywheel in a subprocess of the current Python interpreter. Protected by a filesystem lock (~/.cache/wxflywheel/update.lock) to prevent concurrent upgrades. On success, returns before/after version and a reminder that the new version only activates on the next invocation.

Opting out (tests / CI)

Set WXFLYWHEEL_NO_META=1 to make meta a deterministic minimal stub ({"cli": {"current_version": "X.Y.Z"}}). Useful for deterministic test snapshots. wxflywheel's own test suite uses this via an autouse pytest fixture in conftest.py.

Cache directory override

Set WXFLYWHEEL_CACHE_DIR=/custom/path to override the default ~/.cache/wxflywheel. Useful for containerized environments where the home directory is read-only.

Adding a Command Module

Curated commands are intentionally added one by one. Do not expose a backend route directly just because it exists.

Minimum standard for a new curated command:

  • One command maps to one stable user intent.
  • Read-only commands are preferred by default.
  • State-changing behavior must be explicit in the command name or behind an opt-in flag.
  • Output must stay on the standard code/data/message schema.
  • Command logic must use shared helpers from src/wxflywheel/commands/common.py.
  • Every new command must ship with tests before registration.

Workflow:

  1. Copy src/wxflywheel/commands/_template.py.
  2. Replace module/action names and API parameters.
  3. Add focused tests under tests.
  4. Register the command in src/wxflywheel/cli.py.
  5. Run the release checks before merging.

Release Checks

Repeatable release verification now lives in Makefile:

make release-check

This runs:

  • ruff
  • mypy
  • pytest
  • wheel/sdist build
  • twine check
  • editable-command help smoke
  • built-wheel install smoke
  • package rebuild from a clean dist/ / build/ state

The built package ships py.typed, so installed type checkers can treat wxflywheel as a typed package.

Optional live smoke against a real service:

export WXFLYWHEEL_HOST=http://host:8011
export WXFLYWHEEL_KEY=your-api-key
make smoke-live
make smoke-live-article KEYWORD=微信

Development

make install-dev
make release-check

Release Management


[0.5.0] - 2026-04-07

Added

  • wxflywheel search article — a new read-only curated command that wraps POST /v1/Finder/WebSearch for WeChat official-account article lists using the live-verified article search baseline (BusinessType=2, Scene=101). The command intentionally exposes only three server-verified orders (default, newest, hot) and returns a normalized Agent-facing payload: {keyword, sort, has_more, next_cursor?, items[]}. Each article item keeps only article_id, title, summary, source_name, published_at_ts, url, cover_url, plus read_count_text / read_count when the live response actually includes reading-hotness metadata. It does not fetch article bodies, comments, like/share/comment counts, or raw backend fields.
  • Opaque article paging cursor — article pagination no longer exposes raw offset, search_id, or cookies to the caller. The command now returns next_cursor, a base64url-encoded JSON blob carrying {v, keyword, sort, offset, search_id, cookies}. This design is driven by live paging verification: default uses server-returned offsets such as 23 -> 42 (not simple +20), and newest paging breaks if cookies are dropped.
  • make smoke-live-article — a dedicated live smoke target that validates login status, first-page article search for default/newest/hot, second-page paging for default/newest, forbidden-field absence, and meta.cli presence against a real backend.

Changed

  • CLI docs now treat search article as part of the intentional curated command surface. README.md, RELEASE.md, CLAUDE.md, and project memory are updated to describe the new command, its paging model, and the live-smoke entrypoint.
  • cli/RELEASE.md now matches the actual publish path: GitHub Actions OIDC Trusted Publisher, not a manually managed PYPI_API_TOKEN.

[0.4.3] - 2026-04-06

Fixed

  • parse_breaking_from_description no longer false-positives on CHANGELOG sections that describe the breaking-detection feature. Discovered during v0.4.2 end-to-end verification: when the parser finally ran against a real PyPI info.description (for the first time in 3 releases, after v0.4.2 broke the silent fallback), it flagged the v0.3.0 section as has_breaking=True. The reason was that v0.3.0's CHANGELOG entry documents the breaking-detection feature by naming all three marker tokens inline (`### Breaking` headers, `BREAKING CHANGE` phrases, or `BREAKING:` prefixes), and the token scanner treated these literal references as declarations. v0.4.3 adds a _strip_markdown_code_spans preprocessor that removes fenced code blocks (```...```) and inline code (`...`) from the section body before keyword scanning. Real ### Breaking headings and BREAKING CHANGE / BREAKING: tokens in regular prose are still detected; only tokens visually rendered as code literals are ignored.
  • ## [Unreleased] section no longer pollutes PyPI project page. Release workflow now uses awk '/^## \[[0-9]/{found=1} found' instead of cat CHANGELOG.md when splicing into README.md, emitting lines only from the first numeric version header onward. Empty [Unreleased] WIP placeholders stay out of the published long_description.

Added

  • 4 new regression tests covering markdown code-span awareness: backtick-wrapped marker reference (false positive guard), real heading coexisting with backtick reference (must still detect), fenced code block containing marker example (must ignore), and verbatim reproduction of v0.3.0's original prose as a pinned regression fixture.
  • 197 → 201 tests; 100% branch coverage preserved.

Notes

  • The v0.3.0 self-description trap existed from v0.3.0 and was silently masked by the GitHub-raw 404 fallback for 3 releases. This is a textbook "silent fallback hides real bugs" case — v0.4.2's fix to one problem (data source) immediately surfaced a dormant problem (parser not markdown-aware). Both fixes ship in consecutive patches rather than being bundled because v0.4.2 needed to exist on PyPI before end-to-end verification could run.
  • Memory rule reinforced: except X: return False is a reverse-debugging trap. Use Optional[T] to distinguish "unknown" from "confirmed-no"; if bool is mandatory, at least emit a debug log so failures are observable.

[0.4.2] - 2026-04-06

Fixed

  • Breaking-change detection is no longer silently broken. From v0.3.0 through v0.4.1 the fetch_changelog_breaking function fetched raw.githubusercontent.com/vinsew/weixin/main/cli/CHANGELOG.md to look for BREAKING markers, but the upstream repository is private and anonymous raw access returns 404 — meaning has_breaking has been permanently returning False regardless of real CHANGELOG contents since v0.3.0. Agents consuming meta.cli.has_breaking and meta.cli.update_severity == "breaking" have effectively been receiving incorrect (always-non-breaking) signals for every release. v0.4.2 replaces the GitHub raw fetch with local parsing of the PyPI info.description field, which the release workflow (wxflywheel-release.yml) now splices with README + CHANGELOG before twine upload. Zero new network requests — the PyPI JSON API call was already being made for version lookup, so the CHANGELOG arrives in the same response.
  • TD-015 closed. The original technical-debt entry described a pre-emptive concern about unbounded CHANGELOG file growth with stream=True / 100KB cap as the remediation. Investigation showed the real problem was not file size but permanent 404 fallback under private repositories — the "file too large" scenario could never occur because the fetch had never succeeded in the first place. TD-015 is closed as fixed (data source swap), not as implemented-as-described.

Changed

  • meta.cli.changelog_url now points to PyPI project page (https://pypi.org/project/wxflywheel/X.Y.Z/) instead of the GitHub release tag URL (https://github.com/vinsew/weixin/releases/tag/wxflywheel-vX.Y.Z). Agents can now actually follow this URL to read the full long_description including the embedded CHANGELOG. The GitHub release URL was previously unresolvable to anonymous callers because the repository is private.
  • fetch_pypi_latest renamed to fetch_pypi_meta and extended to return a 3-tuple (latest_version, upload_time_iso, description) instead of a 2-tuple. fetch_changelog_breaking deleted outright. New function parse_breaking_from_description(description, version) performs the BREAKING scan as a pure local operation (no network). refresh_cache_from_pypi now makes exactly one PyPI API call and parses everything from the single response.
  • Release workflow (.github/workflows/wxflywheel-release.yml) acquires a new step between tag validation and make release-check: printf '\n---\n\n' >> README.md && cat CHANGELOG.md >> README.md. This modifies only the CI working directory — local developers continue to see the original README.md.

Notes

  • This patch fixes a latent functional regression that existed since v0.3.0. The regression was silent because requests.get(...).raise_for_status() caught the 404 and the function returned False (no BREAKING detected), which is indistinguishable at the cache/meta layer from "CHANGELOG says no breaking changes". Agents relying on has_breaking to auto-upgrade safely were technically receiving a false-negative guarantee for every release since v0.3.0 — though in practice no v0.3.x/v0.4.x release contained real BREAKING markers, so the gap had no observable incident.
  • The v0.4.2 fix is discovered while investigating why TD-015 felt like "an optimization that would never trigger" — which led to recognizing the actual failure mode (private repo 404) vs. the theoretical one (file too large).

[0.4.1] - 2026-04-06

Fixed

  • Matrix CI coverage gap on Windows runners. v0.4.0's try_trigger_background_refresh contains a if sys.platform == "win32" ... else: start_new_session=True branch. On macOS / Linux runners the else branch is taken natively so its line is counted as covered; on Windows runners the if branch is taken natively so start_new_session=True is never executed, causing branch coverage to drop to 99.76% and the 100% coverage gate to fail. v0.4.0 had test_try_trigger_background_refresh_windows_creationflags which monkey-patches sys.platform = "win32" to force the Windows branch on POSIX runners, but lacked the symmetric counterpart. v0.4.1 adds test_try_trigger_background_refresh_posix_start_new_session which monkey-patches sys.platform = "linux" to force the POSIX branch on Windows runners. Both branches are now explicitly covered on every matrix cell; 3 OS × 4 Python = 12 jobs all reach 100% branch coverage.
  • No functional change on any platform. v0.4.0 was already functionally correct on Windows (all 190 tests passed); this patch only fixes the coverage measurement gap so the matrix CI release gate can be truly green.

Notes

  • This release was motivated by the matrix CI's FIRST Windows run revealing the gap — validating the entire v0.4.0 cross-platform strategy: we caught a Windows-specific issue without owning or testing on any Windows machine. The issue turned out to be a test-coverage methodology gap rather than a code bug, which is the best possible outcome for a first matrix run.
  • Release workflow (wxflywheel-release.yml) is still independent of matrix CI (wxflywheel-ci.yml) — v0.4.0 was successfully published to PyPI despite the matrix CI failure. A future v0.4.2 may wire matrix CI as a needs: dependency of the release workflow to make the gate truly blocking, but this requires either merging both workflows or using workflow_call; logged as a consideration for next iteration.

[0.4.0] - 2026-04-06

Added

  • wxflywheel doctor diagnostic command — runs a 6-subsystem self-check (Python runtime / platform identity / required dependencies / cache directory writability / PyPI+GitHub network reachability / subprocess spawn capability) and returns a single JSON verdict. Designed as the FIRST command an Agent should run after pip install wxflywheel on a new machine: surfaces missing deps, broken networks, read-only home directories, wrong Python versions, and sandbox restrictions in one shot rather than letting them emerge one-by-one during real business commands. Requires no API key and does not call any wx-ipad backend — purely a local probe safe in air-gapped environments.
  • Automatic environment fingerprint on all error responses — every error JSON (code/data/message envelope) now carries a compact 10-field platform snapshot under data._environment (platform_system / platform_release / platform_machine / platform_version / python_version / python_implementation / python_executable / locale_preferred_encoding / stdout_encoding / filesystem_encoding). This lets an Agent (or the upstream wx-ipad maintainer) diagnose cross-platform failures without having to round-trip "what OS are you on?" questions. The fingerprint is compact (<300 bytes), contains no PII (no username / hostname / MAC / IP / home path), and only appears on error responses — success responses remain unchanged to minimize bandwidth cost.
  • New module wxflywheel.environment — centralized environment fingerprint collection with defensive _safe wrapper (any attribute lookup that fails returns the string "unknown" instead of None, keeping the schema stable for Agent JSON parsers). Used by both doctor command and error payload injection.
  • GitHub Actions matrix CI (release gate) — on wxflywheel-v*.*.* tag push, the CI workflow now runs the full release-check on 3 operating systems × 4 Python versions = 12 combinations (ubuntu-latest, windows-latest, macos-latest × Python 3.10, 3.11, 3.12, 3.13). This acts as a hard gate before any PyPI publish. Regular main branch pushes continue to use a single fast job (ubuntu + Python 3.11, ~2 min) to preserve quick feedback and avoid burning CI minutes on every dev commit.

Changed

  • error_payload signature is unchanged but behavior changed: when data is None, the returned dict now contains {"_environment": {...}} instead of None. When data is a dict, _environment is merged in as an additional key. When data is a non-dict (list / str / primitive), it becomes {"details": original, "_environment": {...}}. This is technically a JSON envelope change for error responses, which is why v0.4.0 is a minor bump (not patch). Agents that only inspect code/message are unaffected; Agents that inspect data fields should see their existing keys preserved.
  • test_missing_key_exits_1_with_json_stderr (in test_entrypoint.py) updated to assert the new data._environment shape instead of data is None.

Fixed

  • (Layer 1 audit) Verified that no file I/O, subprocess call, JSON serialization, path manipulation, or string encoding in the wxflywheel source depends on the system locale, path separator, line ending convention, or timezone. All open() / Path.open() calls explicitly pass encoding="utf-8"; all subprocess.run / Popen calls use list-form args (no shell=True); all json.dumps uses ensure_ascii=False; all datetimes use timezone.utc. No fixes needed in this release — the audit confirmed v0.3.1 was already cross-platform clean at the source level.

Notes

  • This release completes the 5-layer cross-platform compatibility strategy for wxflywheel:
    1. Code layer: no implicit platform dependencies (verified by audit in v0.4.0)
    2. CI matrix: 3 OS × 4 Python on release gate
    3. Runtime diagnostic: wxflywheel doctor command
    4. Passive telemetry: automatic _environment on error responses
    5. (Optional) Alpine docker test — logged but not implemented
  • Agents can now rely on wxflywheel working on any combination of the 3 major OSes × 4 supported Python versions, and can use wxflywheel doctor to probe edge environments (sandboxes, containers, minimal Python distros) before committing to use the CLI.

[0.3.1] - 2026-04-06

Fixed

  • self update docstring now documents error code -3 (cache directory creation failure) which was previously undocumented, leaving Agents unable to interpret the error. Also corrected the docstring's claim that pip failures return success=false on stdout — in reality pip failures (code -7) are emitted on stderr with exit code 1, matching the standard error contract. The rewritten docstring tells Agents explicitly: "There is no success=false path on stdout — any failure uses stderr + exit 1 + code/data/message envelope; Agents parsing output must check exit code first and read stderr on non-zero."
  • self update subprocess calls (pip install --upgrade wxflywheel and pip show wxflywheel) now use encoding="utf-8", errors="replace" instead of text=True. The previous text=True relied on locale.getpreferredencoding(False), which on Windows CP1252 / CP936 / other non-UTF-8 locales could raise an uncaught UnicodeDecodeError when pip's output contained characters outside the local encoding — breaking the JSON output contract. With explicit UTF-8 + replace, non-decodable bytes become U+FFFD and the JSON envelope survives.
  • try_trigger_background_refresh now wraps the fire-and-forget subprocess.Popen call in a warnings.catch_warnings() block that locally suppresses ResourceWarning. CPython 3.12+ emits ResourceWarning: subprocess <pid> is still running when a Popen wrapper is garbage collected before wait() is called, even when the child process is detached (which is exactly our design). The suppression is local to this single call site; no other warnings are affected.
  • test_all_existing_commands_still_return_three_field_envelope no longer deletes the WXFLYWHEEL_NO_META environment variable. The previous test body had a reversed comment claiming "use stub meta via conftest default" while monkeypatch.delenv actually did the opposite — removing the stub flag set by the autouse conftest fixture and causing build_meta to hit the real code path, which in CI (where no cache file exists) would spawn an actual version-check worker subprocess and leave side effects. The test now keeps the autouse fixture's WXFLYWHEEL_NO_META=1 setting so build_meta returns a deterministic stub, preserving test isolation.

Notes

  • No behavioral changes visible to existing users on the success path. v0.3.0 and v0.3.1 are interchangeable for Agents already using the meta.cli field in the success case; v0.3.1 is strictly more robust on the error path (Windows locales, Python 3.12+, CI isolation).
  • All fixes originated from a post-release rigorous code review against the project-level rules (memory/ai-era-development-philosophy.md, memory/agent-first-expression.md). The review surfaced 2 Important issues and 3 Suggestions; 4 of the 5 are fixed in this patch; the 5th (CHANGELOG size unbounded fetch) is logged to docs/tech-debt.md as a pre-emptive concern with no current symptom.

[0.3.0] - 2026-04-06

Added

  • Agent-aware version notification system. Every command response now includes a meta.cli field with 12 version-related signals (current_version, latest_version, update_available, update_severity, update_command, self_update_command, changelog_url, latest_release_date, days_behind, cache_age_seconds, has_breaking, python_version). Agents using wxflywheel can read this field from any command's JSON response to autonomously detect update availability and decide whether to upgrade.
  • wxflywheel version command group. New version subcommand (alias: version show) displays the cli meta schema from the local 24-hour cache (fast, offline-tolerant). New version check subcommand forces a fresh synchronous PyPI query that bypasses the cache for Agents that need up-to-the-second data.
  • wxflywheel self update command. New self command group with self update subcommand that invokes python -m pip install --upgrade wxflywheel in a subprocess of the currently running Python interpreter. Protected by a cross-process file lock (~/.cache/wxflywheel/update.lock) with a 60-second acquisition timeout to prevent concurrent upgrades from corrupting the package. Returns before/after version, pip stdout/stderr tails, and a hint that the new version only takes effect on the next invocation (current process keeps old code in memory).
  • Background cache refresh worker. A fire-and-forget subprocess (python -m wxflywheel._version_check_worker) is spawned automatically when the 24-hour cache is expired or missing. On platforms where subprocess spawning fails (OSError), falls back to an inline synchronous refresh with a 500ms hard timeout. The main command is never blocked on network I/O by the version-check subsystem.
  • Breaking-change detection from CHANGELOG. When a new version is detected, the worker fetches the GitHub-hosted CHANGELOG and searches the new version's section for ### Breaking headers, BREAKING CHANGE phrases, or BREAKING: prefixes. If found, update_severity is set to "breaking" instead of the SemVer-derived patch/minor/major.

Changed

  • New runtime dependencies: packaging>=23.0,<26 (for PEP 440 version comparison) and filelock>=3.12,<4 (for cross-process update lock). Both are small, widely-used PyPA-maintained packages.
  • emit_payload now accepts an include_meta: bool = True keyword argument. Meta injection is wrapped in a broad except so any version-check failure (network, filesystem, parsing) is silently downgraded to an absent meta field — the primary code/data/message response contract is never broken by version-check internals.
  • Ruff per-file-ignores now also covers version_check.py and _version_check_worker.py for the same Agent First expression-rule reasons as cli.py and commands/.

Compatibility

  • The code/data/message three-field JSON envelope is unchanged and fully backwards compatible. meta is an additive optional field. Agents that parse only the original three fields continue to work without modification. Agents that parse the new meta field get a stable 12-key schema where unknown values are null (not missing keys) for deterministic parsing.

[0.2.1] - 2026-04-05

Changed

  • Rewrote all 8 command and group docstrings (4 groups + 4 actions) to comply with the project-level Agent First expression rule. Every docstring now includes: domain marker (WeChat), action verb, data source, concrete input/output example, and a contrasting qualifier that disambiguates from sibling commands. No behavioral changes — CLI surface, arguments, JSON output contract, and exit codes are identical to v0.2.0.
  • login status now discloses the full login state enum (online / reconnecting / offline / not_login / logout / unknown) and response fields (loginState, loginErrMsg, loginJournal, targetIp).
  • wxindex related vs search related now carry explicit cross-references telling Agents which to pick: WeChat Index returns short high-frequency terms (咖啡机 / 咖啡色), WeChat Search returns long-tail user queries (附近咖啡店 / 星巴克咖啡), and the two sources are non-overlapping in practice.
  • related aggregate docstring now documents all 8 response fields (related / from_search / from_wxindex / both_sources / search_only / wxindex_only / errors) and partial-failure resilience behavior.

[0.2.0] - 2026-04-05

Added

  • Added wxflywheel related aggregate --keyword "<关键词>", which merges Search and WxIndex related keywords with cross-source deduplication (both → search-only → wxindex-only order).
  • Added wxflywheel search related --seed "<种子词>", which calls the RelatedKeywords aggregation API and returns {seed, related[]} inside the standard JSON envelope.
  • Added wxflywheel wxindex related --keyword "<关键词>", which calls the wxindexsug endpoint and returns {keyword, related[]} inside the standard JSON envelope.

Fixed

  • main() now normalizes non-integer SystemExit values into standard JSON stderr output instead of silently returning exit code 1.
  • Click parser errors are now normalized through the CLI entrypoint and no longer bypass the code/data/message contract.
  • make release-check now rebuilds from a clean package artifact state, so stale wheels in dist/ no longer break wheel smoke tests.
  • The published wheel now includes wxflywheel/py.typed, matching the package's typed metadata.

[0.1.0] - 2026-04-04

Added

  • Standardized wxflywheel package foundation with src/ layout and installable console entry point.
  • Unified JSON output contract on code/data/message.
  • Shared command authoring helpers and repeatable release checks.
  • Buildable sdist/wheel release flow and repository CI coverage for the CLI package.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wxflywheel-0.5.0.tar.gz (83.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wxflywheel-0.5.0-py3-none-any.whl (47.1 kB view details)

Uploaded Python 3

File details

Details for the file wxflywheel-0.5.0.tar.gz.

File metadata

  • Download URL: wxflywheel-0.5.0.tar.gz
  • Upload date:
  • Size: 83.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wxflywheel-0.5.0.tar.gz
Algorithm Hash digest
SHA256 e477d0583718030315863985d471c615e9d3d32cf7ec3372b6abb0097832f363
MD5 069f1c57213718820dc2716089c52993
BLAKE2b-256 9c49bb9fa45c505c97dd0c5626d779c53a260525962fce085c7e1f0b135253e3

See more details on using hashes here.

Provenance

The following attestation bundles were made for wxflywheel-0.5.0.tar.gz:

Publisher: wxflywheel-release.yml on vinsew/weixin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wxflywheel-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: wxflywheel-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 47.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wxflywheel-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1bb6d3af9dbdef1bd74f8c496e06c736e6bc99383e9c4eedf3f4cdd2d41cf34e
MD5 2129945c4d63ea0d8ec78c734b7fcb16
BLAKE2b-256 8fbb7bd1507bfbf7b08417240923ec5ffddb78b6570f54012a067139131110b6

See more details on using hashes here.

Provenance

The following attestation bundles were made for wxflywheel-0.5.0-py3-none-any.whl:

Publisher: wxflywheel-release.yml on vinsew/weixin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page