Commit Graph
143 Commits
Author SHA1 Message Date
nesquena-hermes 728472cacb Merge PR #7814 (@happy5318): Chinese remote-access guide 2026-09-26 05:06:30 +00:00
nesquena-hermes f6b59fd183 Merge branch 'master' into codex/docs-tailscale-serve 2026-09-25 21:56:31 -07:00
happy5318 c13a2ecf64 docs(zh): align Windows sections with start.ps1 / WSL-only autostart
Review feedback (nesquena 9/24, PR #7814):

1. §三.1 "首次准备" 原本让用户在 WebUI 仓库本地 `python -m venv venv`
   再 `pip install -r requirements.txt`,但 `start.ps1`(line 132-136)
   启动时优先用 `<hermes-agent>\venv\Scripts\python.exe`,找不到才
   回退到 PATH 上的 `python`——WebUI 本地的 venv 永远不会被它挑中。
   照原指南装的依赖会变成死代码,启动时仍然缺包。重写为:要求把
   requirements.txt 装进 hermes-agent 的 venv,列出 hermes-agent 的
   常见安装位置,保留 WebUI 本地 venv 作备选但明确警告。

2. §三.4 之前是 "Windows 开机自启",但内容(setup_webui_autostart.ps1
   → wsl.exe → scripts/wsl/hermes_webui_autostart.sh)实际上**只**
   启动 WSL 里的 WebUI,放在 native-Windows 章节里会误导用户以为
   native 启动也有自启配套。把它从 §三 抽出,单独成节
   "## 四、WSL 用户:Windows 开机自启",顶部加 WSL-only 提示,
   §四/§五 顺延为 §五/§六,FAQ 里的 cross-ref 同步更新,README
   中文链接文案改为 "...Windows 原生部署(自启仅适用 WSL 用户)"
   不再暗示 native 自启。

3. 顺手处理两条可选小项:

   a. start.sh / start.ps1 / bootstrap.py 都会从仓库 .env 加载
      `HERMES_WEBUI_PASSWORD`,且 .env 里的值**覆盖**命令行内联
      的 env var。在 §三.2 加 callout 提示:改完密码后打开登录页
      确认真的要求输入密码;如未生效就清 .env 或显式
      `HERMES_WEBUI_PRESERVE_ENV=1`。

   b. §六.1 "Tailscale 私有" 原写法 "仅你的 tailnet 设备可达" 在
      方案 B(`HERMES_WEBUI_HOST=0.0.0.0`)下不成立——`0.0.0.0`
      绑的是所有接口,"仅 tailnet" 完全靠防火墙那条
      `100.64.0.0/10` 规则兜底。改为:首选 `HERMES_WEBUI_HOST=
      $(tailscale ip -4)`(只绑 Tailscale 网卡,更严),次选
      `0.0.0.0` + 防火墙,并明确标注"防火墙被改/被关就立刻
      对 LAN/公网开放"。

保留 24dd1fbd 的 public-exposure note 修正。
2026-09-26 01:39:24 +08:00
xiaobao a77956fcfd docs(zh): add Chinese remote-access guide (Tailscale, SSH tunnel, native Windows)
Companion to docs/remote-access.md for Chinese users, per the
contribution shape requested in #7393:

- Tailscale Serve preferred path (loopback + HTTPS MagicDNS), direct
  tailnet IP as fallback, SSH tunnel section
- Native Windows deployment via the official start.ps1 launcher with
  password auth; firewall rule scoped to the Tailscale CGNAT range
  (100.64.0.0/10) instead of an all-interfaces open
- Windows logon auto-start via the official
  scripts/windows/setup_webui_autostart.ps1 scheduled-task helper
- Explicit security boundary section distinguishing tailnet-private,
  LAN, and public exposure
- No machine-specific usernames/drives/model choices/popularity numbers
- Linked from the README docs index

Tests: test_readme_compat_section, test_issue3012_3006_docker_docs,
test_nix_flake_module_source all pass (17/17).
2026-09-25 02:37:52 +08:00
nesquena-hermes 10faa69155 Merge PR #6746 from happy5318/fix/mobile-enter-newline 2026-09-24 08:05:12 +00:00
happy5318 bbebe23f7e fix(mobile): preserve tablet hardware-keyboard Enter behavior 2026-09-24 15:26:06 +08:00
nesquena-hermes a1b3c068f7 docs: document HERMES_WEBUI_SETTINGS_FILE (#6433) incl. restart-to-change note 2026-09-24 03:15:28 +00:00
nesquena-hermes 1c4072228e Merge PR #7493 into stage/0924-a 2026-09-24 03:15:02 +00:00
carlotestor 35921eccbb fix(sidebar): scope project inheritance to subagents, resolve lineages once
Forks and other child sessions keep their own project_id, so a fork moved to
No project stays Unassigned. A per-render memoized, cycle-safe resolver is
shared by partitioning, reference scoping and the Unassigned chip.
2026-09-23 15:28:47 +00:00
carlotestor 35c9b8ae96 fix(sidebar): Unassigned chip resolves child projects through reference rows
The chip check now reuses the ancestor map built by _partitionSidebarSessionRows,
so a child whose project parent is only a hidden reference row is not counted
as unassigned. Document project inheritance for subagent sessions in README.
2026-09-23 12:59:36 +00:00
carlotestor 5c24458dff fix(sidebar): derive the route session cap from the shared limit
The env override never reached /api/sessions because the route kept a
separate hard-coded cap of 20. Resolve the window in api.config before
profile init, clamp it at 200, and refuse a profile .env override.
2026-09-22 17:50:56 +00:00
carlotestor 899b89e1d3 docs+test: document HERMES_WEBUI_VISIBLE_SESSION_LIMIT; probe it in a subprocess
- README env table + .env.example gain the new setting (default 20, fallback
  semantics), pinned by test_setting_is_documented.
- tests/test_visible_session_limit_env.py no longer importlib.reload()s
  api.models in the shared pytest process (which recreated its module-level
  locks/caches/classes behind other modules' backs); each case now imports
  api.models in a fresh interpreter with a scrubbed env, matching
  test_issue3283_profiles_config_import_order.
2026-09-20 11:19:41 +00:00
CharlesMcquade 6f593f80e8 fix(notifications): preserve prompt owners through lifecycle exits 2026-09-14 18:21:54 -05:00
taljeon 270832cf4c docs: bound Serve to restricted tailnets 2026-09-04 13:52:45 +09:00
taljeon c45ee592f2 docs: make Serve the canonical remote entry point 2026-09-04 13:42:54 +09:00
dcb515611d Release — SSE Last-Event-ID resumption fix (#6886) (#7129)
* fix(sse): scope gateway SSE probe and honor Last-Event-ID on /api/chat/stream

Two narrowly-scoped cross-client SSE fixes from the hermes-android#58
follow-up:

1. The /api/sessions/gateway/stream?probe=1 response only describes the
   optional gateway/agent-sessions stream, but its payload gave clients no
   way to tell that. A 404 'agent sessions not enabled' result could be
   misread as SSE being unsupported server-wide, even though the persistent
   per-session stream (/api/session/stream) is always on and independent of
   the show_cli_sessions setting. Add additive scope markers to the probe
   payload (scope, session_stream_available, session_stream_path) and
   clarify the handler docstring.

2. /api/chat/stream emitted id: stream_id:seq on every journaled event
   but ignored the Last-Event-ID request header, so any spec-compliant SSE
   client that auto-reconnects (browser EventSource, Android/CLI clients)
   replayed the journal from seq 0 and double-rendered the transcript.
   _chat_stream_resume_after_seq() now resolves the resume cursor with
   explicit after_event_id/after_seq query params first and the
   Last-Event-ID header as fallback — the same resolution chain
   api/kanban_bridge.py already uses. Both the dead-stream journal replay
   and the live-subscribe gap check consume it; direct callers of the gap
   check that only pass query params keep historical behavior.

Also documents the cross-client SSE endpoint contract in
docs/sse-streams.md.

Related hermes-webui/hermes-android#58

* fix(sse): split cursor presence from validity on /api/chat/stream resume

Address PR #6886 review (gate-fail): the resume logic conflated "no
cursor" with "invalid cursor" into a single None, which broke replay on
three edges. Root cause and fix:

Cursor presence vs validity — _chat_stream_resume_cursor() now returns
(after_seq, resume_requested) instead of a bare seq. A client that
SUPPLIED any cursor (query params, replay=1, or Last-Event-ID) asked to
resume; an invalid / foreign-run / unparseable cursor resolves to
after_seq=None but keeps resume_requested=True, and is normalized to
replay-from-start so no journal events are silently skipped. A genuinely
cursor-less request stays a fresh subscribe.

1. Explicit-query precedence is now decided by parameter PRESENCE, not
   successful parsing: a malformed/foreign after_event_id/after_seq never
   falls through to let the Last-Event-ID header override it and skip
   events.
2. Invalid/foreign cursors no longer bypass replay + gap detection and
   silently drain a truncated buffer; an ahead-of-stream cursor is no
   longer clamped onto the snapshot's terminal fence (which emptied the
   dead-stream replay by filtering the terminal frame).
3. The runner-local observe path now receives the resolved header cursor
   (retaining explicit-query precedence) so header-only runner reconnects
   resume instead of duplicating events from the start.

Regression tests cover invalid-cursor replay-from-start, ahead-of-stream
terminal survival, header-only runner reconnect, and explicit-query
precedence; the stale clamp test is updated to the corrected contract.

Related hermes-webui/hermes-android#58

* fix(sse): consume resolved resume cursor at every consumer on /api/chat/stream

Address PR #6886 r2 review (gate-fail). The r1 presence/validity split
fixed the entry resolution, but the individual consumers still re-derived
ahead/equality/re-parse decisions, so the invariant leaked at the edges.
This makes every consumer honor the resolved (after_seq, resume_requested)
pair and normalizes ahead-of-stream in one place.

1. Equality off-by-one: a valid cursor EQUAL to the snapshot cutoff now
   enters the drain dedup bound (the event at the cursor was already
   delivered), instead of being treated as "ahead" and double-sending the
   retained buffer. Ahead is now strictly after_seq > snapshot_cutoff_seq.
2. Numeric ahead-of-stream cursors are normalized to replay-from-start:
   on the active path, after_seq > snapshot_cutoff_seq resets to 0 before
   gap-coverage/replay so a truncated buffer can no longer falsely declare
   coverage and lose the pre-tail events; on the dead-stream path the
   cursor is normalized against the journal summary's authoritative
   last_seq before _replay_run_journal, so an ahead cursor returns the
   full replay instead of an empty SSE body.
3. Runner-local now consumes the resolved cursor instead of re-parsing
   after_event_id or re-reading Last-Event-ID. The resolver also returns
   the opaque raw cursor so the runner uses the already-precedence-checked
   value; explicit opaque cursor= keeps precedence, invalid/foreign
   cursors pass no cursor (full replay), and the header is honored only
   when no explicit cursor was supplied.

Regression tests cover the equality dedup, active+dead ahead-of-stream
normalization (with after_seq-filtering mocks that assert the real replay
body), and the three runner precedence probes (malformed-explicit blocks
header, foreign passes no cursor, opaque cursor= wins).

Related hermes-webui/hermes-android#58

* fix(sse): carry runner-cursor provenance through /api/chat/stream resume

Address PR #6886 r3 review (gate-fail). The (after_seq, resume_requested,
raw_cursor) tuple carried the cursor VALUE but not its PROVENANCE, so the
runner handoff couldn't distinguish a valid opaque runner cursor from a
journal-shaped one from a malformed one — and gated the runner handoff on
journal-specific validity, which is wrong for the runner adapter (its
cursors are opaque).

The resolver now returns a distinct, centrally-resolved runner cursor:

- a valid after_seq PAIRS with whatever after_event_id shape was supplied
  — including an opaque runner id like event:2 that the journal parser
  reads as a foreign run — so the paired runner cursor resumes at the seq
  (never None / full replay, which would duplicate tokens and tool
  events). after_seq is read directly (via _parse_run_journal_after_seq_value)
  rather than through the after_event_id-first journal parser, which would
  swallow a paired opaque runner id.
- a header-only opaque runner id (Last-Event-ID: event:2) is preserved
  as-is so the runner resumes from it.
- a malformed or foreign explicit cursor WITHOUT a valid paired after_seq
  still yields no runner cursor, blocking Last-Event-ID and replaying from
  start — the r2 malformed-blocks-header guarantee is unchanged.

Regression tests pin the paired opaque id, header-only opaque id, and
malformed-with-valid-seq runner resumes, plus the unchanged
malformed-without-pair replay-from-start behavior.

Related hermes-webui/hermes-android#58

* fix(sse): normalize ahead cursor when the snapshot cutoff is unknown

Address PR #6886 r4 review (gate-fail). The ahead-cursor normalization
was guarded by `snapshot_cutoff_seq is not None`, so when the subscribe
snapshot had no parseable last_event_id (channel has not seen an
id-bearing frame yet), a positive ahead cursor (e.g. Last-Event-ID
run_1:999) was never normalized — it was installed verbatim as the live
dedup bound, filtering EVERY queued frame including the terminal
stream_end fence. The reconnect stalled on heartbeats with an empty SSE
body. origin/master ignored the header on this path and delivered the
events, so this was a new regression.

Fix: treat an unknown, non-truncated snapshot cutoff as fence 0 before
the ahead-cursor normalization, so a positive client cursor can't become
the live dedup bound with no cutoff to bound it — it fails closed to
replay-from-start, delivering the buffered events rather than silently
losing them. Frames dropped while the cutoff is unknown still cannot
prove gap coverage (cutoff None → not covered), so the recovery_control
fail-closed path is preserved.

Regression test: Last-Event-ID run_1:999 + snapshot_cutoff_seq=None
delivers queued events run_1:1 and run_1:2 exactly once, emits the
terminal stream_end, and releases the subscriber. Without the fix the
test stalls on heartbeats (pytest-timeout kills it), proving the stall.

Related hermes-webui/hermes-android#58

* Release — SSE Last-Event-ID resumption fix (#6886)

---------

Co-authored-by: Paladin173 <35980893+Paladin173@users.noreply.github.com>
Co-authored-by: n <a@n>
2026-08-18 15:08:14 +00:00
MHJ e4c3c728d9 fix(commands): wait for bundle metadata before skill suggestions 2026-08-12 00:32:57 +09:00
a725a0f71c Release p1-batch: session cache cap 300→100 (#6362) + virtualization comment (#6318) (#6375)
* perf(transcript): enable DOM virtualization by default (re-enable #4346 fix) (#6151) (#6155)

* fix: revert DOM virtualization default to opt-in, fix gate RED (#6155)

* fix(#6351): lower default session cache cap

* Release p1-batch: session cache cap 300->100 (#6362) + virtualization comment (#6318)

---------

Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
Co-authored-by: webtecnica <webtecnica@users.noreply.github.com>
Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-07-21 02:53:43 +00:00
98a67ee6cf Release: pip-installable packaging metadata (#6337, @rodboev) (#6344)
* build(#2695): add packaging metadata for the current runtime layout

* docs(changelog): stamp #6337 pip-installable packaging metadata

---------

Co-authored-by: Rod Boev <rod.boev@gmail.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-07-20 02:17:52 +00:00
Rod Boev 9bd96fb75d fix(#2422): support packaged Hermes Agent discovery 2026-07-14 01:06:49 +00:00
Rod Boev b7f523c3a1 fix(#2422): tighten Nix module polish 2026-07-14 01:06:49 +00:00
Rod Boev 72b51a6b78 fix(#2422): avoid hardcoded agent site packages 2026-07-14 01:06:49 +00:00
Rod Boev 70514549c4 fix(#2422): harden NixOS packaged runtime 2026-07-14 01:06:49 +00:00
Rod Boev 5bd940a49b fix(#2422): honor the service-mode host default 2026-07-14 01:06:48 +00:00
Rod Boev 09003b5e92 feat(#2422): add Nix flake package and NixOS module 2026-07-14 01:06:48 +00:00
Jaret Bottoms 2844a5ad31 no-mistakes(document): Document profile-scoped cron unread alerts 🔧🟠 2026-07-12 19:20:53 +00:00
nesquena-hermes e061e8534c Rebase #5337 (public read-only conversation sharing) onto master
Rebased 363 commits forward (branch-point 2026-07-05). Applied the PR's code
diff cleanly across 16 files; resolved api/models.py additively (both master's
process_wakeup_pause/anchor_scene_index fields AND the PR's share_token/
share_created_at fields kept in the Session constructor, metadata list, and
to_dict). CI workflow (.github/workflows/tests.yml) intentionally NOT taken from
the stale branch — master owns it (the branch's apparent removal of Playwright/
Office steps was a PAT-workflow-scope revert; rebase restores master's CI).

Co-authored-by: MicoRobot. Concept approved by maintainer (opt-in public share,
2026-07-11). Note: 4 dynamic share tests fail identically on the original
unrebased head (pre-existing test-env Session.load fragility, not rebase-caused);
to be resolved during the security re-gate in a proper sandbox.
2026-07-11 01:39:42 +00:00
Nathan Esquenazi 264a9eab29 Update the screenshot (#5816) 2026-07-08 23:03:20 -07:00
nesquena-hermes 8a7d3eb6c2 Merge PR #5673 into stage 2026-07-06 17:04:53 +00:00
nesquena-hermes 26a829c952 docs: weekly contributor tally refresh (20260706) (#5689) 2026-07-06 09:29:07 -07:00
Rod Boev cdcb31a948 docs(#2781): document proxy auth PWA update caveat 2026-07-06 04:41:45 -04:00
mo7al876anyandClaude Fable 5 3b56cc9629 docs: refresh stale version/test-count/locale numbers
- Version stamps v0.51.192/v0.50.281 → v0.51.792 (Jul 1) in the factual
  header lines (ROADMAP/ARCHITECTURE/SPRINTS/TESTING); curated narrative
  left untouched
- Test counts: the ~7,150 approximates and leftover absolute 5303/488 and
  3995 figures → ~11,500 tests / ~1,150 files (matches --collect-only)
- Locales: 9 → 14 (add Italian, Turkish, Polish, Vietnamese) in ROADMAP;
  '11 languages' → 14 in TESTING

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 16:04:23 +03:00
nesquena-hermes 6caaced8eb fix(webui): bound in-memory SESSIONS cache with lazy reload (#4765)
Root cause of the silent-crash-after-hours cluster (#4765/#2233/#4633): the
global in-memory SESSIONS LRU evicted with a blind popitem(last=False), which
could drop an actively streaming or not-yet-persisted session (data loss) and
was capped only via an env var. On long-running installs the effective result
was unbounded RAM growth until segfault.

- Add _session_is_evictable(): a session is evictable ONLY when it is not
  streaming (no active_stream_id), has no in-flight turn (no pending_user_message
  / pending_started_at), and its full state is proven on disk (sidecar
  message_count >= in-memory count; metadata-only stubs and zero-message shells
  are trivially safe).
- Add _evict_sessions_over_cap(): replaces all 8 blind popitem loops across
  models.py, routes.py, streaming.py. Walks the LRU oldest-first and removes only
  provably-safe entries; never acquires LOCK/stream locks itself (caller holds
  LOCK) so no lock-ordering deadlock. May briefly exceed the cap rather than ever
  evict an active/unsaved session.
- Make the cap configurable via config.yaml webui.sessions_cache_max
  (get_sessions_cache_max()); precedence config.yaml -> HERMES_WEBUI_SESSIONS_MAX
  (legacy) -> DEFAULT_SESSIONS_CACHE_MAX=300. No new HERMES_* env var. Invalid or
  <1 values fall back so a typo can never disable the bound.
- Evicted sessions lazily reload from their JSON sidecar via the existing
  get_session() accessor; no call sites changed. _index.json sidebar behavior
  unchanged (the sidebar reads the index, not SESSIONS).
- Add tests/test_issue4765_sessions_lru_eviction.py (8 tests): eviction past
  cap, active/streaming never evicted, unsaved/stale-tail never evicted, lazy
  reload with identical content, and no-data-loss under heavy churn.
- README: document the config.yaml key + safety semantics.

Fixes #4765.
2026-07-01 18:14:39 +00:00
Rod Boev f7a9c98810 fix(auth): harden OIDC key selection and startup guidance (#3825) 2026-06-29 22:28:53 -04:00
nesquena-hermesandnesquena-hermes 8cee867f19 docs: weekly contributor tally refresh (20260629) (#5214)
Regenerated by scripts/regen_contributors.py --apply (markers spliced, prose
untouched, --verify clean). 304 contributors / 1771 credits.

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
2026-06-29 09:18:11 -07:00
sr-dotcom ec14a78320 fix(quickstart): clarify HERMES_WEBUI_CHAT_BACKEND=gateway is available today
The previous wording implied external gateway routing was not yet possible.
HERMES_WEBUI_CHAT_BACKEND=gateway already ships; updated wording distinguishes
it from full agent-loop delegation, which is not yet shipped and tracked in #1925.
2026-06-26 21:29:02 +00:00
sr-dotcom 620b794770 docs(quickstart): clarify WebUI runs the agent in-process, not via an external API server
HERMES_API_URL is only read by the Tasks/cron health probe (api/agent_health.py)
and does not route chat. Adds a plain-language note to Quick Start with the two
supported options for users who run an external endpoint. Closes #3873.
2026-06-26 21:29:02 +00:00
nesquena-hermes d61a67b258 docs: weekly contributor tally refresh (20260622) (#4710) 2026-06-22 10:32:31 -07:00
nesquena-hermes 8f3f6ea67a stage #4593 onto master (v0.51.550) — document extension sidecar CSP support + CSP test coverage
santastabber: docs (README + EXTENSIONS.md) clarifying extension sidecar CSP behavior +
test_issue1909_csp_enforcement / test_issue2901_csp_connect_extra assertions. Docs+tests only, no
prod code. Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 07:04:31 +00:00
nesquena-hermes 1b7c1fe619 rebase #4569 onto master (v0.51.547) for ship-gate — extension status diagnostics (#4561 follow-up)
santastabber: authenticated /api/extensions/status endpoint reporting WHY an extension didn't load
(stable codes + coarse sources only, no path/env/URL leak). Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 04:08:44 +00:00
nesquena-hermes 3e229141af stage #4561 + stamp v0.51.545 — extension manifest asset bundles
santastabber. HERMES_WEBUI_EXTENSION_MANIFEST: bundle extension assets via a 64KB JSON manifest
instead of long URL lists. Same same-origin allowlist validator, traversal-guarded manifest path,
default-off. Nathan blessed (richer extension system). Co-authored-by: santastabber <santastabber@users.noreply.github.com>
2026-06-21 00:37:08 +00:00
nesquena-hermes 4d4b11b43c test+docs(#4449): backward-compat state-dir tests + upgrade migration note (Opus gate)
Opus flagged a real upgrade gap on the #4449 state-dir contract folded into
#4454: a deployment that relocated HERMES_HOME to a non-default base WITHOUT
setting HERMES_WEBUI_STATE_DIR sees WebUI state move to $HERMES_HOME/webui on
upgrade (empty app at the new address). Add (1) README note documenting the
move + how to keep the old location, and (2) two backward-compat regression
tests pinning the invariants: HERMES_HOME-unset stays at the platform default
(normal installs don't relocate), and HERMES_WEBUI_STATE_DIR takes precedence.
2026-06-20 00:51:08 +00:00
Rod Boev f086158c10 fix(#2698): keep isolated deployments on their own state and profile roots 2026-06-20 00:48:19 +00:00
nesquena-hermes 580a157ab1 stage #4447: opt-in chunked SSE for buffering proxies (#4447) + v0.51.524 CHANGELOG 2026-06-19 22:09:17 +00:00
26f54b9972 docs: weekly contributor tally refresh + cherry-pick credit accuracy fix (#4473)
* docs: weekly contributor tally refresh (20260619)

Regenerated by scripts/regen_contributors.py --apply. Includes the source (e)/(f)
ship-signal accuracy fix that recovers systematically-undercounted cherry-picked
contributions (~77 contributors). 280 contributors / 1559 credits (was 263/1232).
Markers spliced, prose untouched, --verify clean, 0 double-counts.

* docs: align CONTRIBUTORS header prose with the 5-source credit algorithm

Addresses greptile P2: the header still described the old three-source union
(merged-PR list + CHANGELOG + Co-authored-by) but regen_contributors.py now adds
two more — ship-comment scans and absorb-commit scans — for five total. Updates
the prose to match what the script actually runs.

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-18 22:05:37 -07:00
nesquena-hermes f5f882b1dd docs: fairly count absorbed-but-closed contributor PRs (backfill @Isla-Liu trio) (#4401) 2026-06-17 20:08:08 -07:00
nesquena-hermes 232963791f Merge pull request #4250 from nesquena/contributors-refresh-20260615
docs: weekly contributor tally refresh (20260615)
2026-06-16 09:02:29 -07:00
fadb4fdf32 docs(README): correct server stop instructions — start.sh runs detached, not foreground (#4303) (#4304)
start.sh exec's bootstrap.py without --foreground, which double-forks into a
detached daemon, so it belongs in the 'find PID + kill' row, not the Ctrl-C
foreground row. Docs-only, no version stamp.

Co-authored-by: tomas-forgac

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
2026-06-16 03:40:26 -07:00
e775fb3355 Release OV (v0.51.435): supported local pytest runner (#3908) (#4252)
* stage-3908: supported local pytest runner + symlink-guard on venv create/clear (Codex CORE fix)

Rebased rodboev/franksong2702 #3908 onto v0.51.434. Adds scripts/test.sh dev
runner + requirements-dev.txt + test_ci_hygiene.py + conftest version guard.
Defensive fix on the authoritative gate: create_or_rebuild_venv refuses a
symlinked .venv so 'python -m venv --clear' can't wipe the symlink target
(same symlink-hardening class as #4217/#4234/#4240). Locked by a hygiene test.

* Release OV: supported local pytest runner (#3908)

scripts/test.sh + requirements-dev.txt + conftest version guard + hygiene tests.
Self-rebased franksong2702's #3908 onto v0.51.434; full Codex+Opus+suite gate.
Codex CORE fix applied: refuse to create/--clear a virtualenv through a symlinked
.venv (symlink-hardening class, #4217/#4234/#4240), locked by a hygiene assertion.

Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>

---------

Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
Co-authored-by: franksong2702 <franksong2702@users.noreply.github.com>
2026-06-15 10:25:32 -07:00
3ee2f5d693 docs: refresh contributor tally for v0.51.390 (248 contributors) (#4132)
* docs: refresh contributor tally for v0.51.390 (248 contributors)

Regenerated via scripts/regen_contributors.py after fixing three real
over-counting bugs in the generator (release-vehicle PR# leak, reporter
false-positives, prose-token leakage — see workspace commit). Net:

- 248 contributors / 1092 credits (corrected; the prior generator inflated
  this with ~106 spurious release-vehicle co-author credits + reporter mentions)
- CONTRIBUTORS.md now recognizes 3+ PR contributors in ranked tables and lists
  everyone with 1-2 PRs in a combined roll, so nobody already credited is dropped
- README top-10 snapshot + notable-contribution counts updated to match
  (franksong 180, Michaelyklam 118, rodboev 83 [new], ai-ag2026 75, bergeouss 70)

Every name in the tally is authorship-verified (merged PR, CHANGELOG attribution,
or a Co-authored-by trailer); bug reporters / relayers / confirmers are no longer
miscredited as authors.

* docs: add generated-region markers so the contributor tally regenerates cleanly

Wraps the machine-generated tables in CONTRIBUTORS.md + README.md with
<!-- BEGIN/END GENERATED CONTRIBUTORS --> markers. scripts/regen_contributors.py
--apply now splices fresh tables between them on each run while leaving the
hand-written prose (How credit is tracked, Special thanks, README Notable
contributions) untouched. Verified idempotent: a second --apply is a no-op.
This is what the weekly refresh cron runs.

Tally re-synced to current master: 248 contributors / 1093 credits.

---------

Co-authored-by: nesquena-hermes <nesquena-hermes@users.noreply.github.com>
Co-authored-by: Nathan Esquenazi <nesquena@gmail.com>
2026-06-13 12:18:21 -07:00