6 Commits

Author SHA1 Message Date
chengyongru
f57e324ea5 test(pairing): cover _PENDING_USER_TURN_KEY cleanup and None allow_from
- Assert pending_user_turn is cleared from session metadata after
  shortcut commands (e.g. /help) in test_auto_compact.py.
- Add test for None allow_from / allowFrom values in
  test_base_channel.py to prevent TypeError regressions.
2026-05-15 10:05:30 +08:00
chengyongru
2ad8c8b2f2 refactor(pairing): move /pairing from BaseChannel to CommandRouter
/pairing is now a first-class built-in command dispatched through
CommandRouter, just like /status, /model, /dream, etc.

Benefits:
- WebUI automatically shows /pairing in the slash command palette
  (because builtin_command_palette() feeds /api/commands).
- All channels (Telegram, Discord, WebSocket, etc.) use the same
  dispatch path for /pairing; no more channel-level interception.
- The command still only works for already-authorised users because
  is_allowed() gates message ingestion before the bus.

Changes:
- Add handle_pairing_command() to nanobot.pairing.store — pure
  function callable from CLI, CommandRouter, and tests.
- Add cmd_pairing to nanobot.command.builtin and register in
  BUILTIN_COMMAND_SPECS + register_builtin_commands().
- Remove BaseChannel._handle_pairing_command() and the /pairing
  interception logic from _handle_message().
- Clean up unused pairing imports from base.py.
- Add unit tests for handle_pairing_command and cmd_pairing dispatch.
2026-05-15 10:05:30 +08:00
chengyongru
4e7022e73c refactor(pairing): apply simplify review fixes
- Extract format_pairing_reply() and format_expiry() to eliminate
duplication between BaseChannel and SlackChannel.
- Use _write_text_atomic() from helpers.py instead of hand-rolled
fsync logic in pairing store.
- Convert approved lists to in-memory sets for O(1) lookup.
- Remove collision retry loop (8-char entropy is sufficient).
- Fix /pairing command parsing to split prefix exactly.
- Remove unused import time from base.py.
- Fix tests to pass subcommand_text, not full /pairing string.
2026-05-15 10:05:30 +08:00
chengyongru
cf224c9701 code-review fixes: fsync, entropy, is_dm propagation, tests
- Add os.fsync with Windows-compatible directory flush in pairing store
- Increase pairing code length from 6 -> 8 characters for higher entropy
- Remove SystemExit on empty allowFrom; empty list now defers to pairing
- Update is_allowed docstring to document pairing fallback semantics
- Propagate is_dm to Matrix (direct rooms) and Slack (im channels)
- Slack _is_allowed now checks pairing store for DM allowlist mode
- Fix /pairing revoke to accept optional channel argument
- Move inline import time to module top-level
- Add WebSocket comment explaining is_dm=True assumption
- Add comprehensive tests for store and BaseChannel pairing integration
- Fix existing tests that expected empty allowFrom to hard-exit

Refs #3774
2026-05-15 10:05:30 +08:00
Xubin Ren
1f33df1ea6 fix: preserve empty dict allow_from handling
Keep dict-backed channel configs compatible with both allow_from and allowFrom without losing empty-list semantics, and add focused regression coverage for the allow-list boundary.

Made-with: Cursor
2026-04-15 01:26:51 +08:00
chengyongru
72acba5d27 refactor(tests): optimize unit test structure 2026-03-24 15:12:22 +08:00