Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
358 commits
Select commit Hold shift + click to select a range
4c3a388
fix(discord): widen expired-defer handling to /thread slash command
teknium1 Jul 7, 2026
8ce3c2f
feat(desktop): add UI scale setting to appearance settings
Adolanium Jul 7, 2026
ee66ff2
chore(desktop): drop PR screenshot assets from tree
teknium1 Jul 7, 2026
985e19c
fix(agent): add cross-turn stream-stale circuit breaker (#58962)
necoweb3 Jul 7, 2026
2985d16
fix: reset stream-stale breaker on model switch and fallback activation
kshitijk4poor Jul 7, 2026
437052f
docs: document HERMES_STREAM_STALE_GIVEUP alongside sibling stream knobs
kshitijk4poor Jul 7, 2026
d43863f
fix: widen stale circuit breaker to non-streaming path + all provider…
kshitijk4poor Jul 7, 2026
fa65137
fix(bedrock): route non-Claude auxiliary models through Converse API
xxxigm Jul 7, 2026
e9da629
test(bedrock): cover auxiliary Converse routing for non-Claude models
xxxigm Jul 7, 2026
b2d6a51
fix: normalize string stop + surface dropped stream/tool_choice in Co…
kshitijk4poor Jul 7, 2026
2a14205
feat(mem0): self-hosted dashboard backend + recall tuning (salvage #5…
kartik-mem0 Jul 2, 2026
53edf6f
fix(mem0): make prompt label + platform setup honor host routing prec…
kshitijk4poor Jul 2, 2026
9a32272
fix(mem0): prune dead get_all, wire rerank config default, warn on ME…
kshitijk4poor Jul 7, 2026
b598f8e
feat: add prompt-only session export
catbearlove1-lang Jul 3, 2026
a80e5e7
feat(cli): add standalone HTML session export with sidebar navigation
simplast May 22, 2026
49dd0b1
feat(cli): include system prompts in HTML export
simplast May 23, 2026
a730156
feat(cli): redesign system prompt display as dedicated header section
simplast May 23, 2026
271130a
feat(cli): expand system prompt by default in HTML export
simplast May 23, 2026
4bd6fce
fix(cli): fix layout width bug and ensure system prompt header is used
simplast May 23, 2026
ab07e06
style(export): restore width: 0 for multi-session flex layout
simplast May 23, 2026
b172e03
feat(cli): filter internal session_meta messages from HTML export
simplast May 23, 2026
f76899f
feat(sessions): wire html + prompt-only formats into 'sessions export'
teknium1 Jul 7, 2026
e0176cb
feat(discord): optionally mention approval owners on exec prompts
alex107ivanov Jul 7, 2026
94b4ac1
chore: add alex107ivanov to AUTHOR_MAP
teknium1 Jul 7, 2026
b1500af
fix: restore cli-config.yaml.example from main (stale-branch version …
teknium1 Jul 7, 2026
b428920
fix(web-server): close OAuth token TOCTOU by writing 0o600 atomically
Que0x Jul 4, 2026
5e51b12
feat(mem0): add self-hosted mode to the setup wizard
teknium1 Jul 7, 2026
0e04d14
feat(sessions): trace export + HF upload via 'sessions export --forma…
teknium1 Jul 7, 2026
37a4cf9
fix: limit desktop model pickers to explicit providers
rarf Jul 2, 2026
a0b14a3
chore: map Ronald contributor email
rarf Jul 2, 2026
f304f41
fix: harden explicit-provider gate for stale env-seeded pool entries …
teknium1 Jul 7, 2026
36308f0
feat(plugins): pass approve rule keys to approval gate
doncazper Jul 5, 2026
117f49b
fix(approval): wire gateway notify round-trip into the plugin escalat…
teknium1 Jul 7, 2026
d5a5ea8
chore: add doncazper to AUTHOR_MAP
teknium1 Jul 7, 2026
0ecfbc9
feat(pty): RingBuffer for keep-alive output capture
TinkerOfThings Jun 21, 2026
e5ac169
feat(pty): PtySession drain/attach/detach with EOF close 4410
TinkerOfThings Jun 21, 2026
41166bb
feat(pty): PtySessionRegistry with reap + capacity
TinkerOfThings Jun 21, 2026
e10e4bc
feat(chat): reattach /api/pty sessions via ?attach= token
TinkerOfThings Jun 21, 2026
c3d2be0
feat(pty): periodic reaper wired into dashboard lifespan
TinkerOfThings Jun 21, 2026
79f4f78
feat(chat): persist attach token, reconnect on transient close
TinkerOfThings Jun 21, 2026
086596c
fix(mcp): reap orphaned subprocesses before spawning new ones on retry
liuhao1024 Jul 2, 2026
f99e9f0
fix(mcp): reap stdio orphans before reconnect
tianma-if Jul 4, 2026
743c116
fix(mcp): unify reconnect orphan reaping + move off the event loop
teknium1 Jul 7, 2026
1f6836c
fix(mcp): bound stdio initialize handshake to stop subprocess/FD leak
astraltrekkin Jul 6, 2026
4638f3b
fix(mcp): widen #59349 handshake bound to HTTP transports + cancel ab…
teknium1 Jul 7, 2026
5089c84
fix(mcp): reap orphaned stdio MCP children on ungraceful parent death
Jul 7, 2026
86c5feb
fix(mcp): watchdog wrap after OSV preflight + forward SIGTERM to chil…
teknium1 Jul 7, 2026
6c731fe
Recycle idle MCP stdio servers
harjothkhara Jun 8, 2026
ea0b42c
Handle minimal MCP server fakes
harjothkhara Jun 8, 2026
bae3954
chore(release): map rainbowgore + thestudionorth in AUTHOR_MAP for MC…
teknium1 Jul 7, 2026
a620383
docs(mcp): document idle_timeout_seconds / max_lifetime_seconds recyc…
teknium1 Jul 7, 2026
2d4fd1d
test(mcp): unblock recycle-reconnect test from the parked self-probe …
teknium1 Jul 7, 2026
838d504
fix(mcp): guard POSIX-only kill primitives in stdio watchdog for the …
teknium1 Jul 7, 2026
b062083
feat(dashboard): report profile + gateway topology in /api/status (#6…
teknium1 Jul 7, 2026
8a726e9
fix(tools): enable platform-native toolsets when their composite is e…
Tranquil-Flow Jul 1, 2026
551f001
docs(sessions): unify export docs under one overview section (#60554)
teknium1 Jul 7, 2026
c3808cf
fix(discord): honor pairing grants for message auth
BROCCOLO1D Jul 3, 2026
3e7ade4
fix(discord): explain fail-closed allowlist default
yungchentang Jul 7, 2026
db9e3e4
docs(discord): troubleshoot silent fail-closed denials
teknium1 Jul 7, 2026
6ca3d70
fix(gateway): only session-discover channel targets for connected pla…
teknium1 Jul 8, 2026
0263f1d
Fix delegation config precedence
shannonsands Jul 7, 2026
bf76391
Use read-only config loader and honor HERMES_IGNORE_USER_CONFIG in de…
shannonsands Jul 7, 2026
5633fa1
fix(dashboard): advertise truecolor to the embedded chat TUI (#60576)
teknium1 Jul 8, 2026
8d66e78
feat(dashboard): expose profile names + gateway_mode on gated /api/st…
benbarclay Jul 8, 2026
4e4a69c
feat(relay): carry routed profile from the connector wire source (#60…
benbarclay Jul 8, 2026
4b184cb
Add dashboard memory provider switching
shannonsands Jul 3, 2026
d9a4b5a
fix: validate memory provider names before filesystem lookup and setu…
teknium1 Jul 8, 2026
75de005
feat(gateway): GATEWAY_MULTIPLEX_PROFILES env override for multiplex …
benbarclay Jul 8, 2026
543f069
Fix dashboard chat model profile scoping
shannonsands Jun 22, 2026
6015ee5
fix: pass profile-scoped SessionDB to _session_latest_descendant in d…
teknium1 Jul 7, 2026
4f620a0
Add WhatsApp dashboard pairing flow
shannonsands Jul 2, 2026
f9eca7e
chore: release v0.18.1 (2026.7.7) (#60595)
teknium1 Jul 8, 2026
c30c975
fix(whatsapp): unpin Baileys from git commit, use published 7.0.0-rc1…
teknium1 Jul 8, 2026
9de9c25
chore: release v0.18.2 (2026.7.7.2) (#60651)
teknium1 Jul 8, 2026
4d7f8ad
feat(install): warn pip/Homebrew installs are unsupported (CLI, TUI, …
ethernet8023 Jul 8, 2026
2e1982f
Fail closed on invalid JSON/YAML/TOML writes instead of writing then …
neoguyverx Jul 7, 2026
6695640
fix(tools): make the YAML write gate syntax-only so multi-doc/tagged …
teknium1 Jul 8, 2026
a208b7e
chore: add AUTHOR_MAP entry for neoguyverx (PR #60526 salvage)
teknium1 Jul 8, 2026
862aee4
fix(gateway): drain in-flight cron jobs before shutdown tool kill
HexLab98 Jul 8, 2026
e6077af
test(gateway): cover cron drain during gateway shutdown (#60432)
HexLab98 Jul 8, 2026
24e9ed7
fix(gateway,cron): make shutdown drain visible to in-flight cron work
JoaoMarcos44 Jul 8, 2026
8a573bb
fix(cron): stop interrupted jobs from delivering their pre-kill output
JoaoMarcos44 Jul 8, 2026
ecc6725
fix(gateway,cron): reconcile #60612 + #60631 onto one drain surface
teknium1 Jul 8, 2026
f5ef7ee
fix(tui): prevent ws_orphan_reap from ending gateway-originated sessions
AIalliAI Jul 8, 2026
4878803
fix(tui): derive gateway-owned sources from the Platform enum, not a …
teknium1 Jul 8, 2026
f64e4f4
feat(gateway): generic OIDC client-credentials relay provisioning (NA…
benbarclay Jul 8, 2026
832c5f9
Fix slow Z.AI startup by caching auto-detected endpoint to disk
veradim Jun 7, 2026
c75e1d1
chore: add veradim to AUTHOR_MAP for PR #41201 salvage
kshitijk4poor Jul 8, 2026
6eeed3f
fix: don't flip active_provider when caching Z.AI probe result
kshitijk4poor Jul 8, 2026
1192f29
fix: Z.AI endpoint persist failure must not break URL resolution
kshitijk4poor Jul 8, 2026
7ecc822
fix(cron): stop the ticker from stalling forever on a wedged jobs loc…
teknium1 Jul 8, 2026
98804db
fix(tui_gateway): back off notification poller when session is busy
SiteupAgencia Jul 3, 2026
5413c42
chore: add SiteupAgencia to AUTHOR_MAP for #57435 salvage
teknium1 Jul 8, 2026
465cbe8
test(tools): add unit tests for skill_gist
waroffchange Jul 8, 2026
ac6dd59
fix(agent): tag desktop chat sessions as desktop
fyzanshaik Jul 4, 2026
aab351b
fix(delegation): route async results to origin session
dschnurbusch Jul 6, 2026
4b27be1
fix(delegation): fail-closed orphan handling + session-scoped delegat…
teknium1 Jul 8, 2026
b64b802
feat(models): swap curated Tencent Hy3 Preview for GA tencent/hy3, dr…
teknium1 Jul 8, 2026
ee0b54e
docs(i18n): align translated CONTRIBUTING files with pyproject Python…
waroffchange Jul 8, 2026
5057f03
docs(i18n): align translated CONTRIBUTING files with pyproject Python…
waroffchange Jul 8, 2026
f75f3cd
fix(delegation): route async delegate_task results back to originatin…
asimons81 Jul 5, 2026
6537239
fix(delegation): positive-proof ownership for the post-turn drain
teknium1 Jul 8, 2026
c0fbee9
fix(desktop): register /compress command in TUI gateway dispatch so D…
kyssta-exe Jul 8, 2026
7e3986a
fix(tui): route /compress and /compact past the slash worker to comma…
teknium1 Jul 8, 2026
e10c8eb
fix(whatsapp): use windows_detach_popen_kwargs to prevent console win…
kyssta-exe Jul 8, 2026
efb226b
fix(cli): preserve chat -q answer by gating exit-summary screen clear…
Tranquil-Flow Jun 26, 2026
58e1647
test(cli): update FakeCLI._print_exit_summary for new clear_screen kwarg
teknium1 Jul 8, 2026
63c4100
perf(yuanbao): bounded-concurrency inbound media resolve
Jun 16, 2026
b848fcb
feat(Yuanbao) optimizes media resource processing speed: parallel dow…
Jul 8, 2026
d39c624
fix(delegate): pin async completion to spawning parent session (#57498)
nankingjing Jul 3, 2026
75efd73
fix(gateway): never resurrect ended sessions for delegation completio…
teknium1 Jul 8, 2026
0cf2e39
feat(gateway): add webhook payload filters
uwucatherine Jul 3, 2026
ae5e390
fix(gateway): run webhook route scripts off the event loop + AUTHOR_M…
teknium1 Jul 8, 2026
8e73481
fix(desktop): continue the selected stored session instead of minting…
teknium1 Jul 8, 2026
76381e2
fix(compression): stop compaction thrash — 75% trigger floor under 51…
teknium1 Jul 8, 2026
aabfedc
docs(webhook): complete filters + route-scripts coverage across doc s…
teknium1 Jul 8, 2026
62ada51
feat(xai): add grok-4.5 (GA) to model catalog, context lengths, and r…
teknium1 Jul 8, 2026
d6a275b
fix(gateway): compact hygiene transcripts in place
nullptr0807 Jul 8, 2026
4d611ba
chore: AUTHOR_MAP entry for nullptr0807 (PR #60956 salvage)
teknium1 Jul 8, 2026
9a4341a
fix(dashboard): keep status responsive when session db locks
tianma-if Jul 4, 2026
346e567
🐛 fix(dashboard): offload cron profile scans
BlackishGreen33 Jun 13, 2026
49fa04a
🐛 fix(dashboard): use managed cron threadpool
BlackishGreen33 Jun 13, 2026
7d0ddbb
fix(dashboard): cache gateway PID status probes
0disoft Jun 27, 2026
492be28
fix(web): bound dashboard action log tails
ooiuuii Jul 4, 2026
d7e4d94
perf(dashboard): recursive-CTE descendant lookup in _session_latest_d…
sebastianlutycz Jul 8, 2026
24d5bda
fix(dashboard): run GET /api/sessions session-DB read off the event loop
0-CYBERDYNE-SYSTEMS-0 Jul 8, 2026
206c042
chore: AUTHOR_MAP entries for salvaged contributors (#53511/#53966/#3…
kshitijk4poor Jul 8, 2026
1e2ad17
fix: descendant CTE must dedup (UNION) to survive parent-chain cycles
kshitijk4poor Jul 8, 2026
664878b
fix: guard /api/status active count against missing state.db
kshitijk4poor Jul 8, 2026
c95cf31
test: patch the cached PID probe name in profile-unification status t…
kshitijk4poor Jul 8, 2026
0d5549a
fix(api): add pagination to GET /api/sessions/{id}/messages
mahdiwafy Jul 7, 2026
4df16c4
Refresh on upstream/main: resolve conflicts (no behavior change)
Jul 5, 2026
22eb1af
perf(state): add compact_rows to skip system_prompt blob in session l…
CodeForgeNet Jun 16, 2026
4f220fc
fix: follow-up for salvaged #60347/#43653/#47437
kshitijk4poor Jul 8, 2026
7570bb4
fix: offset-without-limit was silently ignored in get_messages
kshitijk4poor Jul 8, 2026
7a25017
test: accept compact_rows kwarg in tui_gateway session fakes
kshitijk4poor Jul 8, 2026
31e39de
test: expect compact_rows in the read-only status-count fake
kshitijk4poor Jul 8, 2026
0569a63
fix(agent): guard response.text access in _summarize_api_error agains…
gauravsaxena1997 Jul 8, 2026
1792a3a
chore: add gauravsaxena1997 to AUTHOR_MAP (PR #59868 salvage)
kshitijk4poor Jul 8, 2026
74e28f7
style(tests): merge import blocks in test_summarize_api_error
kshitijk4poor Jul 8, 2026
be1346c
fix(gateway): reload fallback_providers on live agent create/reuse
HexLab98 Jul 8, 2026
e721ad8
test(gateway): cover fallback_providers reload for live sessions
HexLab98 Jul 8, 2026
0a01b20
fix(gateway): harden fallback-chain refresh from review findings
kshitijk4poor Jul 8, 2026
e21ba91
perf(skills): speed up snapshot prompt builds
dexhunter Jul 7, 2026
449706c
chore: add dexhunter to AUTHOR_MAP (PR #60339 salvage)
kshitijk4poor Jul 8, 2026
2a29331
fix: run CLI new-session memory flush off-thread
Tosko4 Jul 5, 2026
d8bc4f2
fix: serialize /new end→switch boundary on the memory manager worker
kshitijk4poor Jul 8, 2026
e0ed5dc
refactor: address Phase-2 review findings on /new boundary handoff
kshitijk4poor Jul 8, 2026
6d65210
feat(desktop): group tool calls across text-less assistant messages
OutThisLife Jul 8, 2026
fac8551
Merge pull request #61147 from NousResearch/bb/desktop-tool-window-merge
OutThisLife Jul 8, 2026
39d0945
feat(desktop): ts-ify everything
ethernet8023 Jun 29, 2026
7a65530
fix(js): set @types/node to node 22, what's required in "engines"
ethernet8023 Jul 3, 2026
56a8e81
cleanup(desktop): `npm run fix` for fmtting
ethernet8023 Jul 8, 2026
513dba4
chore(models): drop x-ai/grok-4.3 from OpenRouter/Nous curated lists …
teknium1 Jul 9, 2026
bf913ab
fix(desktop): stop using tsx to boot Electron main in dev
OutThisLife Jul 9, 2026
88a58ff
Merge pull request #61277 from NousResearch/bb/fix-desktop-tsx-electr…
OutThisLife Jul 9, 2026
3e24b16
fix(dashboard): support mobile OAuth login
shannonsands Jul 9, 2026
ad8f103
i18n(dashboard): translate OAuth copy-code strings in all locales
shannonsands Jul 9, 2026
4734071
test(dashboard): assert server still gates OAuth endpoints without co…
kshitijk4poor Jul 9, 2026
32a0f9e
fix(model_metadata): avoid str(tools) token estimate stalls
infinitycrew39 Jul 8, 2026
f4d5cfd
test(model_metadata): cache tools schema token estimate
infinitycrew39 Jul 8, 2026
55dbc3f
fix(model_metadata): bound the tools-token estimate cache
kshitijk4poor Jul 9, 2026
cbf6853
fix(gateway): sync HERMES_HOME before refreshing system systemd units
HexLab98 Jul 8, 2026
8f18f6c
test(gateway): cover sudo system-unit refresh adopting HERMES_HOME
HexLab98 Jul 8, 2026
d54a8f7
refactor(gateway): funnel HERMES_HOME sync through a single chokepoint
kshitijk4poor Jul 9, 2026
3fe7f6d
fix: preserve fallback switch notice on successful fallback
Umi4Life Jun 16, 2026
a4ba8c9
chore: map poowis2011@hotmail.com → Umi4Life for PR #47377 salvage
kshitijk4poor Jul 9, 2026
0b2b08d
fix(dashboard): recover mobile chat reconnect
shannonsands Jul 9, 2026
3e88cae
fix(dashboard): harden PTY input tracker against escape sequences
shannonsands Jul 9, 2026
6f42bf3
fix(dashboard): harden PTY reconnect race, wedged-connect recovery, I…
kshitijk4poor Jul 9, 2026
c889941
fix(model_metadata): cache detect_local_server_type result for proces…
uzaylisak May 21, 2026
91ece5c
perf(model-metadata): resolve localhost to IPv4 in detect_local_serve…
rodboev Jun 2, 2026
9a18a2d
fix(agent): probe localhost via IPv4 for LM Studio detection
rodboev Jul 9, 2026
c454d32
fix(model_tools): honor model.context_length to skip OpenRouter probe…
Jun 22, 2026
040e30a
perf(model_metadata): cache ollama /api/show probe + normalize contex…
kshitijk4poor Jul 9, 2026
20cb385
fix(model_metadata): widen localhost->IPv4 rewrite to all sibling pro…
kshitijk4poor Jul 9, 2026
f556edc
fix(model_metadata): address Phase-2 review findings on probe caches
kshitijk4poor Jul 9, 2026
750c131
fix(caching): include Kimi/Moonshot in OpenRouter prompt cache policy…
zccyman Jul 8, 2026
fbbb841
test(caching): pin Kimi/Moonshot OpenRouter cache policy (#25970)
kshitijk4poor Jul 8, 2026
1d689e1
fix(caching): use canonical Kimi-family matcher in cache policy
kshitijk4poor Jul 8, 2026
74609f9
fix(dashboard): run residual cron profile I/O off the event loop
kshitijk4poor Jul 9, 2026
8cfada0
test(dashboard): pin cron fire + blueprint handlers off the event loop
kshitijk4poor Jul 9, 2026
d928017
fix(dashboard): validate HERMES_WEB_DIST before startup
kshitijk4poor Jul 9, 2026
4ed910c
fix(cli): mock systemd preflight in gateway service tests for non-sys…
Tranquil-Flow Apr 24, 2026
724ab90
perf: avoid broad message prep deepcopies
pedrommaiaa Jun 5, 2026
63ddd02
refactor(salvage): scope #40632 to the two live copy-on-write sites
kshitijk4poor Jul 8, 2026
e7648d5
test: restore gemma-3-27b to keep-extra_content coverage
kshitijk4poor Jul 8, 2026
f5bc18f
fix: write expanded HERMES_WEB_DIST back for web_server's raw read
kshitijk4poor Jul 9, 2026
cb79518
Merge pull request #61385 from kshitijk4poor/fix/dashboard-residual-c…
kshitijk4poor Jul 9, 2026
3ed7c8a
Merge pull request #61388 from kshitijk4poor/fix/dashboard-validate-w…
kshitijk4poor Jul 9, 2026
1e16120
fix(reasoning): add deepseek-v4-flash and deepseek-v4-pro to reasonin…
liuhao1024 Jul 7, 2026
411d599
test: fold deepseek-v4 cases into canonical reasoning-floor test, dro…
kshitijk4poor Jul 9, 2026
5a42491
perf(skills): cache skill discovery results by directory mtime
nankingjing Jul 6, 2026
9e9608e
fix: harden skill-discovery cache signature + TTL
kshitijk4poor Jul 9, 2026
cbdf87b
fix: return per-call copies from the skill-discovery cache
kshitijk4poor Jul 9, 2026
709da84
feat(gateway): attach MEDIA: caption to the media bubble on standalon…
kshitijk4poor Jul 9, 2026
73b611a
Merge pull request #61415 from kshitijk4poor/fix/media-tag-caption
kshitijk4poor Jul 9, 2026
d23990f
fix(gateway): offload channel directory session scans
embwl0x Jul 8, 2026
daedf4f
chore: AUTHOR_MAP entry for embwl0x (PR #60810 salvage)
teknium1 Jul 8, 2026
3a1a3c7
add 5.6 (#61578)
rob-maron Jul 9, 2026
bd767b5
feat(openai): complete gpt-5.6 registration — context, codex catalog,…
kshitijk4poor Jul 9, 2026
db117af
review fixes: openai-api pricing route normalization, GA pricing_vers…
kshitijk4poor Jul 9, 2026
a3828a9
feat(openai): cover gpt-5.6 -pro variants (PR #61587 complement)
kshitijk4poor Jul 9, 2026
7efee32
pro variants
rob-maron Jul 9, 2026
5da7b23
chore(catalog): regenerate model-catalog.json from source
kshitijk4poor Jul 9, 2026
4af484d
feat(openai): complete gpt-5.6 E2E — codex catalog + 272K compaction …
kshitijk4poor Jul 9, 2026
111544d
test(codex-picker): raise max_models so count invariant survives cata…
kshitijk4poor Jul 9, 2026
5829fe1
fix(kanban): failure diagnostics exempt done/archived tasks
OutThisLife Jul 9, 2026
e87c495
fix(kanban): spawn workers headless — TUI can never eat a worker run
OutThisLife Jul 9, 2026
aea570d
fix(kanban): clear failure/crash diagnostics while a retry is in flight
OutThisLife Jul 9, 2026
77db9d6
fix(kanban): explicit re-queue bypasses the recent-success respawn guard
OutThisLife Jul 9, 2026
b06e2f8
fix(kanban): no-TTY gate in _wants_tui_early — the actual worker-cras…
OutThisLife Jul 9, 2026
8e3f953
Merge pull request #61649 from NousResearch/bb/kanban-worker-headless
OutThisLife Jul 9, 2026
fe25806
fix(config): retain last-known-good config when config.yaml fails to …
teknium1 Jul 9, 2026
a23d507
fix(agent): stop switch_model from pairing new provider with stale ba…
JoaoMarcos44 Jul 8, 2026
1f57ed2
fix(export): escape tool-call name in HTML session export
Adolanium Jul 9, 2026
501616e
fix(cli): set HERMES_YOLO_MODE before plugin discovery at startup
bytesnail Jul 7, 2026
d2e64fc
fix(cli): widen --yolo env guarantee to the _prepare_agent_startup ch…
teknium1 Jul 9, 2026
c71d19c
fix(cron): id-less job no longer freezes the whole scheduler
Jul 9, 2026
8e2ce43
fix(cron): non-dict schedule no longer freezes the whole scheduler
necoweb3 Jul 9, 2026
26f040e
fix(cron): malformed next_run_at no longer freezes the scheduler
necoweb3 Jul 9, 2026
10c0d9b
fix(cron): contain any per-job exception in the due scan; harden as a…
teknium1 Jul 10, 2026
b298fd5
test(cli): deflake --accept-hooks position test — one driver, one imp…
teknium1 Jul 10, 2026
549b87c
fix(gateway): prevent hygiene compression from destroying archived tr…
AlexFucuson9 Jul 9, 2026
9cbac64
test(gateway): pin in-place compaction skipping the destructive rewrite
teknium1 Jul 9, 2026
79f1274
chore: AUTHOR_MAP entry for AlexFucuson9 (PR #61209 salvage)
teknium1 Jul 10, 2026
b5226ca
fix(memory): share one SQLite connection per holographic store database
adambiggs Jun 10, 2026
a801046
fix(memory): resolve() the shared-connection registry key; symlink test
teknium1 Jul 10, 2026
0a4b4d6
fix(agent): reapply provider headers after model switch
AlexFucuson9 Jul 9, 2026
c75789f
test: regression coverage for header reapplication on model switch
teknium1 Jul 10, 2026
bd16395
chore: add AlexFucuson9 to AUTHOR_MAP (PR #61347 salvage)
teknium1 Jul 10, 2026
bdecf0a
fix(cli): ignore empty config sections
yungchentang Jul 4, 2026
4661307
fix(config): widen empty-section guard to _deep_merge in load_config
teknium1 Jul 10, 2026
50c66b2
fix(gateway): ignore malformed config sections
sharziki Jun 6, 2026
a7f65e3
fix(gateway): tolerate scalar gateway config block
sharziki Jun 6, 2026
276542c
fix(qqbot): add is_reconnect param to QQAdapter.connect for gateway r…
luxuguang-leo Jun 26, 2026
0f8603c
test(gateway): regression: every adapter.connect() must accept is_rec…
lemonwan Jul 6, 2026
9c40fc2
chore: map QQBot fix contributor
teknium1 Jul 10, 2026
16b841b
docs: add gateway reconnect contract infographic
teknium1 Jul 10, 2026
540f901
chore: map reconnect contract contributor
teknium1 Jul 10, 2026
b5c655c
fix(cli): normalize role into a single CSS token for the message class
briandevans Jul 9, 2026
a4dd08a
fix(session-export): escape html tool call names
kohoj Jul 9, 2026
c49d51b
chore: AUTHOR_MAP entry for kohoj (PR #61667 salvage)
teknium1 Jul 10, 2026
b2e227d
fix(agent): handle YAML null value in context_length_cache
ygd58 Jun 16, 2026
881a952
test: regression coverage for null context_lengths key (#47135)
teknium1 Jul 10, 2026
4c03032
fix(cli): normalize malformed skills config in get_disabled_skills (#…
teknium1 Jul 10, 2026
8937121
fix(stt/tts): guard against null config subsections crashing with Att…
x7peeps Jun 16, 2026
3a39421
fix(stt/tts): widen null-subsection guards to all provider config reads
teknium1 Jul 10, 2026
66dda52
Merge remote-tracking branch 'dave-fork/main'
DaveVoyles Jul 10, 2026
883bdbe
fix(terminal): route desktop (Windows/WSL) SSH commands via stdin
DaveVoyles Jul 10, 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
69 changes: 69 additions & 0 deletions tests/tools/test_ssh_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,75 @@ def test_user_host_suffix(self):
assert env._build_ssh_command()[-1] == "u@h"


class TestRunBashQuoting:
"""Regression coverage for the desktop (Windows) quoting bug.

ssh joins trailing argv elements with spaces and sends the joined string
for the remote side to re-parse. A POSIX login shell strips
shlex.quote()'s quotes correctly, so `bash -c <shlex.quote(cmd)>` keeps
cmd_string as one argument. A Windows OpenSSH host's re-parse does not
preserve that quoting, so any command-line-embedded script (not just
trivial one-liners) arrives mangled — so Windows hosts instead send the
script over the SSH stdin channel (`bash -s`), sidestepping the remote
command-line re-parse entirely.
"""

@pytest.fixture(autouse=True)
def _mock_connection(self, monkeypatch):
monkeypatch.setattr("tools.environments.ssh.subprocess.run",
lambda *a, **k: subprocess.CompletedProcess([], 0))
monkeypatch.setattr("tools.environments.base.time.sleep", lambda _: None)

def _captured_call(self, env, cmd_string, monkeypatch, **kwargs):
captured = {}

def fake_popen_bash(cmd, stdin_data):
captured["cmd"] = cmd
captured["stdin_data"] = stdin_data
return MagicMock()

monkeypatch.setattr("tools.environments.ssh._popen_bash", fake_popen_bash)
env._run_bash(cmd_string, **kwargs)
return captured

def test_posix_host_quotes_compound_command(self, monkeypatch):
env = SSHEnvironment(host="h", user="u") # default remote_shell="posix"
captured = self._captured_call(env, "hostname && whoami", monkeypatch)
cmd = captured["cmd"]
assert cmd[cmd.index("-c") + 1] == "'hostname && whoami'"

def test_posix_host_quotes_simple_command_when_needed(self, monkeypatch):
# shlex.quote leaves safe single words unquoted either way, so use
# a command with a space to actually exercise the quoting branch.
env = SSHEnvironment(host="h", user="u")
captured = self._captured_call(env, "echo hello world", monkeypatch, login=True)
cmd = captured["cmd"]
assert cmd[cmd.index("-c") + 1] == "'echo hello world'"

def test_windows_host_sends_script_via_stdin_not_command_line(self, monkeypatch):
env = SSHEnvironment(host="h", user="u", remote_shell="windows")
cmd_string = "echo hello && echo world"
captured = self._captured_call(env, cmd_string, monkeypatch)
cmd = captured["cmd"]
# No -c, no embedded script text anywhere in the argv — only "-s".
assert "-c" not in cmd
assert "-s" in cmd
assert cmd_string not in cmd
assert captured["stdin_data"].startswith(cmd_string + "\n")

def test_windows_host_login_flag_with_stdin_script(self, monkeypatch):
env = SSHEnvironment(host="h", user="u", remote_shell="windows")
captured = self._captured_call(env, "whoami", monkeypatch, login=True)
cmd = captured["cmd"]
bash_idx = cmd.index("bash")
assert cmd[bash_idx:bash_idx + 3] == ["bash", "-l", "-s"]

def test_windows_host_appends_real_stdin_after_script(self, monkeypatch):
env = SSHEnvironment(host="h", user="u", remote_shell="windows")
captured = self._captured_call(env, "cat", monkeypatch, stdin_data="payload\n")
assert captured["stdin_data"] == "cat\npayload\n"


class TestControlSocketPath:
"""Regression tests for issue #11840.

Expand Down
33 changes: 31 additions & 2 deletions tools/environments/ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,20 @@ class SSHEnvironment(BaseEnvironment):
"""

def __init__(self, host: str, user: str, cwd: str = "~",
timeout: int = 60, port: int = 22, key_path: str = ""):
timeout: int = 60, port: int = 22, key_path: str = "",
remote_shell: str = "posix"):
super().__init__(cwd=cwd, timeout=timeout)
self.host = host
self.user = user
self.port = port
self.key_path = key_path
# "posix": ssh's remote-side re-parse of the joined command line goes
# through the user's POSIX login shell, which strips shlex.quote()'s
# single-quotes correctly. "windows": the remote re-parse doesn't
# preserve POSIX quoting, so shlex.quote() arrives mangled — pass the
# command unquoted instead. Verified empirically against both a POSIX
# host and a Windows OpenSSH host on 2026-07-10.
self.remote_shell = remote_shell

self.control_dir = Path(tempfile.gettempdir()) / "hermes-ssh"
self.control_dir.mkdir(parents=True, exist_ok=True)
Expand Down Expand Up @@ -343,8 +351,29 @@ def _before_execute(self) -> None:
def _run_bash(self, cmd_string: str, *, login: bool = False,
timeout: int = 120,
stdin_data: str | None = None) -> subprocess.Popen:
"""Spawn an SSH process that runs bash on the remote host."""
"""Spawn an SSH process that runs bash on the remote host.

ssh joins the trailing argv elements with spaces and sends that as
one string for the remote side to re-parse. A POSIX login shell
strips shlex.quote()'s single-quotes correctly, so quoting via
`bash -c <shlex.quote(cmd_string)>` keeps cmd_string as one argument.

A Windows OpenSSH host's re-parse does not preserve that quoting the
same way — any command-line-embedded script (quotes, newlines,
wrapper markers) arrives mangled, not just simple one-liners. So for
`self.remote_shell == "windows"`, cmd_string is sent over the SSH
stdin channel instead of the command line (`bash -s`, script read
from stdin) — this sidesteps the remote-side re-parse entirely.
Real stdin_data (if any) is appended after the script, matching how
`some_script | bash` lets the script's own commands keep reading
stdin once the script text is consumed.
"""
cmd = self._build_ssh_command()
if self.remote_shell == "windows":
cmd.extend(["bash", "-l", "-s"] if login else ["bash", "-s"])
combined_stdin = cmd_string + "\n" + (stdin_data or "")
return _popen_bash(cmd, combined_stdin)

if login:
cmd.extend(["bash", "-l", "-c", shlex.quote(cmd_string)])
else:
Expand Down
7 changes: 6 additions & 1 deletion tools/terminal_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@
"macbook-personal": {"host": "192.168.1.2", "user": "davevoyles"},
"macbook-dock": {"host": "192.168.1.39", "user": "davevoyles"},
"macbook": {"host": "Daves-MacBook-Pro-2.local", "user": "davevoyles"},
"desktop": {"host": "192.168.1.24", "user": "DaveV"},
# remote_shell="windows": ssh's remote-side re-parse of the joined command
# line strips single-quotes differently than a POSIX login shell does, so
# shlex.quote()'d args arrive mangled. See SSHEnvironment._run_bash.
"desktop": {"host": "192.168.1.24", "user": "DaveV", "remote_shell": "windows"},
}


Expand Down Expand Up @@ -1544,6 +1547,7 @@ def _create_environment(env_type: str, image: str, cwd: str, timeout: int,
user=ssh_config["user"],
port=ssh_config.get("port", 22),
key_path=ssh_config.get("key", ""),
remote_shell=ssh_config.get("remote_shell", "posix"),
cwd=cwd,
timeout=timeout,
)
Expand Down Expand Up @@ -2244,6 +2248,7 @@ def terminal_tool(
"port": resolved_host.get("port", 22),
"key": resolved_host.get("key", ""),
"persistent": resolved_host.get("persistent", False),
"remote_shell": resolved_host.get("remote_shell", "posix"),
}
else:
ssh_config = {
Expand Down
Loading