asher-cli 0.2.0__tar.gz → 1.0.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.
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/workflows/release.yml +16 -1
- asher_cli-1.0.0/CHANGELOG.md +87 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/CLAUDE.md +9 -3
- {asher_cli-0.2.0 → asher_cli-1.0.0}/PKG-INFO +47 -36
- {asher_cli-0.2.0 → asher_cli-1.0.0}/README.md +41 -35
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/app.py +14 -5
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/commands/__init__.py +138 -7
- asher_cli-1.0.0/asher/config.py +66 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/faults.py +6 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/monitoring/__init__.py +19 -1
- asher_cli-1.0.0/asher/notifications.py +48 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/robot_adapters.py +47 -1
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/robot_protocol.py +5 -1
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/slash-commands/__init__.py +2 -1
- asher_cli-1.0.0/cliff.toml +102 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0/docs}/ROADMAP.md +123 -902
- asher_cli-1.0.0/docs/roadmap-archive/README.md +16 -0
- asher_cli-1.0.0/docs/roadmap-archive/cat-panel-badges.md +100 -0
- asher_cli-1.0.0/docs/roadmap-archive/config-persistence.md +42 -0
- asher_cli-1.0.0/docs/roadmap-archive/desktop-notifications.md +123 -0
- asher_cli-1.0.0/docs/roadmap-archive/fault-monitoring.md +131 -0
- asher_cli-1.0.0/docs/roadmap-archive/headless-export.md +180 -0
- asher_cli-1.0.0/docs/roadmap-archive/history-export.md +117 -0
- asher_cli-1.0.0/docs/roadmap-archive/tab-completion.md +90 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/pyproject.toml +11 -2
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/conftest.py +2 -0
- asher_cli-1.0.0/tests/test_config.py +357 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_faults.py +29 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_lr5_commands.py +63 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_monitoring.py +83 -1
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_new_commands_pilot.py +17 -1
- asher_cli-1.0.0/tests/test_notifications.py +82 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_robot_adapters.py +88 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/uv.lock +34 -1
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.claude/hooks/block-env.ps1 +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.claude/settings.json +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.claude/skills/pylitterbot-ref/SKILL.md +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.claude/skills/release/SKILL.md +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.claude/skills/textual/SKILL.md +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.env.example +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.githooks/pre-push +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/pull_request_template.md +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/workflows/ci.yml +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/workflows/claude-code-review.yml +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/workflows/claude.yml +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.github/workflows/coverage.yml +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.gitignore +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.vscode/launch.json +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.vscode/settings.json +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/.vscode/tasks.json +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/CODEOWNERS +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/LICENSE +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/app.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/__init__.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/__main__.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/activity_labels.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/auth.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/cats.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/commands/base.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/completion.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/connection/__init__.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/constants.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/export.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/helpers.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/history_view.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/login_flow.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/mcp_bridge.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/mcp_config.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/ui/__init__.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/asher/ui/style.tcss +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/renovate.json +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/requirements.txt +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/test.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/__init__.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_activity_labels.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_app_pilot.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_auth.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_auth_pilot.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_cats.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_commands_pilot.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_completion.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_connection.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_connection_mixin.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_export.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_history_view.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_mcp_bridge.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_mcp_command.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_mcp_config.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_missing_robot_commands.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_ui.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/test_version_command.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/tests/testhelpers.py +0 -0
- {asher_cli-0.2.0 → asher_cli-1.0.0}/watchrun.py +0 -0
|
@@ -44,11 +44,26 @@ jobs:
|
|
|
44
44
|
needs: [build, publish]
|
|
45
45
|
runs-on: ubuntu-latest
|
|
46
46
|
steps:
|
|
47
|
+
# Full history (fetch-depth: 0) so git-cliff can walk commits/tags.
|
|
47
48
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
49
|
+
with:
|
|
50
|
+
fetch-depth: 0
|
|
48
51
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
49
52
|
with:
|
|
50
53
|
name: dist
|
|
51
54
|
path: dist/
|
|
55
|
+
- uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
|
|
56
|
+
- name: Install git-cliff
|
|
57
|
+
run: uv tool install git-cliff
|
|
58
|
+
- name: Generate release notes with git-cliff
|
|
59
|
+
env:
|
|
60
|
+
VERSION: ${{ needs.build.outputs.version }}
|
|
61
|
+
run: |
|
|
62
|
+
# Explicit -c cliff.toml avoids auto-discovering pyproject.toml.
|
|
63
|
+
# Pin the just-released version so git-cliff groups its commits under
|
|
64
|
+
# the right heading even before the tag is fetched, then emit only
|
|
65
|
+
# that section (--latest) with the header stripped.
|
|
66
|
+
git cliff -c cliff.toml --tag "v${VERSION}" --latest --strip header -o RELEASE_NOTES.md
|
|
52
67
|
- name: Create release
|
|
53
68
|
env:
|
|
54
69
|
GH_TOKEN: ${{ github.token }}
|
|
@@ -56,5 +71,5 @@ jobs:
|
|
|
56
71
|
run: |
|
|
57
72
|
gh release create "v${VERSION}" dist/* \
|
|
58
73
|
--title "v${VERSION}" \
|
|
59
|
-
--
|
|
74
|
+
--notes-file RELEASE_NOTES.md \
|
|
60
75
|
--verify-tag=false
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to asher-cli are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Generated by [git-cliff](https://git-cliff.org) from conventional commits.
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
### 🚀 Features
|
|
13
|
+
|
|
14
|
+
- *(robot)* Complete LR3/LR4 non-destructive support
|
|
15
|
+
- *(notify)* Desktop toast notifications for fault events + /notify command
|
|
16
|
+
- *(commands)* Accept /cat colour spelling (color as alias)
|
|
17
|
+
- *(config)* Persist runtime settings to ~/.asher-cli/config.json
|
|
18
|
+
|
|
19
|
+
### 📚 Documentation
|
|
20
|
+
|
|
21
|
+
- *(roadmap)* Archive completed sections to docs/roadmap-archive/
|
|
22
|
+
|
|
23
|
+
### 🔧 Miscellaneous
|
|
24
|
+
|
|
25
|
+
- *(release)* Move ROADMAP to docs/, add git-cliff CHANGELOG automation
|
|
26
|
+
|
|
27
|
+
## [0.2.0] - 2026-07-27
|
|
28
|
+
|
|
29
|
+
### 🚀 Features
|
|
30
|
+
|
|
31
|
+
- *(export)* Headless --export for cron/automation (ROADMAP §25)
|
|
32
|
+
- *(completion)* Inline ghost-text suggestions for bare commands
|
|
33
|
+
- *(completion)* Claude Code-style slash-command tab completion
|
|
34
|
+
- *(history)* Aligned timestamps + rich pager header/footer
|
|
35
|
+
- *(history)* Scrollable pager sub-view for activity history
|
|
36
|
+
|
|
37
|
+
### 📚 Documentation
|
|
38
|
+
|
|
39
|
+
- *(changelog)* Cut v0.2.0
|
|
40
|
+
- *(commands)* Sync stale command lists in CLAUDE.md and slash-commands docstring
|
|
41
|
+
- *(readme)* Sync command tables with code, add changelog
|
|
42
|
+
|
|
43
|
+
### 🔧 Miscellaneous
|
|
44
|
+
|
|
45
|
+
- Declare repo-level Claude Code plugins
|
|
46
|
+
|
|
47
|
+
## [0.1.1] - 2026-07-21
|
|
48
|
+
|
|
49
|
+
### 🚀 Features
|
|
50
|
+
|
|
51
|
+
- *(commands)* Add /version slash command and sleep-schedule viewer
|
|
52
|
+
- *(connection)* Persist OAuth session token in keyring
|
|
53
|
+
- *(ui)* Cat panel badges, fault banner, cycling elapsed timer
|
|
54
|
+
|
|
55
|
+
### 🐛 Bug Fixes
|
|
56
|
+
|
|
57
|
+
- *(faults,panel)* Model-scoped detection; aligned complementary badges
|
|
58
|
+
- *(faults)* Enum-aware detection; restore top rows; banner in cat panel
|
|
59
|
+
|
|
60
|
+
### 📚 Documentation
|
|
61
|
+
|
|
62
|
+
- *(roadmap)* Mark token persistence, /version, sleep-schedule done
|
|
63
|
+
|
|
64
|
+
## [0.1.0] - 2026-07-20
|
|
65
|
+
|
|
66
|
+
### 🚀 Features
|
|
67
|
+
|
|
68
|
+
- *(lr5)* Wire up privacy, volume, camera-audio, drawer-reset
|
|
69
|
+
- *(commands)* Split status/info, add info; fix flaky export test
|
|
70
|
+
- *(commands)* Add wait-time, power, rename, insight
|
|
71
|
+
- *(history)* Render readable, colour-coded event labels
|
|
72
|
+
|
|
73
|
+
### 🐛 Bug Fixes
|
|
74
|
+
|
|
75
|
+
- *(status)* Render readable status text, not enum repr
|
|
76
|
+
|
|
77
|
+
### 📚 Documentation
|
|
78
|
+
|
|
79
|
+
- *(roadmap)* Mark testing/coverage/versioning/CI as done
|
|
80
|
+
- *(roadmap)* Mark LR5 extras (privacy/volume/camera-audio/drawer-reset) done
|
|
81
|
+
- *(roadmap)* Mark wait-time/power/rename/insight + status/info split done
|
|
82
|
+
|
|
83
|
+
### 🔧 Miscellaneous
|
|
84
|
+
|
|
85
|
+
- Add CODEOWNERS to auto-request review on PRs
|
|
86
|
+
|
|
87
|
+
<!-- generated by git-cliff -->
|
|
@@ -37,13 +37,15 @@ asher/
|
|
|
37
37
|
auth.py LoginScreen modal (ModalScreen[tuple[str,str]]) — available, not primary flow
|
|
38
38
|
helpers.py fmt_ago(), drawer_bar(), ts(), robot_model() (pure, testable)
|
|
39
39
|
constants.py STATUS_COLORS, ROBOT_MODELS
|
|
40
|
+
config.py runtime settings persistence — load()/save()/update() over ~/.asher-cli/config.json; holds poll interval, cat-panel visibility/colour, active pet index, notification settings (non-secret UI prefs only; credentials stay in keyring)
|
|
41
|
+
notifications.py desktop toast + audible alert façade over plyer (fire/beep, always-safe no-op on failure/headless)
|
|
40
42
|
cats.py CATS dict (ASCII art)
|
|
41
43
|
login_flow.py LoginFlow state machine — inline email/password prompt in command bar
|
|
42
44
|
robot_protocol.py RobotProtocol structural Protocol for pylitterbot robot objects
|
|
43
45
|
robot_adapters.py RobotAdapter ABC + LR3/LR4/LR5 subclasses + make_adapter() factory
|
|
44
46
|
mcp_config.py Claude Desktop config read/write for the /mcp slash command
|
|
45
47
|
mcp_bridge.py asher-mcp-launch console script — keyring-backed pylitterbot MCP launcher
|
|
46
|
-
faults.py check_faults(robot) — model-scoped safety/component fault detection (status enum + per-model attr allowlist; hopper never a fault)
|
|
48
|
+
faults.py check_faults(robot) — model-scoped safety/component fault detection (status enum + per-model attr allowlist incl. LR4 USB power fault; hopper never a fault)
|
|
47
49
|
history_view.py HistoryScreen (ModalScreen) + format_history_rows() — scrollable activity-history pager pushed by the `history` command
|
|
48
50
|
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
51
|
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
|
|
@@ -68,6 +70,8 @@ tests/
|
|
|
68
70
|
test_monitoring.py MonitoringMixin async methods
|
|
69
71
|
test_ui.py UIMixin constants, CSS, helper existence
|
|
70
72
|
test_mcp_config.py Claude Desktop config read/write
|
|
73
|
+
test_config.py runtime settings persistence — load/save/update over defaults
|
|
74
|
+
test_notifications.py plyer toast + beep façade — always-safe no-op paths
|
|
71
75
|
test_mcp_bridge.py mcp_bridge launcher credential/subprocess handling
|
|
72
76
|
test_mcp_command.py /mcp slash command dispatch
|
|
73
77
|
test_faults.py check_faults() — safety statuses, attribute faults, graceful degradation
|
|
@@ -109,10 +113,12 @@ pylitterbot ships an optional MCP server (`pip install pylitterbot[mcp]`, run vi
|
|
|
109
113
|
## Command convention
|
|
110
114
|
|
|
111
115
|
**Normal commands** (no prefix) — robot actions only:
|
|
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`
|
|
116
|
+
`clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness <level>`, `panel-brightness <low|medium|high>`, `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`
|
|
113
117
|
|
|
114
118
|
**Slash commands** (`/` prefix) — app management only:
|
|
115
|
-
`/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|
|
|
119
|
+
`/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|colour <hex>`, `/refresh [seconds|off]`, `/config`, `/notify on|off|sound on|off|test`, `/version`, `/mcp on|off|status`, `/exit`
|
|
120
|
+
|
|
121
|
+
`/refresh`, `/cat`, `/pet`, and `/notify` persist their settings to `~/.asher-cli/config.json` (via `asher.config.update()`), so they survive restarts. Credentials and the preferred-robot serial stay in the OS keyring; the config file holds only non-secret UI preferences.
|
|
116
122
|
|
|
117
123
|
> 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`.
|
|
118
124
|
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: asher-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.0
|
|
4
4
|
Summary: Terminal dashboard for Litter Robot (LR3/LR4/LR5) via the Whisker cloud API
|
|
5
|
+
Project-URL: Homepage, https://github.com/karanshukla/asher-cli
|
|
6
|
+
Project-URL: Repository, https://github.com/karanshukla/asher-cli
|
|
7
|
+
Project-URL: Issues, https://github.com/karanshukla/asher-cli/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/karanshukla/asher-cli/blob/main/CHANGELOG.md
|
|
5
9
|
License: MIT License
|
|
6
10
|
|
|
7
11
|
Copyright (c) 2026 Karz
|
|
@@ -35,6 +39,7 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
35
39
|
Classifier: Topic :: Home Automation
|
|
36
40
|
Requires-Python: >=3.10
|
|
37
41
|
Requires-Dist: keyring>=24.0.0
|
|
42
|
+
Requires-Dist: plyer>=2.1.0
|
|
38
43
|
Requires-Dist: pylitterbot==2025.6.2
|
|
39
44
|
Requires-Dist: python-dotenv>=1.0.0
|
|
40
45
|
Requires-Dist: rich>=13.0.0
|
|
@@ -66,8 +71,8 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
|
|
|
66
71
|
- 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
72
|
- Cat panel with mode label + status badges (status chip, lock, night light, sleep, wait time) under the art
|
|
68
73
|
- 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|
|
|
74
|
+
- Commands: `clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `panel-brightness <low|medium|high>` (LR4/LR5), `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`
|
|
75
|
+
- Slash commands for app management: `/login`, `/logout`, `/robots`, `/robot <index|name>`, `/pets`, `/pet <index|name>`, `/cat on|off|colour <hex>`, `/refresh [seconds|off]`, `/config`, `/notify on|off|sound on|off|test`, `/version`, `/mcp on|off|status`, `/exit`
|
|
71
76
|
- 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
77
|
- Inline ghost-text completion for bare commands — type a prefix (`cle`) and the rest (`an`) appears greyed; `Tab` or `→` to accept → `clean`
|
|
73
78
|
- Headless export — `asher --export 7` writes activity history to CSV from cron / Task Scheduler / SSH without launching the TUI
|
|
@@ -135,6 +140,7 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
135
140
|
| `sleep` / `wake` | Toggle sleep mode |
|
|
136
141
|
| `night-light on\|off\|auto` | Set night light mode |
|
|
137
142
|
| `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
|
|
143
|
+
| `panel-brightness <low\|medium\|high>` | Set control-panel brightness (LR4/LR5 only; shows current if omitted) |
|
|
138
144
|
| `wait-time <minutes>` | Set clean-cycle wait time (shows valid values / current if omitted) |
|
|
139
145
|
| `power on\|off` | Hard-power the unit on or off |
|
|
140
146
|
| `rename <new name>` | Rename the unit in the Whisker cloud |
|
|
@@ -161,9 +167,10 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
161
167
|
| `/pets` | List all pets on the account |
|
|
162
168
|
| `/pet <index\|name>` | Switch which pet's name/weight shows in the status bar |
|
|
163
169
|
| `/cat on\|off` | Show or hide the cat animation panel |
|
|
164
|
-
| `/cat
|
|
170
|
+
| `/cat colour <hex>` | Change the cat art colour (e.g. `/cat colour #ff79c6`); `color` also accepted; `/cat reset` to revert |
|
|
165
171
|
| `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
|
|
166
|
-
| `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet) |
|
|
172
|
+
| `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet, notifications) |
|
|
173
|
+
| `/notify on\|off\|sound on\|off\|test` | Toggle desktop toast notifications for fault events (cat detected, pinch, motor fault, drawer full); `test` fires a sample toast |
|
|
167
174
|
| `/version` | Show version info (asher-cli, Python, pylitterbot, textual) |
|
|
168
175
|
| `/mcp on\|off\|status` | Toggle the Litter-Robot MCP server entry in Claude Desktop |
|
|
169
176
|
| `/exit` | Exit Asher CLI |
|
|
@@ -202,21 +209,47 @@ Exit codes for scripting:
|
|
|
202
209
|
asher.exe --export 7 --output C:\Users\me\litter-history.csv
|
|
203
210
|
```
|
|
204
211
|
|
|
212
|
+
## Configuration
|
|
213
|
+
|
|
214
|
+
Runtime settings persist across restarts in `~/.asher-cli/config.json`, so you don't have to re-apply `/refresh 60`, `/cat colour #ff79c6`, or `/pet 1` every launch. The file is auto-created on first change and holds six non-secret UI preferences:
|
|
215
|
+
|
|
216
|
+
| Setting | Slash command | Default |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `poll_interval_seconds` | `/refresh <seconds\|off>` | `300` |
|
|
219
|
+
| `cat_panel_visible` | `/cat on\|off` | `true` |
|
|
220
|
+
| `cat_panel_color` | `/cat colour <hex>\|reset` | `null` (default palette) |
|
|
221
|
+
| `active_pet_index` | `/pet <index\|name>` | `0` |
|
|
222
|
+
| `notifications` | `/notify on\|off` | `true` |
|
|
223
|
+
| `notification_sound` | `/notify sound on\|off` | `false` |
|
|
224
|
+
|
|
225
|
+
Credentials and the preferred-robot serial stay in the OS keyring; `.env` vars stay as env vars. You generally don't need to edit the file by hand — just use the slash commands — but it's plain JSON and safe to inspect or delete (deleting it restores defaults).
|
|
226
|
+
|
|
205
227
|
## Releasing
|
|
206
228
|
|
|
207
229
|
```bash
|
|
208
|
-
#
|
|
209
|
-
uv run
|
|
210
|
-
|
|
211
|
-
|
|
230
|
+
# 1. regenerate CHANGELOG.md from conventional commits (idempotent), then commit it
|
|
231
|
+
uv run poe changelog
|
|
232
|
+
git add CHANGELOG.md
|
|
233
|
+
git commit -m "docs(changelog): update for next release"
|
|
234
|
+
|
|
235
|
+
# 2. bump version, commit, and tag in one step, then push with tags
|
|
236
|
+
uv run bump-my-version bump patch # 0.2.0 → 0.2.1
|
|
237
|
+
uv run bump-my-version bump minor # 0.2.0 → 0.3.0
|
|
238
|
+
uv run bump-my-version bump major # 0.2.0 → 1.0.0
|
|
212
239
|
|
|
213
240
|
git push && git push --tags
|
|
214
241
|
|
|
215
|
-
#
|
|
216
|
-
|
|
217
|
-
git
|
|
242
|
+
# 3. push the release branch to trigger PyPI publish (OIDC) + GitHub Release
|
|
243
|
+
# (release notes auto-generated by git-cliff from the same cliff.toml)
|
|
244
|
+
git checkout -b release/X.Y.Z
|
|
245
|
+
git push origin release/X.Y.Z
|
|
218
246
|
```
|
|
219
247
|
|
|
248
|
+
`CHANGELOG.md` is generated by [git-cliff](https://git-cliff.org) from
|
|
249
|
+
conventional commits — see [`cliff.toml`](cliff.toml). Commit messages must use
|
|
250
|
+
`feat:`/`fix:`/`docs:`/etc. prefixes (optionally scoped, e.g. `feat(robot):`)
|
|
251
|
+
to appear in the changelog.
|
|
252
|
+
|
|
220
253
|
## Troubleshooting
|
|
221
254
|
|
|
222
255
|
**`asher` not found after `pip install asher-cli`**
|
|
@@ -310,30 +343,8 @@ CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every
|
|
|
310
343
|
|
|
311
344
|
## Changelog
|
|
312
345
|
|
|
313
|
-
|
|
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).
|
|
346
|
+
The full, maintained release history lives in [CHANGELOG.md](CHANGELOG.md),
|
|
347
|
+
auto-generated from conventional commits by [git-cliff](https://git-cliff.org).
|
|
337
348
|
|
|
338
349
|
## Notes
|
|
339
350
|
|
|
@@ -20,8 +20,8 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
|
|
|
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
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|
|
|
23
|
+
- Commands: `clean`, `status`, `info`, `lock`, `unlock`, `sleep`, `wake`, `night-light on|off|auto`, `night-light-brightness`, `panel-brightness <low|medium|high>` (LR4/LR5), `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|colour <hex>`, `/refresh [seconds|off]`, `/config`, `/notify on|off|sound on|off|test`, `/version`, `/mcp on|off|status`, `/exit`
|
|
25
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
26
|
- Inline ghost-text completion for bare commands — type a prefix (`cle`) and the rest (`an`) appears greyed; `Tab` or `→` to accept → `clean`
|
|
27
27
|
- Headless export — `asher --export 7` writes activity history to CSV from cron / Task Scheduler / SSH without launching the TUI
|
|
@@ -89,6 +89,7 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
89
89
|
| `sleep` / `wake` | Toggle sleep mode |
|
|
90
90
|
| `night-light on\|off\|auto` | Set night light mode |
|
|
91
91
|
| `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
|
|
92
|
+
| `panel-brightness <low\|medium\|high>` | Set control-panel brightness (LR4/LR5 only; shows current if omitted) |
|
|
92
93
|
| `wait-time <minutes>` | Set clean-cycle wait time (shows valid values / current if omitted) |
|
|
93
94
|
| `power on\|off` | Hard-power the unit on or off |
|
|
94
95
|
| `rename <new name>` | Rename the unit in the Whisker cloud |
|
|
@@ -115,9 +116,10 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
115
116
|
| `/pets` | List all pets on the account |
|
|
116
117
|
| `/pet <index\|name>` | Switch which pet's name/weight shows in the status bar |
|
|
117
118
|
| `/cat on\|off` | Show or hide the cat animation panel |
|
|
118
|
-
| `/cat
|
|
119
|
+
| `/cat colour <hex>` | Change the cat art colour (e.g. `/cat colour #ff79c6`); `color` also accepted; `/cat reset` to revert |
|
|
119
120
|
| `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
|
|
120
|
-
| `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet) |
|
|
121
|
+
| `/config` | Show current runtime settings (robot, refresh rate, cat panel, active pet, notifications) |
|
|
122
|
+
| `/notify on\|off\|sound on\|off\|test` | Toggle desktop toast notifications for fault events (cat detected, pinch, motor fault, drawer full); `test` fires a sample toast |
|
|
121
123
|
| `/version` | Show version info (asher-cli, Python, pylitterbot, textual) |
|
|
122
124
|
| `/mcp on\|off\|status` | Toggle the Litter-Robot MCP server entry in Claude Desktop |
|
|
123
125
|
| `/exit` | Exit Asher CLI |
|
|
@@ -156,21 +158,47 @@ Exit codes for scripting:
|
|
|
156
158
|
asher.exe --export 7 --output C:\Users\me\litter-history.csv
|
|
157
159
|
```
|
|
158
160
|
|
|
161
|
+
## Configuration
|
|
162
|
+
|
|
163
|
+
Runtime settings persist across restarts in `~/.asher-cli/config.json`, so you don't have to re-apply `/refresh 60`, `/cat colour #ff79c6`, or `/pet 1` every launch. The file is auto-created on first change and holds six non-secret UI preferences:
|
|
164
|
+
|
|
165
|
+
| Setting | Slash command | Default |
|
|
166
|
+
|---|---|---|
|
|
167
|
+
| `poll_interval_seconds` | `/refresh <seconds\|off>` | `300` |
|
|
168
|
+
| `cat_panel_visible` | `/cat on\|off` | `true` |
|
|
169
|
+
| `cat_panel_color` | `/cat colour <hex>\|reset` | `null` (default palette) |
|
|
170
|
+
| `active_pet_index` | `/pet <index\|name>` | `0` |
|
|
171
|
+
| `notifications` | `/notify on\|off` | `true` |
|
|
172
|
+
| `notification_sound` | `/notify sound on\|off` | `false` |
|
|
173
|
+
|
|
174
|
+
Credentials and the preferred-robot serial stay in the OS keyring; `.env` vars stay as env vars. You generally don't need to edit the file by hand — just use the slash commands — but it's plain JSON and safe to inspect or delete (deleting it restores defaults).
|
|
175
|
+
|
|
159
176
|
## Releasing
|
|
160
177
|
|
|
161
178
|
```bash
|
|
162
|
-
#
|
|
163
|
-
uv run
|
|
164
|
-
|
|
165
|
-
|
|
179
|
+
# 1. regenerate CHANGELOG.md from conventional commits (idempotent), then commit it
|
|
180
|
+
uv run poe changelog
|
|
181
|
+
git add CHANGELOG.md
|
|
182
|
+
git commit -m "docs(changelog): update for next release"
|
|
183
|
+
|
|
184
|
+
# 2. bump version, commit, and tag in one step, then push with tags
|
|
185
|
+
uv run bump-my-version bump patch # 0.2.0 → 0.2.1
|
|
186
|
+
uv run bump-my-version bump minor # 0.2.0 → 0.3.0
|
|
187
|
+
uv run bump-my-version bump major # 0.2.0 → 1.0.0
|
|
166
188
|
|
|
167
189
|
git push && git push --tags
|
|
168
190
|
|
|
169
|
-
#
|
|
170
|
-
|
|
171
|
-
git
|
|
191
|
+
# 3. push the release branch to trigger PyPI publish (OIDC) + GitHub Release
|
|
192
|
+
# (release notes auto-generated by git-cliff from the same cliff.toml)
|
|
193
|
+
git checkout -b release/X.Y.Z
|
|
194
|
+
git push origin release/X.Y.Z
|
|
172
195
|
```
|
|
173
196
|
|
|
197
|
+
`CHANGELOG.md` is generated by [git-cliff](https://git-cliff.org) from
|
|
198
|
+
conventional commits — see [`cliff.toml`](cliff.toml). Commit messages must use
|
|
199
|
+
`feat:`/`fix:`/`docs:`/etc. prefixes (optionally scoped, e.g. `feat(robot):`)
|
|
200
|
+
to appear in the changelog.
|
|
201
|
+
|
|
174
202
|
## Troubleshooting
|
|
175
203
|
|
|
176
204
|
**`asher` not found after `pip install asher-cli`**
|
|
@@ -264,30 +292,8 @@ CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every
|
|
|
264
292
|
|
|
265
293
|
## Changelog
|
|
266
294
|
|
|
267
|
-
|
|
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).
|
|
295
|
+
The full, maintained release history lives in [CHANGELOG.md](CHANGELOG.md),
|
|
296
|
+
auto-generated from conventional commits by [git-cliff](https://git-cliff.org).
|
|
291
297
|
|
|
292
298
|
## Notes
|
|
293
299
|
|
|
@@ -47,11 +47,16 @@ class AsherApp(UIMixin, ConnectionMixin, MonitoringMixin, CommandsMixin, App):
|
|
|
47
47
|
self._last_cat_seen: Any = None
|
|
48
48
|
self._is_loading: bool = True
|
|
49
49
|
self._spinner_idx: int = 0
|
|
50
|
-
|
|
50
|
+
from .config import load as _load_config # noqa: PLC0415
|
|
51
|
+
|
|
52
|
+
_cfg = _load_config()
|
|
53
|
+
self._poll_interval: int = _cfg["poll_interval_seconds"]
|
|
51
54
|
self._poll_timer: Timer | None = None
|
|
52
|
-
self._cat_panel_visible: bool =
|
|
53
|
-
self._cat_color: str | None =
|
|
54
|
-
self._active_pet_idx: int =
|
|
55
|
+
self._cat_panel_visible: bool = _cfg["cat_panel_visible"]
|
|
56
|
+
self._cat_color: str | None = _cfg["cat_panel_color"]
|
|
57
|
+
self._active_pet_idx: int = _cfg["active_pet_index"]
|
|
58
|
+
self._notifications_enabled: bool = _cfg["notifications"]
|
|
59
|
+
self._notification_sound: bool = _cfg["notification_sound"]
|
|
55
60
|
self._prev_faults: set[str] = set()
|
|
56
61
|
self._fault_dismissed: set[str] = set()
|
|
57
62
|
self._cycle_start: Any = None
|
|
@@ -63,8 +68,12 @@ class AsherApp(UIMixin, ConnectionMixin, MonitoringMixin, CommandsMixin, App):
|
|
|
63
68
|
self._refresh_title()
|
|
64
69
|
self._show_welcome()
|
|
65
70
|
self._show_loading_state()
|
|
71
|
+
self.query_one("#cat-panel").display = self._cat_panel_visible
|
|
66
72
|
self._connect_worker()
|
|
67
|
-
self.
|
|
73
|
+
if self._poll_interval > 0:
|
|
74
|
+
self._poll_timer = self.set_interval(self._poll_interval, self._poll_status_interval)
|
|
75
|
+
else:
|
|
76
|
+
self._poll_timer = None
|
|
68
77
|
self.set_interval(0.4, self._tick_cat)
|
|
69
78
|
self.query_one("#cmd-input", Input).focus()
|
|
70
79
|
|