Update claude-companion to v1.3.0 (what its got: a lot) (#167)
* claude-companion: v1.3.0 — headless aggregator, user settings, sessions panel Catalog-side update for lowcache/claude-companion, from 1.0.1 to 1.3.0. Architecture: the pulse aggregator moved out of the bar widget into a headless [[service]] (pulse-svc.luau). Capture no longer depends on the bar dot being placed — the service starts with the shell and listens regardless of surfaces, retiring the plugin's old "pulse must sit on a bar" deployment invariant. The bar widget and desktop orb are now independent subscribers of the claude.pulse rollup, rendering only. Noctalia 5 beta also fixed the older limitation where bar widgets did not receive state.watch callbacks, so the bar dot is event-driven like the orb; both docs are updated accordingly. New: a `sessions` panel on right-click of the pulse (left-click still opens the answer panel) — one row per live session with state, model and token burn, plus a Retire control for a session whose SessionEnd hook never fired and which would otherwise sit at idle indefinitely. It introduces no new IPC verb: only the trailing `session` payload field is read for routing, so `session_end` with `,,,,,<sid>` is already a well-formed single-session retire. PROTOCOL.md now documents that property so any adapter can use it. Session ids are allowlisted before reaching a shell command. New: three animation settings (breath_speed, pulse_glow_floor, orb_swell), each declaring an explicit `step` — an omitted step defaults to 1.0 in the manifest parser, which collapses a fractional range to a couple of preset stops instead of a slider. plugin_api stays at 3. Everything used here is ungated at that level, and the contributing guidance is to raise it only when adopting a capability from a newer level. Verified against the installed build rather than assumed. Also ships tests/manifest_spec.py, which pins the settings contract: every numeric setting must declare an explicit step finer than its range, defaults must land on a step boundary, label/description must use the *_key form, and every key must resolve in translations/en.json. Neither the linter nor a widget spec can catch a bad step, which is how the slider bug shipped in the first place. Validated: catalog validator 54/54 exit 0, its own 54 self-tests pass, and the plugin's suite (5 luau + shim + manifest) is green. Live-tested on niri against Noctalia 5 beta; the compositor shim is unchanged in this update. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * claude-companion: tint the sessions retire control, fix singular header Follow-up on the v1.3.0 submission from live review: the retire button carried no variant and rendered at the background colour; a single session read "1 sessions". The panel root stays unfilled by design — noctalia panels are translucent under the glass style, so the backdrop is the shell's, not the plugin's. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: lowcache <drawpdeadredd@gmail.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
lowcache
Claude Opus 5
parent
d113b03439
commit
d2aa9b9751
@@ -12,13 +12,13 @@
|
||||
# Without one it sends a bare event, which lands in the widget's shared
|
||||
# "default" test slot — fine for a poke, wrong for a real integration.
|
||||
#
|
||||
# Env: PULSE_TARGET plugin dispatch id (default lowcache/claude-companion:pulse)
|
||||
# Env: PULSE_TARGET plugin dispatch id (default lowcache/claude-companion:pulse-svc)
|
||||
# PULSE_DRYRUN non-empty -> print the command instead of dispatching
|
||||
#
|
||||
# Fail-open by contract: exits 0 no matter what, output swallowed, dispatch
|
||||
# capped at 3 s. A hook must never block or error the agent driving it.
|
||||
|
||||
TARGET="${PULSE_TARGET:-lowcache/claude-companion:pulse}"
|
||||
TARGET="${PULSE_TARGET:-lowcache/claude-companion:pulse-svc}"
|
||||
event="${1:-idle}"
|
||||
session="$2"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Pulse hook dispatcher (lowcache/claude-companion plugin).
|
||||
|
||||
Bridges a Claude Code lifecycle hook to the pulse bar widget, enriching the
|
||||
Bridges a Claude Code lifecycle hook to the pulse aggregator service, enriching the
|
||||
event with live model + token-burn telemetry parsed from the session transcript.
|
||||
Invoked by the hooks in settings.snippet.json as:
|
||||
|
||||
@@ -10,16 +10,16 @@ Invoked by the hooks in settings.snippet.json as:
|
||||
Hook JSON arrives on stdin (transcript_path, session_id). The widget is driven via
|
||||
noctalia's documented plugin IPC (`noctalia msg --help`):
|
||||
|
||||
noctalia msg plugin lowcache/claude-companion:pulse all <event> [payload]
|
||||
noctalia msg plugin lowcache/claude-companion:pulse-svc all <event> [payload]
|
||||
|
||||
`[payload]` is a single positional token, so the payload is a SPACE-FREE CSV the
|
||||
widget (pulse.luau) parses:
|
||||
aggregator service (pulse-svc.luau) parses:
|
||||
|
||||
model,in,out,cacheCreate,cacheRead,session
|
||||
|
||||
The `session` (short id) tags EVERY event, so the widget can track each concurrent
|
||||
The `session` (short id) tags EVERY event, so the service can track each concurrent
|
||||
session separately. The matching SessionEnd hook fires `session_end`, which retires
|
||||
the session in the widget and drops its token cache here.
|
||||
the session in the service and drops its token cache here.
|
||||
|
||||
Token accounting is incremental: a per-session cache in $XDG_RUNTIME_DIR stores the
|
||||
last byte offset + running sums, so each hook reads only newly-appended transcript
|
||||
@@ -36,7 +36,7 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
PLUGIN = "lowcache/claude-companion:pulse"
|
||||
PLUGIN = "lowcache/claude-companion:pulse-svc"
|
||||
TARGET = "all"
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"_comment": "Merge into ~/.claude/settings.json. The attention reflex: Claude Code lifecycle hooks invoke hooks/pulse.py <event>, which reads the hook JSON on stdin, computes live model + token-burn telemetry from the session transcript, and dispatches into the pulse bar widget via `noctalia msg plugin lowcache/claude-companion:pulse all <event> [payload]` (target `all` = every monitor's instance; `focused`/bare connector error when the widget is on multiple bars). payload is a space-free CSV `model,in,out,cacheCreate,cacheRead,session` whose trailing `session` (short id) tags every event, so the widget tracks each concurrent session separately and renders the most urgent state + a per-session token-burn tooltip. SessionEnd fires `session_end`, retiring that session in the widget and dropping its token cache. The dispatcher is fail-open: if noctalia is offline or the transcript is unreadable it fires the bare event (or nothing) and never errors. Path assumes the plugin is installed/symlinked at ~/.local/share/noctalia/plugins/claude-companion. Verified against noctalia 5.0.0 (`noctalia msg --help`). SessionStart registers the session at idle; the lifecycle drives turn_start -> tool_start -> turn_end; SessionEnd removes it. For the MCP shim (senses/hands), wire it separately via mcpServers/--mcp-config once shim/noctalia-mcp.py is in use.",
|
||||
"_comment": "Merge into ~/.claude/settings.json. The attention reflex: Claude Code lifecycle hooks invoke hooks/pulse.py <event>, which reads the hook JSON on stdin, computes live model + token-burn telemetry from the session transcript, and dispatches into the headless aggregator service via `noctalia msg plugin lowcache/claude-companion:pulse-svc all <event> [payload]` (target `all` = every monitor's instance; `focused`/bare connector error when the widget is on multiple bars). payload is a space-free CSV `model,in,out,cacheCreate,cacheRead,session` whose trailing `session` (short id) tags every event, so the service tracks each concurrent session separately and publishes the most urgent state + token-burn telemetry for the widget to render as a tooltip. SessionEnd fires `session_end`, retiring that session in the service and dropping its token cache. The dispatcher is fail-open: if noctalia is offline or the transcript is unreadable it fires the bare event (or nothing) and never errors. Path assumes the plugin is installed/symlinked at ~/.local/share/noctalia/plugins/claude-companion. Verified against noctalia 5.0.0 (`noctalia msg --help`). SessionStart registers the session at idle; the lifecycle drives turn_start -> tool_start -> turn_end; SessionEnd removes it. For the MCP shim (senses/hands), wire it separately via mcpServers/--mcp-config once shim/noctalia-mcp.py is in use.",
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{ "matcher": "*", "hooks": [ { "type": "command", "command": "python3 $HOME/.local/share/noctalia/plugins/claude-companion/hooks/pulse.py idle" } ] }
|
||||
|
||||
Reference in New Issue
Block a user