asher-cli 0.1.0__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.
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.claude/settings.json +6 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/workflows/ci.yml +4 -4
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/workflows/claude-code-review.yml +2 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/workflows/claude.yml +2 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/workflows/coverage.yml +2 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/workflows/release.yml +3 -3
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.gitignore +3 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/CLAUDE.md +26 -5
- {asher_cli-0.1.0 → asher_cli-0.2.0}/PKG-INFO +82 -6
- {asher_cli-0.1.0 → asher_cli-0.2.0}/README.md +81 -5
- {asher_cli-0.1.0 → asher_cli-0.2.0}/ROADMAP.md +262 -121
- asher_cli-0.2.0/asher/__main__.py +58 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/app.py +7 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/commands/__init__.py +262 -99
- asher_cli-0.2.0/asher/completion.py +113 -0
- asher_cli-0.2.0/asher/connection/__init__.py +322 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/constants.py +3 -0
- asher_cli-0.2.0/asher/export.py +236 -0
- asher_cli-0.2.0/asher/faults.py +146 -0
- asher_cli-0.2.0/asher/history_view.py +228 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/monitoring/__init__.py +135 -3
- asher_cli-0.2.0/asher/slash-commands/__init__.py +43 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/ui/__init__.py +52 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/ui/style.tcss +40 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/pyproject.toml +2 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/conftest.py +15 -2
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_app_pilot.py +3 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_commands_pilot.py +2 -2
- asher_cli-0.2.0/tests/test_completion.py +571 -0
- asher_cli-0.2.0/tests/test_connection.py +194 -0
- asher_cli-0.2.0/tests/test_export.py +416 -0
- asher_cli-0.2.0/tests/test_faults.py +186 -0
- asher_cli-0.2.0/tests/test_history_view.py +276 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_missing_robot_commands.py +130 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_monitoring.py +120 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_ui.py +12 -0
- asher_cli-0.2.0/tests/test_version_command.py +87 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/uv.lock +5 -5
- asher_cli-0.1.0/asher/__main__.py +0 -11
- asher_cli-0.1.0/asher/connection/__init__.py +0 -180
- asher_cli-0.1.0/asher/slash-commands/__init__.py +0 -19
- asher_cli-0.1.0/tests/test_connection.py +0 -96
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.claude/hooks/block-env.ps1 +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.claude/skills/pylitterbot-ref/SKILL.md +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.claude/skills/release/SKILL.md +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.claude/skills/textual/SKILL.md +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.env.example +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.githooks/pre-push +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.github/pull_request_template.md +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.vscode/launch.json +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.vscode/settings.json +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/.vscode/tasks.json +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/CODEOWNERS +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/LICENSE +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/app.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/__init__.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/activity_labels.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/auth.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/cats.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/commands/base.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/helpers.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/login_flow.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/mcp_bridge.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/mcp_config.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/robot_adapters.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/asher/robot_protocol.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/renovate.json +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/requirements.txt +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/test.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/__init__.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_activity_labels.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_auth.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_auth_pilot.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_cats.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_connection_mixin.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_lr5_commands.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_mcp_bridge.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_mcp_command.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_mcp_config.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_new_commands_pilot.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/test_robot_adapters.py +0 -0
- {asher_cli-0.1.0 → asher_cli-0.2.0}/tests/testhelpers.py +0 -0
- {asher_cli-0.1.0 → 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@
|
|
16
|
-
- uses: astral-sh/setup-uv@
|
|
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@
|
|
32
|
-
- uses: astral-sh/setup-uv@
|
|
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@
|
|
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@
|
|
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@
|
|
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@
|
|
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@
|
|
16
|
-
- uses: astral-sh/setup-uv@
|
|
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@
|
|
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@
|
|
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@
|
|
47
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
48
48
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
49
49
|
with:
|
|
50
50
|
name: dist
|
|
@@ -43,11 +43,15 @@ asher/
|
|
|
43
43
|
robot_adapters.py RobotAdapter ABC + LR3/LR4/LR5 subclasses + make_adapter() factory
|
|
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
|
+
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
|
|
46
50
|
__main__.py main() entry point
|
|
47
51
|
commands/
|
|
48
52
|
base.py Command ABC, SlashCommand, CommandRegistry
|
|
49
53
|
__init__.py CommandsMixin — all command classes + registry + dispatch
|
|
50
|
-
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`)
|
|
51
55
|
monitoring/ MonitoringMixin — _poll_status_interval, _refresh_status
|
|
52
56
|
ui/ UIMixin — CSS, compose(), log helpers, cat helpers
|
|
53
57
|
slash-commands/ Convention doc
|
|
@@ -66,6 +70,10 @@ tests/
|
|
|
66
70
|
test_mcp_config.py Claude Desktop config read/write
|
|
67
71
|
test_mcp_bridge.py mcp_bridge launcher credential/subprocess handling
|
|
68
72
|
test_mcp_command.py /mcp slash command dispatch
|
|
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
|
|
69
77
|
|
|
70
78
|
.github/workflows/
|
|
71
79
|
ci.yml ruff + mypy + pytest on every push/PR
|
|
@@ -101,10 +109,12 @@ pylitterbot ships an optional MCP server (`pip install pylitterbot[mcp]`, run vi
|
|
|
101
109
|
## Command convention
|
|
102
110
|
|
|
103
111
|
**Normal commands** (no prefix) — robot actions only:
|
|
104
|
-
`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`
|
|
105
113
|
|
|
106
114
|
**Slash commands** (`/` prefix) — app management only:
|
|
107
|
-
`/login`, `/logout`, `/
|
|
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`.
|
|
108
118
|
|
|
109
119
|
**Special cases** (accepted both with and without `/`):
|
|
110
120
|
`exit`, `quit`, `q` — exit the app
|
|
@@ -122,7 +132,13 @@ AsherApp (textual.App)
|
|
|
122
132
|
├── #status-bar top dock — two rows (top: name/online/night-light/lock; bottom: drawer/litter/weight/visit)
|
|
123
133
|
├── #main-area
|
|
124
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
|
|
125
136
|
│ └── #cat-panel animated ASCII cat sidebar
|
|
137
|
+
│ ├── #cat-fx animated FX strip
|
|
138
|
+
│ ├── #cat-art the ASCII cat
|
|
139
|
+
│ ├── #cat-label mode label (connected / cycling… / fault!)
|
|
140
|
+
│ ├── #cat-status complementary badges (status, power, cycles, wait time) — no lock/night-light (those are top-row only)
|
|
141
|
+
│ └── #fault-banner hidden unless check_faults() returns active faults; `d` dismisses
|
|
126
142
|
└── #bottom-dock bottom dock
|
|
127
143
|
├── #input-bar / #input-row command prompt ("> " label + CmdInput)
|
|
128
144
|
└── #hint-bar shortcut hints / login flow prompts
|
|
@@ -135,11 +151,16 @@ LoginScreen (ModalScreen) — available in auth.py but not the primary auth path
|
|
|
135
151
|
| Method | Purpose |
|
|
136
152
|
|---|---|
|
|
137
153
|
| `_connect_worker()` | `@work` — resolve credentials (keyring → .env → inline login), authenticate |
|
|
138
|
-
| `_refresh_status()` | update all header widgets from robot state |
|
|
154
|
+
| `_refresh_status()` | update all header widgets + cat panel + fault banner from robot state |
|
|
155
|
+
| `_update_cat_panel(robot)` | render `#cat-label` + `#cat-status` (complementary: status, power, cycles, wait); called from `_refresh_status` |
|
|
156
|
+
| `_refresh_faults(robot)` | run `check_faults()`, render `#fault-banner`, log transitions; sets cat mode to `error` while faults active |
|
|
157
|
+
| `_cycling_chip()` / `_start_cycle_timer()` / `_stop_cycle_timer()` / `_tick_cycle()` | `⟳ Cycling M:SS` chip + lazy 1s elapsed timer |
|
|
139
158
|
| `_poll_status_interval()` | `@work` — poll fallback every 300s (5 min); WebSocket is primary |
|
|
140
159
|
| `_tick_cat()` | advances multi-frame cat animation every 0.4s |
|
|
141
160
|
| `_dispatch_command(command, args)` | `@work` — calls `command.run(app, args)` from the registry |
|
|
142
|
-
| `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 |
|
|
143
164
|
| `_start_login_flow()` | begin inline email/password prompt in command bar |
|
|
144
165
|
| `_cmd_logout()` | delete creds from keyring, disconnect |
|
|
145
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.
|
|
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
|
|
|
@@ -62,9 +62,15 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
|
|
|
62
62
|
|
|
63
63
|
- Live status bar — unit name, online/offline, drawer fill level, last activity, cat weight
|
|
64
64
|
- Human-readable robot status — translates raw API states into plain English (`Ready`, `Cleaning`, `Cat Detected`, `Drawer Full`, etc.)
|
|
65
|
-
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
65
|
+
- Real-time cycling indicator with elapsed time (`⟳ Cycling M:SS`)
|
|
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
|
+
- Cat panel with mode label + status badges (status chip, lock, night light, sleep, wait time) under the art
|
|
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
|
|
68
74
|
- Cat animation panel that reacts to robot state
|
|
69
75
|
- Command history (↑/↓ arrows)
|
|
70
76
|
- Real-time updates via WebSocket; 5-minute poll fallback
|
|
@@ -129,7 +135,16 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
129
135
|
| `sleep` / `wake` | Toggle sleep mode |
|
|
130
136
|
| `night-light on\|off\|auto` | Set night light mode |
|
|
131
137
|
| `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
|
|
132
|
-
| `
|
|
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) |
|
|
133
148
|
| `export [days\|month]` | Export activity history to CSV in `~/Downloads` (default: 30 days) |
|
|
134
149
|
| `clear` | Clear the log |
|
|
135
150
|
| `help` | Show command list |
|
|
@@ -149,9 +164,43 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
149
164
|
| `/cat color <hex>` | Change the cat art colour (e.g. `/cat color #ff79c6`); `/cat reset` to revert |
|
|
150
165
|
| `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
|
|
151
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 |
|
|
152
169
|
| `/exit` | Exit Asher CLI |
|
|
153
170
|
|
|
154
|
-
**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
|
+
```
|
|
155
204
|
|
|
156
205
|
## Releasing
|
|
157
206
|
|
|
@@ -259,6 +308,33 @@ uv run poe check # run all of the above + tests (same as CI)
|
|
|
259
308
|
|
|
260
309
|
CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every push.
|
|
261
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
|
+
|
|
262
338
|
## Notes
|
|
263
339
|
|
|
264
340
|
- Uses the unofficial [pylitterbot](https://github.com/natekspencer/pylitterbot) library — supports LR3, LR4, LR5, and other Whisker robots
|
|
@@ -16,9 +16,15 @@ A Claude Code-style terminal dashboard for monitoring and controlling Litter Rob
|
|
|
16
16
|
|
|
17
17
|
- Live status bar — unit name, online/offline, drawer fill level, last activity, cat weight
|
|
18
18
|
- Human-readable robot status — translates raw API states into plain English (`Ready`, `Cleaning`, `Cat Detected`, `Drawer Full`, etc.)
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
19
|
+
- Real-time cycling indicator with elapsed time (`⟳ Cycling M:SS`)
|
|
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
|
+
- Cat panel with mode label + status badges (status chip, lock, night light, sleep, wait time) under the art
|
|
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
|
|
22
28
|
- Cat animation panel that reacts to robot state
|
|
23
29
|
- Command history (↑/↓ arrows)
|
|
24
30
|
- Real-time updates via WebSocket; 5-minute poll fallback
|
|
@@ -83,7 +89,16 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
83
89
|
| `sleep` / `wake` | Toggle sleep mode |
|
|
84
90
|
| `night-light on\|off\|auto` | Set night light mode |
|
|
85
91
|
| `night-light-brightness <level>` | Set brightness (LR5: 0-100; LR4: 25/50/100) |
|
|
86
|
-
| `
|
|
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) |
|
|
87
102
|
| `export [days\|month]` | Export activity history to CSV in `~/Downloads` (default: 30 days) |
|
|
88
103
|
| `clear` | Clear the log |
|
|
89
104
|
| `help` | Show command list |
|
|
@@ -103,9 +118,43 @@ LITTER_ROBOT_PASSWORD=yourpassword
|
|
|
103
118
|
| `/cat color <hex>` | Change the cat art colour (e.g. `/cat color #ff79c6`); `/cat reset` to revert |
|
|
104
119
|
| `/refresh [seconds\|off]` | Change the auto-poll interval or disable it (`/refresh 60`, `/refresh off`) |
|
|
105
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 |
|
|
106
123
|
| `/exit` | Exit Asher CLI |
|
|
107
124
|
|
|
108
|
-
**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
|
+
```
|
|
109
158
|
|
|
110
159
|
## Releasing
|
|
111
160
|
|
|
@@ -213,6 +262,33 @@ uv run poe check # run all of the above + tests (same as CI)
|
|
|
213
262
|
|
|
214
263
|
CI runs on Python 3.10 / 3.11 / 3.12 across Ubuntu, Windows, and macOS on every push.
|
|
215
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
|
+
|
|
216
292
|
## Notes
|
|
217
293
|
|
|
218
294
|
- Uses the unofficial [pylitterbot](https://github.com/natekspencer/pylitterbot) library — supports LR3, LR4, LR5, and other Whisker robots
|