344 Commits

Author SHA1 Message Date
chengyongru
01a0f5aaf3 fix: remove unreliable Shift+Enter shortcut
maintainer edit: keep Alt+Enter as the supported multiline input path and remove the terminal-dependent Shift+Enter ANSI sequence patch.
2026-07-07 15:41:08 +08:00
wangjunwei
77a6003255 fix(cli): make Alt+Enter insert a newline on LF-as-Enter terminals
On terminals that send a bare LF for plain Enter (WSL is the case
prompt_toolkit itself calls out), Alt+Enter arrives as ESC + LF
("\x1b\x0a" = Escape + ControlJ), not the ESC + CR the existing
"escape","enter" binding matches. The Escape was swallowed and the bare
LF hit prompt_toolkit's default submit, so the documented "universally
supported" Alt+Enter newline fallback failed on exactly the terminal path
plain Enter is preserved for.

Bind ESC + ControlJ to insert a newline too, and add a real-PromptSession
regression test covering the WSL Alt+Enter path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:41:08 +08:00
wangjunwei
25a477050d fix(cli): make the xterm modifyOtherKeys Shift+Enter encoding insert a newline
"\x1b[27;2;13~" (the older xterm modifyOtherKeys / rxvt encoding of
Shift+Enter) is already registered by prompt_toolkit by default -- as
Keys.ControlM, i.e. plain Enter/submit. The previous `setdefault()` call was
therefore a silent no-op against it: this Shift+Enter variant kept behaving
like a submit instead of inserting a newline, even after the ControlJ/WSL
fix, since setdefault only sets missing keys.

Assign directly to override that default for both known Shift+Enter
sequences, since inserting a newline is the whole point of the binding.
Add a regression test driving a real PromptSession/parser with this exact
sequence, since a mocked-buffer test can't observe prompt_toolkit's default
ANSI_SEQUENCES entries taking priority.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:41:08 +08:00
wangjunwei
ea0516e655 fix(cli): stop hijacking ControlJ for Shift+Enter, it breaks Enter on WSL
Keys.ControlJ is also the literal LF byte ("\x0a") that some terminals send
for a plain Enter keypress -- prompt_toolkit's own default bindings handle
this by re-feeding it as ControlM/submit, and calls out WSL by name as the
case that needs it. Binding our Shift+Enter handler to ControlJ shadowed
that default, so on any terminal sending LF for Enter, pressing Enter only
ever inserted a newline and the prompt could never be submitted.

Register the CSI-u Shift+Enter sequences against Keys.ControlF3 instead: an
enum member prompt_toolkit declares but never wires to a default ANSI
sequence or key binding, so it's only reachable through our own mapping.

Also add a regression test that drives a real PromptSession/Vt100Parser
with a raw LF byte -- the existing key-binding test invoked handlers
directly against a mocked buffer, which exercises the handler logic but not
prompt_toolkit's key-resolution precedence, so it couldn't have caught this.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 15:41:08 +08:00
wangjunwei
18a230de75 feat(cli): support multiline input via Shift+Enter / Alt+Enter
The interactive prompt used a single-line buffer (multiline=False), so
there was no way to compose a multi-line message before submitting.

Switch to a multiline-capable buffer with custom key bindings: Enter still
submits (unchanged feel), Alt+Enter always inserts a newline, and
Shift+Enter inserts a newline on terminals that emit a distinguishable
CSI-u sequence for it (kitty, iTerm2 with the fixterms protocol) by mapping
those sequences onto the otherwise-unused ControlJ key.
2026-07-07 15:41:08 +08:00
Xubin Ren
d04ad1a5b4 fix(gateway): resolve runtime config path for state refresh 2026-07-06 15:55:15 +08:00
dajiaohuang
67b56cba74 @
fix(gateway): self-heal state file PID on server startup

After /restart on Windows, the gateway process gets a new PID (os.execv
creates a new process on Windows), but the state file at
run/gateway.<suffix>.json still contains the old PID from the initial
background spawn.  Nothing rewrites it, leaving state inconsistent.

Add GatewayRuntime.refresh_state_pid() — a classmethod that reads the
existing state file, updates the PID and identity to the current
process, and writes atomically.  Call it early in _run_gateway() so the
state file is always correct regardless of how the process was started
(initial spawn, os.execv, or subprocess.Popen).

On POSIX os.execv preserves the PID, so this is a no-op in normal
operation there, but still beneficial after any unusual restart path.

Fixes #4511
@
2026-07-06 15:29:11 +08:00
Kenneth Zhao
105230cc34 fix(cli): print response text when streaming fails in interactive mode 2026-07-06 15:28:10 +08:00
Kenneth Zhao
f0c989ba2d
fix(dream): ground memory audit records in the real git diff (#4673)
* fix(dream): ground commit messages and cursor advance in the real git diff

Dream consolidation could emit a /dream-log audit record that did not match
the actual file changes: build_dream_commit_message appended the LLM's
unverified resp.content, dream_run_completed only checked the stop reason, and
file contents were deliberately omitted from the prompt. The combination let a
single-turn self-report become the durable audit record.

- gitstore: add summarize_working_tree() — a structured, machine-derived
  summary (per-file +N/-M, totals, capped unified diff) of working-tree
  changes vs HEAD. Pure filesystem/git ground truth, never LLM narrative.
- memory: build_dream_commit_message now takes the diff body instead of resp;
  dream_content_diff() exposes the real delta over SOUL/USER/MEMORY.md only
  (excludes .dream_cursor so cursor writes aren't mistaken for edits);
  build_dream_prompt embeds current file contents so the model edits reality,
  not a stale mental model.
- builtin/cli: both Dream paths now compute the diff, gate cursor advance on
  a non-empty delta (no-op runs no longer swallow history), and commit with
  the diff-grounded message. Non-git workspaces fall back to the completion
  check.
- dream.md: document that contents are embedded, and add a chain-of-
  verification guardrail so the model's summary cannot claim unmade edits.

A regression test proves a lying resp.content never reaches the audit log
while the real diff does.

* fix(dream): mark non-UTF-8 memory files as binary in diff summary

Address review feedback (Q1 on PR #4673): summarize_working_tree read
working-tree files with errors="replace", which would emit U+FFFD
replacement chars into the audit record if a memory file ever held
invalid UTF-8 — misrepresenting the diff it is meant to make truthful.

Switch to errors="strict" and catch UnicodeDecodeError: a non-UTF-8
(or binary/corrupt) file is now recorded as "{path}: binary or
non-UTF-8 file changed" and omitted from the unified diff, so the
audit record stays honest. An empty diff block is also suppressed when
all changes are binary.

Adds a defensive regression test asserting no replacement char leaks.
2026-07-06 12:12:55 +08:00
axelray-dev
6a95877196 fix(providers): standardize oauth_cli_kit error messages across CLI and WebUI 2026-07-06 12:11:03 +08:00
Xubin Ren
067e0c4a40
feat(cli): add safe WebUI first-run launcher (#4688) 2026-07-03 18:58:04 +08:00
chengyongru
5283ceae85
Add optional Nanobot plugin controls (#4396)
* feat: add optional nanobot features

* test: update azure install hint expectation

* fix: validate optional feature extras

maintainer edit: verify requested dependency extras before treating optional features as installed, propagate restart state from feature enablement, and align docs with the new plugins enable command.

* fix: bound optional feature installs

maintainer edit: make optional feature installs time out as a normal install failure instead of leaving the WebUI or CLI action waiting indefinitely.

* feat: slim optional channel dependencies

* fix: log optional install commands

* fix(webui): gate remote feature installs

* docs: clarify webhook plugin example

* fix(webui): harden optional feature installs

* fix: install optional deps without package fallback

* fix(cli): refine plugin feature controls

* fix(webui): count enabled nanobot features

* fix(webui): allow slow feature install routes

* fix(webui): allow disabling websocket channel

* fix(plugins): simplify optional feature controls

* fix(webui): polish apps catalog states

* fix(webui): confirm nanobot support installs

* fix(webui): polish nanobot install dialog

* fix(webui): suppress empty websocket handshakes

* fix(webui): clarify apps plugin summary

* fix(webui): localize workspace access copy

* fix(plugins): polish optional feature controls (#4691)

---------

Co-authored-by: Xubin Ren <52506698+Re-bin@users.noreply.github.com>
2026-07-03 18:17:52 +08:00
chengyongru
acb0e853ff refactor(trigger): share automation turn delivery 2026-07-02 13:32:46 +08:00
chengyongru
afef27dd6c fix(webui): show pending local triggers 2026-07-02 13:32:46 +08:00
chengyongru
f32007c83f fix(trigger): defer local triggers until session idle 2026-07-02 13:32:46 +08:00
chengyongru
2ebf5c4972 refactor(trigger): name CLI trigger source as local
maintainer edit: cron is also a trigger source, so keep the new CLI-delivered source explicitly named as local trigger across backend, WebUI, docs, and tests.
2026-07-02 13:32:46 +08:00
chengyongru
2a0cd19a74 feat(trigger): add session-bound local triggers 2026-07-02 13:32:46 +08:00
chengyongru
5f4cfbcb16 refactor(bus): type outbound runtime events 2026-07-01 20:17:00 +08:00
dajiaohuang
56443ac6e2 @
feat(api): require api_key when binding to all interfaces (parity with WS gateway)

The OpenAI-compatible API server had no authentication option, unlike the
WebSocket gateway which already refuses wildcard binds without a token.
When bound to 0.0.0.0, any caller who could reach the port could drive
the agent with its default tool posture.

- Add api_key field to ApiConfig (schema.py).
- Add wildcard_host_requires_auth validator that rejects wildcard binds
  without api_key, mirroring the WS gateway pattern.
- Add Bearer-token auth middleware to the API server (server.py).
  /health remains unauthenticated.
- Replace the wildcard-host CLI warning with a hard error when api_key
  is unset, and pass api_key to create_app.

Fixes #4490
@
2026-07-01 13:09:49 +08:00
hamb1y
bfbae5a7b3 fix(cli): refresh oauth provider default models 2026-06-30 23:02:42 +08:00
hamb1y
58cce14a07 fix(cli): allow oauth login to set main provider 2026-06-30 23:02:42 +08:00
chengyongru
44a5ed1bc0 feat(providers): support provider-scoped proxy config 2026-06-30 17:33:36 +08:00
Xubin Ren
34f776b48b test(cli): lock disabled dream cursor advancement 2026-06-25 22:53:10 +08:00
axelray-dev
f7b027a295 fix: only advance dream cursor when behind latest (#4242)
Address review: avoid overwriting cursor on every restart when Dream
is disabled. Now only advances if current cursor is behind the latest
position, so repeated restarts don't permanently skip entries.
2026-06-25 22:53:10 +08:00
axelray-dev
6c880a6691 fix: advance dream cursor when Dream is disabled to prevent prompt bloat (#4242)
When dream.enabled is false, the Dream cron job never runs, so the
dream cursor (.dream_cursor) stays at its initial value (0). This
causes read_recent_history_for_prompt() to treat every history entry
as unprocessed, injecting the full chat history into every system
prompt and growing without bound.

Fix: fast-forward the dream cursor to the latest history entry at
gateway startup when Dream is disabled.
2026-06-25 22:53:10 +08:00
Xubin Ren
c915e98c15 test: cover archived heartbeat target selection 2026-06-24 15:45:49 +08:00
Heng Wei Bin
de4009efbd fix: exclude archived keys in heartbeat & fallback missing session timestamps 2026-06-24 15:45:49 +08:00
Xubin Ren
90703002c9 fix(gateway): restore tty signal mode for ctrl-c 2026-06-22 23:20:45 +08:00
Xubin Ren
747104c9cc fix(gateway): make foreground shutdown responsive 2026-06-22 22:00:07 +08:00
Xubin Ren
fbaa85117b fix: close MCP stdio transports from agent task 2026-06-22 18:59:50 +08:00
Xubin Ren
e3c9aff41e feat(gateway): add background and service controls 2026-06-22 14:48:49 +08:00
chengyongru
8e9f09f829 fix: keep onboard cli defaults unchanged
Remove the PR changes that made nanobot onboard default to the wizard, added --defaults, added non-TTY fallback behavior, and changed the Docker smoke command. Keep Quick Start available through nanobot onboard --wizard.
2026-06-22 13:04:05 +08:00
chengyongru
84143d31b2 refactor: reuse onboard config refresh path
Simplify pass: share the existing-config refresh flow between non-interactive defaults and declined overwrite prompts without changing behavior.
2026-06-22 13:04:05 +08:00
chengyongru
3d773d9054 fix: preserve config during non-interactive defaults onboarding
Maintainer edit: make explicit --defaults refresh existing configs without prompting when no TTY is available, preserving user values for CI and Docker runs.
2026-06-22 13:04:05 +08:00
chengyongru
fc7971b3b6 Improve onboard wizard setup flow 2026-06-22 13:04:05 +08:00
chengyongru
cd51654bf1 fix: keep channel login generic
maintainer edit: remove the Feishu-specific config-file guard from the shared CLI login command. Feishu now follows the Weixin pattern where channel.login owns its setup and persistence.
2026-06-18 22:38:06 +08:00
bllackhu
593ab4a788 feat(feishu): add QR scan-to-create bot CLI login feishu command
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-18 22:38:06 +08:00
04cb
e36c43c9e5 fix(cli): use configured bot_icon for agent interactive banner (#4262) 2026-06-14 12:51:43 +08:00
Xubin Ren
7ff8e02eaf chore(repo): remove desktop app from core repo 2026-06-13 00:14:21 +08:00
chengyongru
a50b3ac0f2 fix: harden cron session automation flows 2026-06-12 18:13:25 +08:00
chengyongru
8335554894 refactor: migrate legacy cron payloads to bound sessions 2026-06-12 16:51:20 +08:00
chengyongru
af8192dc38 refactor: move bound cron execution out of gateway 2026-06-12 15:50:36 +08:00
chengyongru
5ae907bc2f refactor: store cron origin delivery context 2026-06-12 15:07:25 +08:00
chengyongru
c4b64a4caf refactor: preserve origin session routing for cron 2026-06-12 14:21:09 +08:00
chengyongru
80524e9e88 refactor: bind cron jobs to origin sessions 2026-06-12 14:00:53 +08:00
chengyongru
271b3651d7 refactor: use cron turn naming internally 2026-06-12 11:57:35 +08:00
chengyongru
d9d481bc15 refactor: centralize cron session metadata keys 2026-06-12 11:43:23 +08:00
chengyongru
3725b42e0e fix: use shared bound cron predicate
maintainer edit: make gateway execution, WebUI automation listing, and delete protection agree on the new bound cron shape. Legacy delivery payloads that carry sessionKey are excluded from the WebUI-bound automation surface.
2026-06-11 23:09:21 +08:00
chengyongru
b4b6c04657 fix: preserve legacy cron delivery payloads
maintainer edit: keep existing cron jobs with legacy delivery fields on the legacy execution path, even when they already carry a sessionKey. This preserves deliver=false behavior and channel-specific routing metadata for upgraded jobs.
2026-06-11 22:26:06 +08:00
chengyongru
a326ba40f4 feat(cron): bind scheduled automations to sessions 2026-06-11 19:48:07 +08:00