* fix: _extract_retry_after returns None for non-retryable errors
* fix: update _extract_retry_after to handle generic transient errors with default retry delay
* fix: extend base _non_retryable_patterns in channel subclasses
* fix(channels): merge structured SDK error check into non-retryable step
* fix(channels): decouple status code and SDK error code extraction in retry logic
- Independently evaluate HTTP status codes and structured SDK error codes
- Fix misleading doc comments for Feishu and DingTalk patterns
- Remove redundant try-except AttributeError on getattr with default
- Expand test coverage for dual-signal matrix and header parsing
* refactor(channels): simplify status code and SDK error extraction via channel overrides
- Handle httpx and aiohttp exceptions in base Channel class
- Override _extract_status_code and _extract_sdk_error_code in SlackChannel and DiscordChannel
- Replace mock exception types in comprehensive test suite with real httpx and aiohttp errors
- Add dedicated Slack and Discord retry error extraction test suites
* fix(channels): clean up Slack and Discord error code extraction
- Remove defensive string checks and attribute guards in SlackChannel
- Directly access exc.response.status_code and exc.response.get('error') in SlackChannel
- Remove unnecessary _extract_sdk_error_code override in DiscordChannel
- Use real SlackApiError, SlackResponse, and discord.HTTPException in unit tests
* refactor: reorder retry logic to prioritize non-retryable checks, remove aiohttp dependency, and clean up exception handling in base and channel modules.
* test(channels): skip Slack/Discord retry tests when the SDK extra is absent
The retry-extraction tests build real SlackApiError / discord.HTTPException
objects, but slack-sdk and discord.py are optional extras that the dev
dependency group does not install. Under CI's `uv sync --dev` all nine
tests failed with ModuleNotFoundError raised from the channel override.
Gate both test classes with skipif(find_spec(...) is None) so the suite is
green without the extras and the tests still run wherever they are installed.
* refactor(channels): replace retry-delay lookup with _extract_retry_delay
_extract_retry_after still read the server-supplied delay by probing
exc.retry_after and exc.response.headers via getattr/hasattr, the last
remnant of the pattern the extractors moved away from. Replace both steps
with one overridable hook, _extract_retry_delay, implemented against the
real exception types:
- base: httpx.HTTPStatusError -> Retry-After header (httpx.Headers is
case-insensitive; HTTP-date form remains unsupported)
- SlackChannel: SlackApiError -> Retry-After, matched case-insensitively
because SlackResponse.headers is a plain dict whose casing depends on the
HTTP client (same approach as slack_sdk's RateLimitErrorRetryHandler)
- TelegramChannel: telegram.error.RetryAfter.retry_after (int, or timedelta
under PTB_TIMEDELTA)
- DiscordChannel: discord.RateLimited.retry_after, which the old duck-typed
getattr matched and would otherwise have been lost
Drop the isinstance(retry, bool) and val >= 0 guards; no SDK produces those.
Delete the test that asserted the duck-typed attribute; add real-object tests
for each override, guarded like the existing SDK-dependent classes.
* ci: install the all-channels extra so SDK-dependent channel tests run
The Slack, Discord, and Telegram retry tests build real SDK exception
objects and are skipped when the SDK is absent. CI only ran `uv sync --dev`,
so those tests never executed there. Install the existing all-channels
extra alongside the dev group; the skipif guards remain for lean local runs.
* fix(channels): honor HTTP-date Retry-After and tolerate malformed values
RFC 9110 allows Retry-After as either delay-seconds or an HTTP-date. The
httpx path treated a date as unparseable and fell back to the 1.0 s default,
so a 503 asking for a specific wait was retried too early. Add
Channel._parse_retry_after, which returns delay-seconds as-is and converts
an HTTP-date to the non-negative seconds until it (tz-less dates read as
UTC).
SlackChannel used a bare float() on the header. A non-numeric value raised
inside the retry predicate, which escapes retry_async and drops the chunk
instead of retrying. Route Slack through the same helper so a bad header
falls back to _rate_limit_delay.
Addresses CodeRabbit review comments on base.py:866 and slack/channel.py:229.
* fix(channels): treat HTTP 400 and 404 as non-retryable
Both are permanent for a given request, so retrying burns the attempt
budget for nothing. Add them to _non_retryable_status_codes alongside
401/403.
Deliberately not a 4xx range check: 408 and 425 are retryable by
definition and 429 is handled by the rate-limit path. A test pins 408 as
still retryable so the range shortcut is not reintroduced later.
Partially addresses CodeRabbit's outside-diff comment on base.py:749-750.
* fix(channels): guard Slack retry extractors against raw aiohttp responses
slack_sdk attaches the bare aiohttp.ClientResponse to SlackApiError when a
JSON-declared body fails to parse. That object has neither status_code nor
get(), so _extract_status_code raised AttributeError inside should_retry,
replacing the original error and skipping the remaining attempts. Narrow
both extractors to SlackResponse/AsyncSlackResponse so such errors fall
through to the message patterns and retry as before. Add a wire-level
regression test against a local aiohttp server.
---------
Co-authored-by: Dinos Papakostas <dinospk1999@gmail.com>
Co-authored-by: X-iZhang <zacharyzhang2022@gmail.com>
* feat(llm): add GLM-5.3-Flash, Qwen3.8-Flash, and Tencent HY4 preview
GLM-5.3-Flash on Zhipu, Zhipu Coding Plan and OpenRouter; Qwen3.8-Flash on
DashScope, DashScope Coding Plan and OpenRouter; HY4 preview on OpenRouter.
All three get explicit 1M-class context-window entries so they are not
caught by the glm-5 family fallback (203K) or the 200K default.
* chore: update wechat_group image asset
* chore: update version to v0.2.9
uv.lock moves to deepagents 0.7.11 with its raised dependency floors
(langchain 1.3.18, langchain-core 1.6.1, langchain-anthropic 1.7.0,
langchain-google-genai 4.3.7, langsmith 0.11.2); langgraph stays 1.2.11.
* docs: use umbrella provider names in v0.2.9 changelog
* ci: publish to PyPI via trusted publishing; build version images on release
* ci: pin publish actions to commit SHAs; extend version guard to docker and manual dispatch
* ci: disable setup-uv cache in the publish workflow
* feat: configurable bind host for WebUI and langgraph dev (refs #400)
WebUI mode was only reachable from the machine running it: the front-end
got no bind interface, and `start_langgraph_dev(...)` was called without a
host, so both servers stayed on loopback with no way to widen them.
Adds two config fields with deliberately different defaults:
webui_host = 0.0.0.0 front-end serves the app shell, no secrets
langgraph_dev_host = 127.0.0.1 unauthenticated API, agent can run shell
The design hinges on separating bind address from client address. Only
bind() uses the configured interface; every consumer that *connects*
(health probes, occupancy checks, async sub-agent self-dispatch) goes
through the new `_probe_host`, which maps a wildcard bind back to
loopback and honors a pinned interface verbatim. `_can_bind_port` is the
one exception and binds the literal host, since it must replicate the
bind the server itself will attempt.
- manager.py: `_probe_host`, `_is_loopback_host`, `_format_hostport`;
host kwarg threaded through the probes and `start_langgraph_dev`,
which now emits `--host` and propagates
EVOSCIENTIST_LANGGRAPH_DEV_HOST to the subprocess
- sdk.py: `langgraph_dev_url` tracks host as well as port;
EvoScientist.py reuses it instead of an inline f-string
- server.py: `--host` flag mirroring `--port`, plus a red PUBLIC BIND
banner whenever the bind is not provably loopback
- webui.py: forwards both hosts; the front-end is widened via HOSTNAME
because @evoscientist/webui ships no --host flag — its bin launcher
does `HOSTNAME: process.env.HOSTNAME || "127.0.0.1"`. The warning is
gated on the backend host only, so the shipped front-end default
doesn't print a banner on every launch
Verified end to end against a live server: requesting 0.0.0.0 yields a
socket listening on 0.0.0.0 with the health probe correctly resolved to
127.0.0.1, while the default still binds 127.0.0.1 only.
Note: webui_host defaulting to 0.0.0.0 is a behavior change — upgrading
users will find the front-end reachable from the LAN.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* feat: default both bind hosts to 0.0.0.0, add --host and wizard host rendering (closes#400)
Completes the remaining items from #400.
- `langgraph_dev_host` now defaults to 0.0.0.0, matching `webui_host`.
Remote WebUI use needs both anyway (the UI reaches the backend from the
browser, not server-side), so a loopback backend default just meant every
remote user hit a silently failing UI. `_DEFAULT_HOST` and sdk's
`DEFAULT_LANGGRAPH_DEV_HOST` follow, so there is one story about where
these servers listen.
SECURITY: this exposes an unauthenticated API whose agent can run shell
commands. The red PUBLIC BIND banner consequently fires on every launch
while exposed — kept deliberately, since the exposure is real and the
escape hatch (`--host 127.0.0.1` / `config set langgraph_dev_host`) is
only discoverable if we say so. READMEs now lead with the warning and
document the SSH-tunnel alternative.
- `EvoSci --host <ip>` on the WebUI launch path, driving both servers. In
WebUI mode they are two halves of one surface; moving only one leaves the
UI loading but unable to reach the agent. Blank values are dropped rather
than written as an empty override that would beat the config file.
- Onboarding wizard no longer prints hard-coded `http://127.0.0.1:{port}` /
`http://localhost:{port}` (steps.py:160, :223) — both render the
configured bind through `_base_url` / `_format_hostport`, so a pinned
interface is reported honestly and a wildcard still shows loopback.
Verified against a live server: with no host argument at all, resolution
through EvoScientistConfig yields a socket listening on 0.0.0.0, a client URL
of http://127.0.0.1, and the warning gate returning True.
Still open and tracked separately: the front-end takes its backend URL from
browser input: `@evoscientist/webui` reads only HOSTNAME, PORT and
EVOSCIENTIST_LANGGRAPH_DEV_PORT, so advertising a backend URL needs a change
in that repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* ci: bump setup-uv v6 -> v9.0.0 to drop the deprecated node20 runtime
GitHub now warns that setup-uv@v6 targets Node.js 20 and is being forced
onto Node.js 24. v7.0.0 is the release that made that switch, so anything
>= v7 clears the warning; v9.0.0 is current.
Pinned to the full tag deliberately: setup-uv stopped publishing major and
minor tags in v8.0.0 as supply-chain hardening, so `@v9` and `@v8` return
404 and would fail the job outright. Releases are immutable from v8 on, so
the full tag is as tamper-proof as a SHA. Comment left in lint.yml because
"simplifying" this back to `@v9` is an easy and CI-breaking mistake.
actions/checkout@v5 is already node24 and needs no change.
Note: v9.0.0 flips the `prune-cache` default to false (upstream did this to
ease load on PyPI infrastructure). None of these workflows set it, so they
follow the new default and Actions cache usage may grow.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(cli): correct --host help text and warn on public bind in non-WebUI modes
The --host help claimed "WebUI mode only", which is wrong in a way that
matters for security. `--host` writes `langgraph_dev_host` unconditionally,
and `_ensure_async_subagent_server` auto-starts that backend for tui / cli /
serve as well — the langgraph dev server is shared across UI modes. So the
flag narrows or widens the agent API in every mode, and only `webui_host` is
actually WebUI-specific. Reported against cli/commands.py.
The documentation error hid a real gap: the PUBLIC BIND banner lived only in
deploy/server.py and deploy/webui.py, so a plain `EvoSci` session bound
0.0.0.0 with no runtime signal whatsoever — and `--help` is opt-in, so
fixing the text alone would not surface it. Added the same banner to the
shared CLI path, gated on `is_async_subagents_available()`: ensure_langgraph_dev
fails soft (async degrades to in-process delegation), and warning about a
bind that never happened would be worse than staying quiet.
READMEs (EN + zh-CN) get the same correction — the warning block sat inside
the Desktop WebUI section and read as WebUI-scoped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(deploy): strip the config-derived bind host, not just the CLI one
`deploy()` only stripped the `--host` branch. When the flag was omitted,
`getattr(config, "langgraph_dev_host", ...)` flowed unstripped into
`_is_port_occupied`, `is_langgraph_dev_running`, `start_langgraph_dev` and
the banner. `run_webui` already strips unconditionally; this aligns the two.
Reachable because `deploy()` reads through `getattr` and is routinely handed
duck-typed config objects (tests, embedders) that never run
`EvoScientistConfig.__post_init__`, which is what normally normalizes these
fields.
Worst case was not just a bad bind: `_is_loopback_host(" 127.0.0.1 ")` is
False, so a padded loopback value would print a false PUBLIC BIND warning
while binding a string socket.bind() rejects outright — a security banner
saying the opposite of the truth.
Three regression tests added, each verified to fail against the old code.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* style: apply ruff format to the bind-host changes
The Lint workflow runs both `ruff check` and `ruff format --check`; I had
only been running the former locally, so five files landed unformatted and
failed CI. Whitespace and line-wrapping only — no semantic change.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(security): keep the langgraph dev backend on loopback by default
The backend is an unauthenticated API whose agent can run shell commands,
and it is auto-started in every UI mode (tui/cli/webui/serve/deploy) — so a
0.0.0.0 default put it on the network for users who never asked. Restore
127.0.0.1 as the default and make 0.0.0.0 an explicit opt-in.
webui_host keeps its 0.0.0.0 default: the front-end serves the app shell
only and holds no credentials. run_webui already prints a remote-backend
hint when the front-end is exposed and the backend is not.
Help text and both READMEs are reframed around widening rather than
narrowing; the escape-hatch tests are inverted to assert the public-bind
opt-in survives into argv.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* fix: add support for new Anthropic models and enhance adaptive thinking tests
* fix: implement patches for Anthropic protocol to handle foreign reasoning blocks and structured output for mandatory-thinking Kimi models
* fix: update version to v0.2.4 in badges, README, and project files
* fix: update Star History chart links in README and README.zh-CN
* fix: add support for Gemini 3.6 Flash and 3.5 Flash Lite models in model entries and update changelog
* fix: update wechat group image in assets
- Ensure 'task' is excluded from the default PTC allowlist to prevent ValueError in langchain-quickjs >=0.3.
- Verify that essential async dispatch tools remain in the allowlist.
- Confirm that the live quickjs filter accepts the default allowlist even with a 'task' tool present.
- Test the creation of the code_interpreter middleware to ensure it builds correctly.
* ci: add windows-latest to test matrix + fix 11 cross-platform test bugs
The test workflow ran on ``ubuntu-latest`` only. Per the issue's
first bullet — the maintainer's explicit #1 priority — add
``windows-latest`` to the matrix so the manager and related
modules are exercised on Windows on every PR.
The matrix addition surfaces 18 pre-existing Windows-only test
failures. Without fixes the new leg would be 18+ reds from
day one and the matrix would just produce a wall of
``fail-fast`` noise. This PR fixes 11 of them; each fix is
a real (cross-platform) bug, not a Windows-specific hack —
most were already flagged by CodeRabbit on PR #236 but never
acted on. The remaining 4 failures need code refactors
(``os.killpg`` → ``psutil`` in ``background.py``,
``convert_virtual_paths_in_command`` Windows-aware quoting,
tilde expansion) that are documented as out-of-scope
follow-ups below.
## What changed
* ``.github/workflows/test.yml``
- ``os: [ubuntu-latest, windows-latest]`` → 2 OS × 2 Python
= 4 cells.
- ``fail-fast: false`` so one bad cell doesn't cancel the
rest while the Windows leg is being brought up. Removable
in a future PR once the suite is fully green.
* ``tests/test_backends.py``
- Hard-coded ``"python3"`` → ``{sys.executable}`` in 7
test commands. Windows has no ``python3`` on PATH; using
``sys.executable`` is portable and matches what CodeRabbit
flagged on PR #236.
- Strict string comparisons → ``shlex.split`` round-trip in
5 resolver tests. ``shlex.quote`` adds single quotes
around backslash paths on Windows, which broke the
direct ``==`` compare.
- Cross-platform suffix checks in 2 path-resolution tests
(``Path(resolved).parts[-2:]`` instead of
``str(resolved).endswith("src/main.py")``).
- ``mkdir -p`` → ``sys.executable -c "import os;
os.makedirs(...)"`` in the cwd-sanitization test.
- ``skipif(sys.platform == "win32")`` on 3 e2e tests that
hit the underlying ``shlex.quote`` + ``cmd.exe`` quoting
bug (real, separate issue).
* ``tests/test_sessions.py``
- ``test_uses_data_dir``: check ``.evoscientist`` in the
long path form (via ``Path.resolve()``) rather than the
short-path form ``get_db_path`` returns on Windows.
* ``tests/test_mcp_client.py``
- ``endswith("python")`` → ``Path(result).stem.lower()`` so
``python.EXE`` matches on Windows.
- ``endswith("npx")`` also accepts ``npx.cmd`` so the npm
shim on Windows matches.
## Out of scope (follow-up issues to file)
* ``os.killpg`` doesn't exist on Windows
(``EvoScientist/background.py:248``) — 3 background tests
fail. Real fix is the same ``psutil`` walk pattern PR #200
shipped in ``langgraph_dev/manager.py``.
* Tilde expansion in file mentions.
* Windows-aware shell quoting in
``convert_virtual_paths_in_command``.
* Path conventions (``~/.config/evoscientist/`` vs
``%APPDATA%\EvoScientist``) — needs design discussion +
``platformdirs`` migration.
* Cross-module audit of
``EvoScientist/tools/execute.py``,
``EvoScientist/ccproxy_manager.py``,
``EvoScientist/config/onboard.py``.
Closes#207 (step 1 only — CI matrix + the easy test
fixes; remaining bullets tracked separately).
* fix: cross-platform compatibility for Windows CI runners
- background.py: replace POSIX-only os.killpg/os.getpgid with
cross-platform _kill_process_tree() helper. On Windows falls back
to Popen.terminate()/Popen.kill() (TerminateProcess); on POSIX
keeps existing os.killpg logic.
- test_backends.py: replace mkdir -p shell execution in
test_literal_workspace_path_replaced with preprocessing-boundary
assertion (patch LocalShellBackend.execute, capture command,
assert workspace path was rewritten to ./). Avoids POSIX-only
mkdir -p on Windows runners.
- test_file_mentions.py: monkeypatch USERPROFILE on Windows so
ntpath.expanduser() resolves ~ to tmp_path even when HOME is
unset on CI runners.
* fix(test): cross-platform sleep/true commands for Windows CI
Replace POSIX-only sleep/true with module-level helpers that use
ping -n / cmd /c on Windows. Also fix python3 -> sys.executable
in the non-timeout recovery test.
- test_background.py: 7 sleep/true fixes
- test_background_middleware.py: 6 sleep/true fixes
- test_backends.py: 4 sleep fixes + 1 python3 fix
2318 passed, 0 failed on Windows.
* fix(test): use shell-portable double quotes for python -c on Windows
cmd.exe does not treat single quotes as string delimiters, so
-c 'raise SystemExit(1)' was passed with literal quotes on Windows.
Switch to double quotes which work on both cmd.exe and POSIX sh.
* fix: use psutil for Windows process tree kill + avoid sys.executable under uv
- background.py: replace Popen.terminate()/kill() with psutil-based
process tree walking on Windows. TerminateProcess does NOT cascade
to grandchildren; psutil.Process.children(recursive=True) ensures
the entire tree is signaled.
- test_backends.py: replace sys.executable with 'python' in sandbox
execute() calls. Under uv, sys.executable is under the workspace
and gets rewritten to ./ by prepare_sandbox_command, breaking
Linux CI. The plain 'python' command resolves correctly in any
activated venv.
* fix: broaden try/except in _kill_process_tree to cover proc.children()
If the process exits between Process(popen.pid) and children(recursive=True),
the children call raises an uncaught exception escaping stop(). Move it inside
the existing try/except block.
* fix: narrow exception to ProcessLookupError in POSIX _kill_process_tree
OSError is too broad — would silently swallow EPERM on SIGKILL, leaving
the process alive when we report it as stopped. Match original behavior
which only caught ProcessLookupError (process already gone).
* style: ruff format test_backends.py
* ci: trigger re-run for flaky prompt_toolkit test
* style: fix ruff check (import order + RUF005 unpacking)
---------
Co-authored-by: Xi Zhang <106144707+X-iZhang@users.noreply.github.com>
* feat(middleware): reposition code interpreter middleware in the stack
* feat(models): add qwen3.7-plus model entry and update context window comment
* feat(models): add qwen3.7-max and qwen3.7-plus model entries for DashScope
* feat(auxiliary): implement auxiliary model support for background tasks and tool selection
- Added auxiliary model configuration to EvoScientistConfig.
- Introduced _ensure_auxiliary_chat_model function to manage auxiliary model instances.
- Updated onboarding steps to include auxiliary model selection.
- Modified middleware to route tool selection to the auxiliary model when applicable.
- Enhanced tests to cover auxiliary model functionality and configuration.
* feat(steps): update UI backend selection options and descriptions
* Refactor code structure for improved readability and maintainability
* feat(patches): implement OpenRouter response reasoning item stripping to prevent multi-turn errors
* feat: update version to v0.1.4 in badges, README, and pyproject.toml; adjust skill counts in steps.py
* feat(config): add auxiliary model and provider environment variables to test setup
* feat(docker): official image with all runtime deps pre-installed
Multi-stage build using uv for the EvoScientist core + all messaging-channel
extras, plus Node.js 24 LTS (for npx-based MCP servers) and uv (for runtime
Python MCP installs) in the runtime layer. Runs as non-root user evosci,
with workspace, app data, and config (XDG_CONFIG_HOME) all consolidated
under a single /home/evosci/.evoscientist volume so a single mount
persists everything across container restarts.
Includes a docker-compose.yml starter, a build/push GitHub Actions
workflow targeting ghcr.io with multi-arch (amd64/arm64) and PR-only
build verification, a .dockerignore, and a new Docker section in the
README documenting mounts, derivation recipes for the unbundled stt /
oauth / TinyTeX extras, and proxy/cert handling expectations.
* fix(docker): pin trixie base + drop redundant python image
Switch builder and runtime from `python:3.11-slim-bookworm` to a single
`ghcr.io/astral-sh/uv:python3.11-trixie-slim` base — trixie drops several
CRITICAL vulnerabilities that bookworm carries today, and reusing the uv
image for runtime eliminates the separate `COPY --from=…/uv` line.
* chore(docker): pin GitHub Actions to commit SHAs in workflow
Replace mutable major-version tags with full commit SHAs (with the
corresponding semver tag in a trailing comment) so a compromised /
retagged action release can't silently change what runs in the publish
pipeline.
* chore(deps): enable Dependabot version updates for Dockerfile pins
Adds a weekly `docker` ecosystem that watches the Dockerfile's `FROM` /
`COPY --from=` references — including the ARG-bound `BASE_IMAGE` and
`NODE_IMAGE` digests — and opens one grouped PR per cadence bumping
both the @sha256 digest and the trailing version comment. This keeps
the otherwise-frozen pins flowing with Debian point releases and
upstream patches.
* fix(docker): use nodejs alias stage so NODE_IMAGE ARG actually resolves
`COPY --from=${NODE_IMAGE}` left the dollar-curly literal at parse time
under buildkit 29.x — it expands ARGs in `FROM` but reads `--from=` as a
static stage/image name. Introduce a tiny `FROM ${NODE_IMAGE} AS nodejs`
alias and `COPY --from=nodejs …` against it, which preserves the
ARG-driven Dependabot updates without tripping the parser.
* fix(docker): harden venv ownership and PATH ordering
- Drop `--chown` on the `/opt/venv` COPY so the venv stays root-owned.
The runtime user only needs read+execute (default Unix perms allow
that); making it user-owned let the agent rewrite its own
dependencies, which defeats the sandboxing premise. All persistent
agent state already lives under /home/evosci/.evoscientist/.
- Reorder PATH so /opt/venv/bin precedes the user-writable
UV_TOOL_BIN_DIR. Otherwise a stray binary dropped into the latter
(e.g. via `uv tool install`) could shadow the canonical
`evosci` / `python` / `pip` shipped with the image.
* docs: update README
* docs(docker): warn about non-root UID and `curl | sh` for derived images
- The image runs as `evosci` (UID 1000), so a host-side `./workspace`
bind mount fails if the host user has a different UID — same gotcha
that bites onboarding's `mcp.yaml` write. Add an !IMPORTANT block
with the two practical fixes (`chown -R 1000:1000` once, or
`--user "$(id -u):$(id -g)"` on each run).
- The TinyTeX derivation snippet pipes an unpinned remote installer
into `sh`. Add a one-line pointer to fetching a pinned release
tarball from `rstudio/tinytex-releases` for users who'd rather not
trust the upstream script blindly. The official installer is kept
as the default since that's what TinyTeX itself recommends.
* chore(docker): cancel in-flight workflow runs + flag iMessage as host-only
- Add `concurrency: cancel-in-progress: true` to the docker workflow
so successive pushes on the same ref supersede the prior run rather
than queueing in parallel — multi-arch buildx is the slowest job in
CI, no point burning minutes on superseded builds.
- Spell out that the docker image installs the `all-chanels` extra and
call out iMessage as a deliberate host-only exclusion: it requires
the `imsg` CLI bridging to macOS's Messages.app, which no Linux
container config can satisfy.
* chore(release): update version to v0.0.8 and dependencies in project files
* feat(models): add new model entries for Claude Opus 4-7 and update version handling
* Refactor code structure for improved readability and maintainability
* chore(assets): update wechat_group image file
* Refactor code structure for improved readability and maintainability
* feat(backends): enhance MergedReadOnlyBackend with improved ls, grep, and glob methods
* fix(docs): update WeChat QR code image link in README files
* feat(skills): enhance skill management to support global and workspace tiers
* style: apply ruff format to skills_cmd and commands/implementation/skills
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(skills): improve uninstall_skill to prevent removal of built-in skills
* fix(docs): update skill installation documentation for clarity on global and user directories
* fix(skills): enhance uninstall_skill to validate skill directory before removal
* fix(skills): improve error handling in install_skill and uninstall_skill for directory creation and validation
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: update OpenRouter API key validation to use /auth/key endpoint and httpx
* Refactor code structure for improved readability and maintainability
* feat: enhance welcome banner to include file commands indication
* feat: update LaTeX setup prompt to use selection UI for better user experience
* feat: update version to v0.0.5 in badges and project configuration
* feat(tui): enhance conversation history rendering and implement two-level thread hierarchy in picker
* feat(tui): improve conversation history display and enhance thread selection UI
* feat(file_mentions): implement @file mention parsing and completion for CLI and TUI
* feat(uv-tool): add compatibility checks and installation helpers for uv tool environments
* feat(dependencies): update package versions in uv.lock for compatibility and improvements
* feat(badges): update PyPI version to v0.0.4 in SVG assets and README files
* feat(tests): format code in TestUvToolCompat for improved readability
* feat: implement background update check and startup notifications
* feat: enhance user experience with timestamp notifications and UI polish
* feat: implement multi-line chat input with Enter-to-submit and modifier+Enter newline
* update
* update
* v0.0.3
* feat: improve code readability with consistent formatting in TUI and test files
* feat: update PyPI badge version to v0.0.3 in README files
* feat: add docstrings for test classes in test_update_check.py
* feat(cli): add --version / -V flag
Uses importlib.metadata to read the version from the installed package.
* chore: improve bug report and feature request issue templates
- Bug report: replace web-app steps with CLI-oriented examples, add
error output section, add Python version and LLM provider fields
- Feature request: add note directing niche features to EvoSkills,
set default label
* chore: add documentation issue template and issue chooser config
- Add documentation template for reporting missing or unclear docs
- Add config.yml to disable blank issues and link to EvoSkills and
Discord as contact options
* chore: add PR template and improve CONTRIBUTING.md
- Add PR template with type-of-change checkboxes, issue linking for
new features, and CI checklist
- CONTRIBUTING.md: add development setup, PR workflow, and code style
sections; fix wording; make Discord link clickable