asher-cli 0.1.1__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. {asher_cli-0.1.1 → asher_cli-0.2.0}/.claude/settings.json +6 -0
  2. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/workflows/ci.yml +4 -4
  3. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/workflows/claude-code-review.yml +2 -2
  4. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/workflows/claude.yml +2 -2
  5. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/workflows/coverage.yml +2 -2
  6. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/workflows/release.yml +3 -3
  7. {asher_cli-0.1.1 → asher_cli-0.2.0}/CLAUDE.md +15 -4
  8. {asher_cli-0.1.1 → asher_cli-0.2.0}/PKG-INFO +79 -6
  9. {asher_cli-0.1.1 → asher_cli-0.2.0}/README.md +78 -5
  10. {asher_cli-0.1.1 → asher_cli-0.2.0}/ROADMAP.md +164 -65
  11. asher_cli-0.2.0/asher/__main__.py +58 -0
  12. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/app.py +2 -0
  13. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/commands/__init__.py +146 -99
  14. asher_cli-0.2.0/asher/completion.py +113 -0
  15. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/connection/__init__.py +63 -0
  16. asher_cli-0.2.0/asher/export.py +236 -0
  17. asher_cli-0.2.0/asher/history_view.py +228 -0
  18. asher_cli-0.2.0/asher/slash-commands/__init__.py +43 -0
  19. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/ui/__init__.py +40 -2
  20. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/ui/style.tcss +17 -0
  21. {asher_cli-0.1.1 → asher_cli-0.2.0}/pyproject.toml +2 -2
  22. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_commands_pilot.py +2 -2
  23. asher_cli-0.2.0/tests/test_completion.py +571 -0
  24. asher_cli-0.2.0/tests/test_export.py +416 -0
  25. asher_cli-0.2.0/tests/test_history_view.py +276 -0
  26. {asher_cli-0.1.1 → asher_cli-0.2.0}/uv.lock +5 -5
  27. asher_cli-0.1.1/asher/__main__.py +0 -11
  28. asher_cli-0.1.1/asher/slash-commands/__init__.py +0 -19
  29. {asher_cli-0.1.1 → asher_cli-0.2.0}/.claude/hooks/block-env.ps1 +0 -0
  30. {asher_cli-0.1.1 → asher_cli-0.2.0}/.claude/skills/pylitterbot-ref/SKILL.md +0 -0
  31. {asher_cli-0.1.1 → asher_cli-0.2.0}/.claude/skills/release/SKILL.md +0 -0
  32. {asher_cli-0.1.1 → asher_cli-0.2.0}/.claude/skills/textual/SKILL.md +0 -0
  33. {asher_cli-0.1.1 → asher_cli-0.2.0}/.env.example +0 -0
  34. {asher_cli-0.1.1 → asher_cli-0.2.0}/.githooks/pre-push +0 -0
  35. {asher_cli-0.1.1 → asher_cli-0.2.0}/.github/pull_request_template.md +0 -0
  36. {asher_cli-0.1.1 → asher_cli-0.2.0}/.gitignore +0 -0
  37. {asher_cli-0.1.1 → asher_cli-0.2.0}/.vscode/launch.json +0 -0
  38. {asher_cli-0.1.1 → asher_cli-0.2.0}/.vscode/settings.json +0 -0
  39. {asher_cli-0.1.1 → asher_cli-0.2.0}/.vscode/tasks.json +0 -0
  40. {asher_cli-0.1.1 → asher_cli-0.2.0}/CODEOWNERS +0 -0
  41. {asher_cli-0.1.1 → asher_cli-0.2.0}/LICENSE +0 -0
  42. {asher_cli-0.1.1 → asher_cli-0.2.0}/app.py +0 -0
  43. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/__init__.py +0 -0
  44. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/activity_labels.py +0 -0
  45. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/auth.py +0 -0
  46. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/cats.py +0 -0
  47. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/commands/base.py +0 -0
  48. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/constants.py +0 -0
  49. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/faults.py +0 -0
  50. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/helpers.py +0 -0
  51. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/login_flow.py +0 -0
  52. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/mcp_bridge.py +0 -0
  53. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/mcp_config.py +0 -0
  54. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/monitoring/__init__.py +0 -0
  55. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/robot_adapters.py +0 -0
  56. {asher_cli-0.1.1 → asher_cli-0.2.0}/asher/robot_protocol.py +0 -0
  57. {asher_cli-0.1.1 → asher_cli-0.2.0}/renovate.json +0 -0
  58. {asher_cli-0.1.1 → asher_cli-0.2.0}/requirements.txt +0 -0
  59. {asher_cli-0.1.1 → asher_cli-0.2.0}/test.py +0 -0
  60. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/__init__.py +0 -0
  61. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/conftest.py +0 -0
  62. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_activity_labels.py +0 -0
  63. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_app_pilot.py +0 -0
  64. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_auth.py +0 -0
  65. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_auth_pilot.py +0 -0
  66. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_cats.py +0 -0
  67. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_connection.py +0 -0
  68. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_connection_mixin.py +0 -0
  69. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_faults.py +0 -0
  70. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_lr5_commands.py +0 -0
  71. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_mcp_bridge.py +0 -0
  72. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_mcp_command.py +0 -0
  73. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_mcp_config.py +0 -0
  74. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_missing_robot_commands.py +0 -0
  75. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_monitoring.py +0 -0
  76. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_new_commands_pilot.py +0 -0
  77. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_robot_adapters.py +0 -0
  78. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_ui.py +0 -0
  79. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/test_version_command.py +0 -0
  80. {asher_cli-0.1.1 → asher_cli-0.2.0}/tests/testhelpers.py +0 -0
  81. {asher_cli-0.1.1 → asher_cli-0.2.0}/watchrun.py +0 -0
@@ -1,4 +1,10 @@
1
1
  {
2
+ "enabledPlugins": {
3
+ "context7@claude-plugins-official": true,
4
+ "github@claude-plugins-official": true,
5
+ "security-guidance@claude-plugins-official": true,
6
+ "claude-md-management@claude-plugins-official": true
7
+ },
2
8
  "permissions": {
3
9
  "allow": [
4
10
  "Bash(uv run *)",
@@ -12,8 +12,8 @@ jobs:
12
12
  lint:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
16
- - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
16
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
17
17
  - run: uv sync --dev
18
18
  - run: uv run ruff check .
19
19
  - run: uv run ruff format --check .
@@ -28,7 +28,7 @@ jobs:
28
28
  os: [ubuntu-latest, windows-latest, macos-latest]
29
29
  runs-on: ${{ matrix.os }}
30
30
  steps:
31
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
32
- - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
32
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
33
33
  - run: uv sync --dev
34
34
  - run: uv run pytest tests/ -v --tb=short
@@ -27,13 +27,13 @@ jobs:
27
27
 
28
28
  steps:
29
29
  - name: Checkout repository
30
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
30
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
31
31
  with:
32
32
  fetch-depth: 1
33
33
 
34
34
  - name: Run Claude Code Review
35
35
  id: claude-review
36
- uses: anthropics/claude-code-action@af0559ee4f514d1ef21826982bed13f7edc3c35e # v1
36
+ uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1
37
37
  with:
38
38
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
39
39
  plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
@@ -26,13 +26,13 @@ jobs:
26
26
  actions: read # Required for Claude to read CI results on PRs
27
27
  steps:
28
28
  - name: Checkout repository
29
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
29
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
30
30
  with:
31
31
  fetch-depth: 1
32
32
 
33
33
  - name: Run Claude Code
34
34
  id: claude
35
- uses: anthropics/claude-code-action@af0559ee4f514d1ef21826982bed13f7edc3c35e # v1
35
+ uses: anthropics/claude-code-action@be7b93b1907a4abad570368f3c74b6fe3807510b # v1
36
36
  with:
37
37
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38
38
 
@@ -12,8 +12,8 @@ jobs:
12
12
  coverage:
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
16
- - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
16
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
17
17
  - run: uv sync --dev
18
18
  - name: Run tests with coverage
19
19
  run: uv run pytest tests/ --cov=asher --cov-report=lcov --cov-report=term-missing
@@ -16,11 +16,11 @@ jobs:
16
16
  outputs:
17
17
  version: ${{ steps.version.outputs.version }}
18
18
  steps:
19
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
20
20
  - name: Extract version from branch name
21
21
  id: version
22
22
  run: echo "version=${GITHUB_REF_NAME#release/}" >> "$GITHUB_OUTPUT"
23
- - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
23
+ - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
24
24
  - run: uv build
25
25
  - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
26
26
  with:
@@ -44,7 +44,7 @@ jobs:
44
44
  needs: [build, publish]
45
45
  runs-on: ubuntu-latest
46
46
  steps:
47
- - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
47
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
48
48
  - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
49
49
  with:
50
50
  name: dist
@@ -44,11 +44,14 @@ asher/
44
44
  mcp_config.py Claude Desktop config read/write for the /mcp slash command
45
45
  mcp_bridge.py asher-mcp-launch console script — keyring-backed pylitterbot MCP launcher
46
46
  faults.py check_faults(robot) — model-scoped safety/component fault detection (status enum + per-model attr allowlist; hopper never a fault)
47
+ history_view.py HistoryScreen (ModalScreen) + format_history_rows() — scrollable activity-history pager pushed by the `history` command
48
+ export.py shared activity-history CSV core + headless export path: build_history_csv(), resolve_dest(), resolve_robot(), _run_headless_export(), ExportError — no Textual imports; both the TUI `export` command and `asher --export` call build_history_csv()
49
+ completion.py pure helpers for command completion: slash popup (slash_matches, enter_completes, render_completion) + inline ghost text (CommandSuggester) — fed by _registry, no Textual imports except the Suggester base class
47
50
  __main__.py main() entry point
48
51
  commands/
49
52
  base.py Command ABC, SlashCommand, CommandRegistry
50
53
  __init__.py CommandsMixin — all command classes + registry + dispatch
51
- connection/ ConnectionMixin — keyring auth, _connect_worker, keyring helpers
54
+ connection/ ConnectionMixin — keyring auth, _connect_worker, keyring helpers, _connect_headless() (no-UI auth for `asher --export`)
52
55
  monitoring/ MonitoringMixin — _poll_status_interval, _refresh_status
53
56
  ui/ UIMixin — CSS, compose(), log helpers, cat helpers
54
57
  slash-commands/ Convention doc
@@ -68,6 +71,9 @@ tests/
68
71
  test_mcp_bridge.py mcp_bridge launcher credential/subprocess handling
69
72
  test_mcp_command.py /mcp slash command dispatch
70
73
  test_faults.py check_faults() — safety statuses, attribute faults, graceful degradation
74
+ test_history_view.py format_history_rows() + HistoryScreen structure + Pilot push/dismiss
75
+ test_export.py build_history_csv/resolve_dest/resolve_robot/parse_days (pure) + headless _run_headless_export (no Pilot, mocks _connect_headless)
76
+ test_completion.py slash_matches/enter_completes/render_completion (pure) + Pilot overlay visibility/navigation/accept
71
77
 
72
78
  .github/workflows/
73
79
  ci.yml ruff + mypy + pytest on every push/PR
@@ -103,10 +109,12 @@ pylitterbot ships an optional MCP server (`pip install pylitterbot[mcp]`, run vi
103
109
  ## Command convention
104
110
 
105
111
  **Normal commands** (no prefix) — robot actions only:
106
- `clean`, `status`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness <level>`, `history`, `clear`, `help`
112
+ `clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness <level>`, `wait-time <minutes>`, `power on|off`, `rename <name>`, `insight [days|month]`, `sleep-schedule`, `privacy on|off`, `volume <0-100>`, `camera-audio on|off`, `drawer-reset`, `history [count|all]`, `export [days|month]`, `clear`, `help`, `quit`
107
113
 
108
114
  **Slash commands** (`/` prefix) — app management only:
109
- `/login`, `/logout`, `/exit`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh <seconds|off>`, `/config`, `/mcp on|off|status`
115
+ `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh [seconds|off]`, `/config`, `/version`, `/mcp on|off|status`, `/exit`
116
+
117
+ > The authoritative list is the `_registry` in `asher/commands/__init__.py`; `/help` renders it at runtime. If you add a command, update the tables in `README.md` and the list in `asher/slash-commands/__init__.py`.
110
118
 
111
119
  **Special cases** (accepted both with and without `/`):
112
120
  `exit`, `quit`, `q` — exit the app
@@ -124,6 +132,7 @@ AsherApp (textual.App)
124
132
  ├── #status-bar top dock — two rows (top: name/online/night-light/lock; bottom: drawer/litter/weight/visit)
125
133
  ├── #main-area
126
134
  │ ├── #log RichLog — scrollable event/command output
135
+ │ ├── #completion-overlay Static — floating slash-command completion list (overlay: screen; hidden unless typing /); does not reserve layout space
127
136
  │ └── #cat-panel animated ASCII cat sidebar
128
137
  │ ├── #cat-fx animated FX strip
129
138
  │ ├── #cat-art the ASCII cat
@@ -149,7 +158,9 @@ LoginScreen (ModalScreen) — available in auth.py but not the primary auth path
149
158
  | `_poll_status_interval()` | `@work` — poll fallback every 300s (5 min); WebSocket is primary |
150
159
  | `_tick_cat()` | advances multi-frame cat animation every 0.4s |
151
160
  | `_dispatch_command(command, args)` | `@work` — calls `command.run(app, args)` from the registry |
152
- | `on_input_submitted()` | routes input to login flow or `_dispatch_command` via `CommandRegistry` |
161
+ | `on_input_submitted()` | routes input to login flow or `_dispatch_command` via `CommandRegistry`; Enter on a partial `/cmd` completes it instead of submitting |
162
+ | `on_input_changed()` | live-filters the `#completion-overlay` as the user types (slash commands only; hides once a space is present); also clears ghost text during the login flow |
163
+ | `on_key()` | `↑`/`↓` history nav, plus completion nav (arrows cycle the slash popup, `Tab`/`Enter` accept, `Esc` dismisses); `Tab` also accepts the inline ghost-text suggestion when the popup is closed |
153
164
  | `_start_login_flow()` | begin inline email/password prompt in command bar |
154
165
  | `_cmd_logout()` | delete creds from keyring, disconnect |
155
166
  | `make_adapter(robot)` | factory in `robot_adapters.py` — returns correct `RobotAdapter` subclass |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: asher-cli
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: Terminal dashboard for Litter Robot (LR3/LR4/LR5) via the Whisker cloud API
5
5
  License: MIT License
6
6
 
@@ -65,9 +65,12 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
65
65
  - Real-time cycling indicator with elapsed time (`⟳ Cycling M:SS`)
66
66
  - Fault & safety monitoring — model-scoped in-panel alerts for cat detected, pinch, motor/position/gas faults (LR5: bonnet/laser/drawer); press `d` to dismiss
67
67
  - Cat panel with mode label + status badges (status chip, lock, night light, sleep, wait time) under the art
68
- - Scrollable activity log with timestamps
69
- - Commands: `clean`, `status`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `history`, `export [days|month]`, `help`, `quit`
70
- - Slash commands for app management: `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh [seconds|off]`, `/config`, `/exit`
68
+ - Scrollable activity-history pager `history [count|all]` opens a full-screen, paginated view (arrow keys, `Page Up`/`Page Down`, `Home`/`End`); `q`/`Esc`/`Enter` to close
69
+ - Commands: `clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `wait-time`, `power on|off`, `rename`, `insight`, `sleep-schedule`, plus LR5 extras (`privacy`, `volume`, `camera-audio`, `drawer-reset`), `history [count|all]`, `export [days|month]`, `help`, `quit`
70
+ - Slash commands for app management: `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh [seconds|off]`, `/config`, `/version`, `/mcp on|off|status`, `/exit`
71
+ - Slash-command tab completion — type `/` and a Claude Code-style overlay lists matching commands; `↑`/`↓` to move, `Tab` or `Enter` to accept, `Esc` to dismiss
72
+ - Inline ghost-text completion for bare commands — type a prefix (`cle`) and the rest (`an`) appears greyed; `Tab` or `→` to accept → `clean`
73
+ - Headless export — `asher --export 7` writes activity history to CSV from cron / Task Scheduler / SSH without launching the TUI
71
74
  - Cat animation panel that reacts to robot state
72
75
  - Command history (↑/↓ arrows)
73
76
  - Real-time updates via WebSocket; 5-minute poll fallback
@@ -132,7 +135,16 @@ LITTER_ROBOT_PASSWORD=yourpassword
132
135
  | `sleep` / `wake` | Toggle sleep mode |
133
136
  | `night-light on\|off\|auto` | Set night light mode |
134
137
  | `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
135
- | `history` | Show last 25 activity events |
138
+ | `wait-time <minutes>` | Set clean-cycle wait time (shows valid values / current if omitted) |
139
+ | `power on\|off` | Hard-power the unit on or off |
140
+ | `rename <new name>` | Rename the unit in the Whisker cloud |
141
+ | `insight [days\|month]` | Show cycle-usage statistics (default: 30 days) |
142
+ | `sleep-schedule` | Show the per-day sleep schedule (read-only) |
143
+ | `privacy on\|off` | Toggle LR5 privacy mode |
144
+ | `volume <0-100>` | Set LR5 sound volume |
145
+ | `camera-audio on\|off` | Toggle LR5 camera audio |
146
+ | `drawer-reset` | Reset the LR5 waste drawer level indicator |
147
+ | `history [count\|all]` | Show recent activity in a scrollable pager (default: 50 events) |
136
148
  | `export [days\|month]` | Export activity history to CSV in `~/Downloads` (default: 30 days) |
137
149
  | `clear` | Clear the log |
138
150
  | `help` | Show command list |
@@ -152,9 +164,43 @@ LITTER_ROBOT_PASSWORD=yourpassword
152
164
  | `/cat color <hex>` | Change the cat art colour (e.g. `/cat color #ff79c6`); `/cat reset` to revert |
153
165
  | `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
154
166
  | `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet) |
167
+ | `/version` | Show version info (asher-cli, Python, pylitterbot, textual) |
168
+ | `/mcp on\|off\|status` | Toggle the Litter-Robot MCP server entry in Claude Desktop |
155
169
  | `/exit` | Exit Asher CLI |
156
170
 
157
- **Keyboard shortcuts:** `Ctrl+L` clears the log, `Ctrl+C` quits.
171
+ **Keyboard shortcuts:** `Ctrl+L` clears the log, `Ctrl+C` quits. While typing a `/` slash command, `↑`/`↓` move through completions, `Tab` or `Enter` accepts, `Esc` dismisses. While typing a bare command, a greyed ghost suggestion appears — `Tab` or `→` accepts it.
172
+
173
+ ### Headless export (cron / Task Scheduler / SSH)
174
+
175
+ `--export` writes the same CSV as the `export` command **without launching the TUI** — so you can script activity-history exports from cron, Windows Task Scheduler, or a server over SSH. No flags launches the interactive dashboard as before.
176
+
177
+ ```bash
178
+ asher --export 7 export last 7 days to ~/Downloads
179
+ asher --export 7 --output ~/hist.csv explicit output path
180
+ asher --export month --robot "Asher 2" 30 days (Whisker ceiling) for a specific robot
181
+ ```
182
+
183
+ `--robot` accepts an index or a partial, case-insensitive name (defaults to your saved preferred robot, else the first). Credentials use the same keyring → `.env` priority as the TUI, but with **no interactive login prompt** — a scheduled task can't type a password, so sign in once with `/login` first.
184
+
185
+ Exit codes for scripting:
186
+
187
+ | Code | Meaning |
188
+ |---|---|
189
+ | `0` | export succeeded |
190
+ | `1` | no credentials found (keyring or `.env`) |
191
+ | `2` | connection or API failure |
192
+ | `3` | failed to write the CSV (permissions, disk full) |
193
+ | `4` | `--robot` matched no robot on the account |
194
+
195
+ ```bash
196
+ # crontab — nightly export at 03:00
197
+ 0 3 * * * /usr/bin/env asher --export 7 --output /home/me/litter-history.csv >> /var/log/asher-export.log 2>&1
198
+ ```
199
+
200
+ ```powershell
201
+ # Windows Task Scheduler action
202
+ asher.exe --export 7 --output C:\Users\me\litter-history.csv
203
+ ```
158
204
 
159
205
  ## Releasing
160
206
 
@@ -262,6 +308,33 @@ uv run poe check # run all of the above + tests (same as CI)
262
308
 
263
309
  CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every push.
264
310
 
311
+ ## Changelog
312
+
313
+ ### Unreleased
314
+
315
+ ### v0.2.0 — 2026-07-27
316
+
317
+ - **Headless export** — `asher --export 7` writes activity history to CSV without launching the TUI, for cron / Task Scheduler / SSH. `--output` and `--robot <index|name>` flags select the destination and robot; documented exit codes for scripting.
318
+ - **Activity-history pager** — `history` now opens a full-screen, scrollable view instead of dumping into the main log. Page through long histories with the arrow keys / `Page Up`/`Page Down` / `Home`/`End`; `q`, `Esc`, or `Enter` closes it. Accepts an optional event count (`history 100`) or `all` (default: 50).
319
+
320
+ ### v0.1.1
321
+
322
+ - **Token persistence** — the OAuth session token is now saved to the keyring, so re-logins are skipped on subsequent launches.
323
+ - **`/version`** — new slash command showing asher-cli, Python, pylitterbot, and textual versions.
324
+ - **Sleep-schedule viewer** — new `sleep-schedule` command renders the per-day schedule (read-only).
325
+ - **Cat panel badges** — mode label plus status chips (status, lock, night light, sleep, wait time) under the cat art.
326
+ - **Fault & safety monitoring** — model-scoped, enum-aware detection with an in-panel banner; press `d` to dismiss.
327
+ - **Cycling indicator** — real-time elapsed timer (`⟳ Cycling M:SS`).
328
+
329
+ ### v0.1.0
330
+
331
+ - **Readable status & history** — robot status and activity events now render as plain English instead of raw enum values.
332
+ - **Missing robot commands** — added `wait-time`, `power on|off`, `rename`, `insight`, and split `status` (summary) from `info` (full property dump).
333
+ - **LR5 extras** — `privacy`, `volume`, `camera-audio`, and `drawer-reset` wired up via the robot adapter (gracefully refused on LR3/LR4).
334
+ - **MCP bridge** — keyring-backed `pylitterbot[mcp]` launcher with Claude Desktop config management (`/mcp on|off|status`).
335
+
336
+ Full history: see the [commit log](https://github.com/karanshukla/asher-cli/commits/main).
337
+
265
338
  ## Notes
266
339
 
267
340
  - Uses the unofficial [pylitterbot](https://github.com/natekspencer/pylitterbot) library — supports LR3, LR4, LR5, and other Whisker robots
@@ -19,9 +19,12 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
19
19
  - Real-time cycling indicator with elapsed time (`⟳ Cycling M:SS`)
20
20
  - Fault & safety monitoring — model-scoped in-panel alerts for cat detected, pinch, motor/position/gas faults (LR5: bonnet/laser/drawer); press `d` to dismiss
21
21
  - Cat panel with mode label + status badges (status chip, lock, night light, sleep, wait time) under the art
22
- - Scrollable activity log with timestamps
23
- - Commands: `clean`, `status`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `history`, `export [days|month]`, `help`, `quit`
24
- - Slash commands for app management: `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh [seconds|off]`, `/config`, `/exit`
22
+ - Scrollable activity-history pager `history [count|all]` opens a full-screen, paginated view (arrow keys, `Page Up`/`Page Down`, `Home`/`End`); `q`/`Esc`/`Enter` to close
23
+ - Commands: `clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `wait-time`, `power on|off`, `rename`, `insight`, `sleep-schedule`, plus LR5 extras (`privacy`, `volume`, `camera-audio`, `drawer-reset`), `history [count|all]`, `export [days|month]`, `help`, `quit`
24
+ - Slash commands for app management: `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|color <hex>`, `/refresh [seconds|off]`, `/config`, `/version`, `/mcp on|off|status`, `/exit`
25
+ - Slash-command tab completion — type `/` and a Claude Code-style overlay lists matching commands; `↑`/`↓` to move, `Tab` or `Enter` to accept, `Esc` to dismiss
26
+ - Inline ghost-text completion for bare commands — type a prefix (`cle`) and the rest (`an`) appears greyed; `Tab` or `→` to accept → `clean`
27
+ - Headless export — `asher --export 7` writes activity history to CSV from cron / Task Scheduler / SSH without launching the TUI
25
28
  - Cat animation panel that reacts to robot state
26
29
  - Command history (↑/↓ arrows)
27
30
  - Real-time updates via WebSocket; 5-minute poll fallback
@@ -86,7 +89,16 @@ LITTER_ROBOT_PASSWORD=yourpassword
86
89
  | `sleep` / `wake` | Toggle sleep mode |
87
90
  | `night-light on\|off\|auto` | Set night light mode |
88
91
  | `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
89
- | `history` | Show last 25 activity events |
92
+ | `wait-time <minutes>` | Set clean-cycle wait time (shows valid values / current if omitted) |
93
+ | `power on\|off` | Hard-power the unit on or off |
94
+ | `rename <new name>` | Rename the unit in the Whisker cloud |
95
+ | `insight [days\|month]` | Show cycle-usage statistics (default: 30 days) |
96
+ | `sleep-schedule` | Show the per-day sleep schedule (read-only) |
97
+ | `privacy on\|off` | Toggle LR5 privacy mode |
98
+ | `volume <0-100>` | Set LR5 sound volume |
99
+ | `camera-audio on\|off` | Toggle LR5 camera audio |
100
+ | `drawer-reset` | Reset the LR5 waste drawer level indicator |
101
+ | `history [count\|all]` | Show recent activity in a scrollable pager (default: 50 events) |
90
102
  | `export [days\|month]` | Export activity history to CSV in `~/Downloads` (default: 30 days) |
91
103
  | `clear` | Clear the log |
92
104
  | `help` | Show command list |
@@ -106,9 +118,43 @@ LITTER_ROBOT_PASSWORD=yourpassword
106
118
  | `/cat color <hex>` | Change the cat art colour (e.g. `/cat color #ff79c6`); `/cat reset` to revert |
107
119
  | `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
108
120
  | `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet) |
121
+ | `/version` | Show version info (asher-cli, Python, pylitterbot, textual) |
122
+ | `/mcp on\|off\|status` | Toggle the Litter-Robot MCP server entry in Claude Desktop |
109
123
  | `/exit` | Exit Asher CLI |
110
124
 
111
- **Keyboard shortcuts:** `Ctrl+L` clears the log, `Ctrl+C` quits.
125
+ **Keyboard shortcuts:** `Ctrl+L` clears the log, `Ctrl+C` quits. While typing a `/` slash command, `↑`/`↓` move through completions, `Tab` or `Enter` accepts, `Esc` dismisses. While typing a bare command, a greyed ghost suggestion appears — `Tab` or `→` accepts it.
126
+
127
+ ### Headless export (cron / Task Scheduler / SSH)
128
+
129
+ `--export` writes the same CSV as the `export` command **without launching the TUI** — so you can script activity-history exports from cron, Windows Task Scheduler, or a server over SSH. No flags launches the interactive dashboard as before.
130
+
131
+ ```bash
132
+ asher --export 7 export last 7 days to ~/Downloads
133
+ asher --export 7 --output ~/hist.csv explicit output path
134
+ asher --export month --robot "Asher 2" 30 days (Whisker ceiling) for a specific robot
135
+ ```
136
+
137
+ `--robot` accepts an index or a partial, case-insensitive name (defaults to your saved preferred robot, else the first). Credentials use the same keyring → `.env` priority as the TUI, but with **no interactive login prompt** — a scheduled task can't type a password, so sign in once with `/login` first.
138
+
139
+ Exit codes for scripting:
140
+
141
+ | Code | Meaning |
142
+ |---|---|
143
+ | `0` | export succeeded |
144
+ | `1` | no credentials found (keyring or `.env`) |
145
+ | `2` | connection or API failure |
146
+ | `3` | failed to write the CSV (permissions, disk full) |
147
+ | `4` | `--robot` matched no robot on the account |
148
+
149
+ ```bash
150
+ # crontab — nightly export at 03:00
151
+ 0 3 * * * /usr/bin/env asher --export 7 --output /home/me/litter-history.csv >> /var/log/asher-export.log 2>&1
152
+ ```
153
+
154
+ ```powershell
155
+ # Windows Task Scheduler action
156
+ asher.exe --export 7 --output C:\Users\me\litter-history.csv
157
+ ```
112
158
 
113
159
  ## Releasing
114
160
 
@@ -216,6 +262,33 @@ uv run poe check # run all of the above + tests (same as CI)
216
262
 
217
263
  CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every push.
218
264
 
265
+ ## Changelog
266
+
267
+ ### Unreleased
268
+
269
+ ### v0.2.0 — 2026-07-27
270
+
271
+ - **Headless export** — `asher --export 7` writes activity history to CSV without launching the TUI, for cron / Task Scheduler / SSH. `--output` and `--robot <index|name>` flags select the destination and robot; documented exit codes for scripting.
272
+ - **Activity-history pager** — `history` now opens a full-screen, scrollable view instead of dumping into the main log. Page through long histories with the arrow keys / `Page Up`/`Page Down` / `Home`/`End`; `q`, `Esc`, or `Enter` closes it. Accepts an optional event count (`history 100`) or `all` (default: 50).
273
+
274
+ ### v0.1.1
275
+
276
+ - **Token persistence** — the OAuth session token is now saved to the keyring, so re-logins are skipped on subsequent launches.
277
+ - **`/version`** — new slash command showing asher-cli, Python, pylitterbot, and textual versions.
278
+ - **Sleep-schedule viewer** — new `sleep-schedule` command renders the per-day schedule (read-only).
279
+ - **Cat panel badges** — mode label plus status chips (status, lock, night light, sleep, wait time) under the cat art.
280
+ - **Fault & safety monitoring** — model-scoped, enum-aware detection with an in-panel banner; press `d` to dismiss.
281
+ - **Cycling indicator** — real-time elapsed timer (`⟳ Cycling M:SS`).
282
+
283
+ ### v0.1.0
284
+
285
+ - **Readable status & history** — robot status and activity events now render as plain English instead of raw enum values.
286
+ - **Missing robot commands** — added `wait-time`, `power on|off`, `rename`, `insight`, and split `status` (summary) from `info` (full property dump).
287
+ - **LR5 extras** — `privacy`, `volume`, `camera-audio`, and `drawer-reset` wired up via the robot adapter (gracefully refused on LR3/LR4).
288
+ - **MCP bridge** — keyring-backed `pylitterbot[mcp]` launcher with Claude Desktop config management (`/mcp on|off|status`).
289
+
290
+ Full history: see the [commit log](https://github.com/karanshukla/asher-cli/commits/main).
291
+
219
292
  ## Notes
220
293
 
221
294
  - Uses the unofficial [pylitterbot](https://github.com/natekspencer/pylitterbot) library — supports LR3, LR4, LR5, and other Whisker robots