aboutsummaryrefslogtreecommitdiffstats
AgeCommit message (Collapse)AuthorFilesLines
4 hourshosts: group cards by node, devices and remote, with a reachability dotHEADmasterDanilo M.3-24/+198
The flat grid mixed Proxmox services with the phone, printers and IoT. hosts.py now gives every entry a group: the node named in its note's `node`, its own name when other notes name it as their node (so the node card heads its section), "Devices" for anything else on a private address, "Remote" for the rest. The list is sorted node by node, node card first, and the grid starts a titled section at each group change. Up/Down move by visual row and keep the column, since rows are no longer a fixed five. `hosts.py --probe` checks every host at once, about a second for the whole list, and runs beside the list rather than ahead of it. A host with a port or url is up only when that port accepts a TCP connect, so a service whose CT is up and whose daemon is down reads red; anything else gets one ping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 hoursperf: hold the process list at five rowsDanilo M.1-29/+41
The list fills about 2s after the page opens and can show fewer than five rows, which resized the CPU card and shifted every card below it. A FontMetrics-sized Column keeps the height fixed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 hoursnetwork: traffic, its busiest processes and the IPs on the pageDanilo M.6-82/+291
The rx/tx graph, the LAN address and the public IP with its pin move from the perf page's NET card to the network page, where they belong; the NET card is gone. Perf still samples and owns all of them: the graph opens on the last minute of history, and a public IP that differs from the pin still lights the perf tile's dot. Below the graph, the five busiest processes. nethogs is installed but cannot open any interface unprivileged, so the rates come from `ss -tinpH`: per-socket byte counters diffed every 2s while the page is open, summed by process name. That counts TCP only, and only the user's own processes, so QUIC and system services are missing. The list is held at five rows tall so the IP lines under it never move. Perf.js gains sockets() and netProcs(), with tests in test_perf.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 hoursgames: search the Steam store from the launcherDanilo M.2-6/+92
Down switches the strip and preview from the library to store results, searched as you type with a 350ms debounce through the store's keyless api/storesearch endpoint, using QML's own XMLHttpRequest rather than a process. Results already in the library read Owned or Installed in green, the rest their price; Enter opens steam://store/<appid> in the client, Up or Escape returns to the library with the query kept, so a name that matches nothing locally is one keypress from the store. The endpoint answers {"total":0} for every term when no cc is given, despite looking like it geolocates, and the locale here is en_US, so the country is fixed to Italy. Store art comes from Steam's CDN; newer apps keep theirs under hashed paths that 404, so the preview layers the search's capsule under the hero and the tile shows the initial until its cover is actually ready. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9 hoursgames: route every Steam-launched window to workspace 8Danilo M.2-0/+25
Hyprland's class rules only catch Proton games (steam_app_N) and whatever else is listed by name, so a non-Steam shortcut, here a GOG Ren'Py build with its own class, opened on the current workspace. Steam sets SteamGameId in the environment of everything it launches, native, Proton and shortcuts alike, so on openwindow the shell looks up the window's pid and moves it when /proc/<pid>/environ carries that variable. Checked with the shortcut that motivated it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9 hoursgames: the Steam library as an endless strip with a large previewDanilo M.7-0/+532
An overlay on DP-1: a looping PathView of slanted tiles along the bottom, the centred one shown large above it in Steam's hero art with its title. Installed games and non-Steam shortcuts come first, by last played; owned games that are not installed follow, framed in peach, and Enter installs them. Launches go through steam -silent so the Steam window stays down. games.py reads appmanifests, the binary shortcuts.vdf and Steam's library cache on every opening; owned games come from the Web API through a cache refreshed in the background. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
33 hoursbookmarks: Firefox bookmarks as a full-width overlayDanilo M.8-0/+992
A new standalone shell, shaped like hosts, on SUPER+b. bookmarks.py reads the bookmark tree and favicons of the profile a running Firefox holds (found through the pid in its lock symlink; the last-modified places.sqlite was tried first and picked the guest profile after a stray launch touched it). Firefox keeps both databases in exclusive lock mode, so they are copied with their -wal and the copy is read: an immutable=1 open of the original skipped the log and kept showing bookmarks deleted minutes before. The grid spans DP-1, a ListView of card rows so only visible rows exist, grouped by folder with each folder's own bookmarks before its subfolders. Six icon buttons (Ctrl+S cycles) sort by folder, newest, title, site, most visited or link state. The wheel scrolls three rows a notch through a MouseArea, since Flickable's own step crawled; only the selected card carries a Glow, through a Loader. Favicons are extracted by content hash; a page without one takes any icon Firefox holds for its host, which found 52 more of 504. bookmarks.py --links (Ctrl+R) checks every http(s) bookmark, HEAD then GET, 32 at a time, in about 22s, and caches the result. Dead means 404/410, an NXDOMAIN or a refused connection; 403, 429, timeouts, TLS and resolver failures are only "unsure", because a 32-thread burst produced EAI_AGAIN that a serial retry resolved. Bookmarks open with xdg-open: a plain `firefox <url>` does not reach an instance started with -P and opened the default profile beside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 hourshosts: the vault's LAN map as a searchable overlayDanilo M.8-0/+596
A new standalone shell, shaped like keybinds, that replaces the rofi SSH menu (blackpearl-sshmenu.sh) on ALT+SHIFT+Return. hosts.py reads the frontmatter of every host note in the vault's Local Network/services folder and the plain lines of ~/.ssh/config, and joins each alias to the note whose ip or hostname is its HostName (or whose short hostname is the alias). Aliases that match no note get cards of their own, so everything the rofi menu listed is still reachable. It runs on every opening, so a vault edit shows next time with no cache to go stale. Each card shows ip:port, hostname, the Proxmox node and CT id, and only the actions its data allows: ssh per alias (a kitty tab, via ssh-tab, lifted from the rofi script), open for a url, copy for the address. Enter runs the first. The cards are laid out in rows of five inside a Flickable rather than a GridView, because a GridView gives every cell one height: a fixed height tall enough for the most aliased host left every other card half empty, and a short one clipped its chips. Each row now takes its busiest card's height. The grid keeps a 24px margin inside its clip, without which the first row's glow was cut off at the top. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 dayscompanion: the seeds kept for the last seated framesDanilo M.1-0/+4
Seed 42 drew a third hand, the new one plus both still on the bench, on every dress frame among sit-think, sit-listen and sit-wave, and on leotard/sit-think. The comments name the seeds that replaced it so a remake does not have to find them again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 dayscompanion: seated recipes that move her, and no ledgeDanilo M.1-11/+21
Naming a ledge in SIT drew a grey bar across the whole image, so SIT now names nothing under her. Its "keep her sitting pose exactly" also froze her arms, so the posed seated frames do without it: sit-point came out as the plain sit with a smirk, and at seed 42 kept her old hand on her hip too (seed 7 kept). dress/sit-read is hand made, a masked inpaint recorded in the art's recipe.txt, since no edit would bend her forward, and leotard/sit-read names the lowered gaze that ${LEOTARD} turned to the viewer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 dayscompanion: fade the new frame in over the old one, dj loop fasterDanilo M.2-5/+12
Both images faded at once, so mid-swap each sat near half opacity and she blinked see-through on every turn of the dj loop. The incoming frame now fades in on top while the outgoing one stays opaque under it. With the blink gone the loop could run faster: 300 ms a frame, from 450. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 daysdocs: the companion's seat on the assistant cardDanilo M.2-9/+18
Records that Hyprland's typing binds fire under the canvas's exclusive keyboard, which is why the canvas reports no typing of its own, and that the seat fixes her right edge rather than her centre. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 dayscompanion: the seated frames' recipesDanilo M.1-0/+19
Edited from base-sitting, the original sitting rest pose dress/base came from, so the legs already dangle and klein only changes the arms and expression. The leotard set follows its dress frames as before. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
3 dayscompanion: no move while a hop is in flightDanilo M.1-1/+3
hopping counts as away, so a goal change during the exit (the chat card closing mid-drop) moved the window before the drop had played. settled already takes the latest goal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 dayscompanion: sit on the assistant's chat cardDanilo M.1-13/+37
While the canvas shows its tall card she hops onto its top edge, through the monitor hop: the exit plays, the window's margins move, the entrance plays. The tall card's top is fixed, so nothing follows a moving edge. Seated she ignores focus changes and balloons, and shows Mood.seatFrame of whatever she would show standing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
3 daysassistant: drop Card.panel, its only reader was the old tallDanilo M.1-1/+0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 daysassistant: the canvas owns tall and the card's topDanilo M.2-2/+8
The companion needs both to sit on the chat card, and should not reach into the card for them. Card.tall now reads the canvas's, so there is one definition of when the card is tall. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
3 dayscompanion: seatFrame, the sitting version of a frameDanilo M.2-1/+23
Pure, so the seat's frame choice is tested with the rest of Mood rather than by eye. Frames without a sitting version fall to the plain sit: a standing frame on the card's edge would float above it. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
3 daysdocs: companion seat, implementation planDanilo M.1-0/+383
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3 daysdocs: companion seat on the assistant's tall card, designDanilo M.1-0/+101
She sits on the chat card's top edge rather than standing on the bar or the file card, because standing frames face the viewer and reading the text below her feet would need art of its own. The tall card's top is fixed, so the seat is a margin change made through the monitor hop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysperf: the five heaviest processes in the CPU card, by CPU or RAMDanilo M.5-1/+142
A table under RAM lists the top five processes with their CPU and resident memory, sorted by either through a toggle in the card. The toggle re-sorts the frame already held and is not saved. The rows come from one `top -b -d2` that runs only while the page is open and dies with it, checked with pgrep. ps was not used: its %CPU is a lifetime average. top's first frame is the same lifetime figure, so it is skipped. top marks no frame end but writes each frame in one burst, so a frame is published once its output has been quiet for 150ms, and rows appear about 2s after opening, not 4s as when waiting for the next header. SplitParser delivered every header after the first as "\ntop - ...", so the header match is a regex that allows leading whitespace; AGENTS.md records it. The parser is Perf.js procs(), covered in test_perf.js. Columns are right-aligned at fixed widths with tabular figures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysdocs: rewrap the tray menu notesDanilo M.1-3/+3
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysisland: release the tray-menu hold when the menu closesDanilo M.4-11/+30
A tray menu un-hovers the pills, so the island holds itself shown while one is open. display() reports no close, so the hold ended only when the pointer came back to the island. Quitting an app from its menu left the pointer on the vanished menu, below the pills, and the island stayed open until the next hover. Menus now open through a QsMenuAnchor. Its closed signal fires on any dismissal, an entry picked, Escape or a click elsewhere, and clears the hold and restarts the hide timer. Checked by eye: menu placement unchanged, Quit and a dismissal both retract the island, hovering back keeps it shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayswindow-switcher: Del closes the selected windowDanilo M.2-1/+4
The keyboard could pick a window but only the mouse could close one, on the hovered card's x. Del closes the selection and, like the x, leaves the overlay open for the next close; the card goes when Hyprland reports the window gone, and the next arrow press picks the top-left card again. The README also still named the IPC show(), renamed open() in c889501. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysipc: show() is open(), the CLI could never reach itDanilo M.4-3/+8
qs ipc has a show subcommand, and its parser takes the word wherever it appears: `qs -p <dir> ipc call companion show` printed the target list and exited 0 instead of calling the function. The companion, window switcher and keybind reminder each had a show() no command line could call. The binds use toggle and are unaffected. open() matches the drawer's own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: stay out of view when the shell starts with her hiddenDanilo M.1-0/+7
A shell started with Prefs.companion false created the Figure with out already true. A starting value fires no onOutChanged, so the drop never ran and she was drawn in place. Hidden, her 200 ms clock does not tick, so every timed step froze: an empty desktop left her on the watch frame of the wallpaper blush, and a balloon left her on shoved, never mad. Toggling her on made the bug look fixed until the next restart. The body is now invisible while out and not animating, and the first entrance after such a start begins from below like any other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: headbang-down that bows her head, and its leotardDanilo M.1-2/+3
The stronger down prompt tucks her head with the hair hanging over her face, which reads as the downbeat; the up frame keeps the earlier prompt, since spelling out the horns still drew a peace sign. ${LEOTARD} insists her eyes show, which parted the hair even with an override appended, so the leotard line only swaps the skirt, as leotard/sing does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: groove prompts that klein followsDanilo M.1-4/+4
Whistle had the same censor-bar blindfold as dj and takes the same fix. headbang-down edited from headbang-up came out nearly identical, so both are made from base with opposite poses. klein will not draw an invisible guitar, so the air guitar is a neon blue electric. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: dj without the blindfold, behind a closed boothDanilo M.1-2/+2
With headphones, the blindfold came out as a flat censor bar across her face, the same failure sing had, so dj takes sing's fix: blindfold off, eyes closed. "Hiding her legs" drew a table on legs with her boots in view; a solid front panel to the ground hides them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: music frames to generate, and the READMEDanilo M.2-1/+27
Twelve frames, dress and leotard. Prompts are a first draft for klein; the user generates them, and until then each falls back to base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: DJ on track change, groove while bored with musicDanilo M.1-4/+50
Reads the sound module's Player, which already filters the MPRIS duplicates. The track key is artist+title while playing, so a pause and resume of the same track does not DJ again; a shell start with music on DJs once, which is harmless. Frame loops are a small table keyed by the frame Mood names, so dj and headbang need no special case in Mood. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: artists page icon as an escape, like its siblingsDanilo M.1-1/+1
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: artist lines pageDanilo M.3-6/+81
PhrasesPage takes its intro, key hint, add-button text and saved set, so the artist set reuses it rather than a copy that would drift. Reset's enabled state read Prefs.companionApps directly and would have tracked the wrong set. ArtistsModule mirrors PhrasesModule on Prefs.companionArtists and Lines.artists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysprefs: companionArtists, saved like companionAppsDanilo M.1-1/+18
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: artist and groove linesDanilo M.2-17/+65
Artist keys match as a case-insensitive substring of the MPRIS artist, so collaborations and feat. credits still hit; the cost is a short key over-matching, marked as a ponytail ceiling. appMap/appList take their defaults so the settings page can serve artists with the same helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: dj and groove states in MoodDanilo M.2-1/+19
A DJ burst ranks just below the headphones sing, so both arriving together sings first. Music turns only the first idle stage into a groove: yawning and lying down still win, so music does not keep her awake and the screensaver handoff is unchanged. The groove pick is an input, keeping pick() pure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysdocs: companion music implementation planDanilo M.1-0/+589
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysdocs: companion music designDanilo M.1-0/+125
She DJs on a track start or change, grooves instead of looking bored while music plays, and says artist lines edited in a settings page that reuses the app phrases page. Player.qml already filters the MPRIS duplicates, so the companion reads it rather than opening players of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: sing when the Sony headphones connectDanilo M.7-8/+45
She now reacts to the headphones connecting with a short singing pose: eyes shut, blindfold gone, mouth wide open, headphones on, a few musical notes. The frames are new klein edits in frames.txt (dress/sing from dress/base, leotard/sing from dress/sing), so a post-self-destruct sing has its own art. Detection is the island's rule (StatusPill.qml): by model prefix, since BlueZ gives no class that says "headphones". The device's BlueZ Name is WH-CH720N, which the alias does not affect. The reaction is a one-shot hold in Mood.js (singHold, 4 s), placed after wave like the other event reactions. A 4 s startup grace keeps a shell start with the headphones already on from counting as a connection, since Bluetooth reads empty for about 2 s.
4 dayscompanion: wave goodbye on hideDanilo M.6-8/+69
SUPER+\ now plays a short goodbye instead of dropping her at once: she cycles wave-l and wave-r around the existing wave for a sway, then the normal drop. One hide in four she also says a bye line, non-forced so the usual 30 s cooldown applies; the hold matches what showed, 2 s with a line and 1 s silent. The sway is klein edits of dress/wave rather than base, so the arm stays up and only the hand moves; the leotard twins come from their dress frames. The leotard rerolled to seed 7 because the first seed left a faint alpha fringe that widened the canvas and made the flip jitter. Fullscreen, the lock screen and the monitor hop keep their own exits and do not wave. Also carries the pending onFocusedChanged guard: with no focused monitor, or already away, she moves at once rather than waiting for an exit that will never settle.
4 dayscompanion: editable per-app lines in a settings pageDanilo M.9-26/+410
Her per-app lines were hardcoded in Lines.js under app:<class>. They now live in Prefs.companionApps once edited and fall back to Lines.js until then, read live by Companion.qml so a save needs no restart. The new Companion phrases page does full CRUD on apps and their phrases, with a draft, SaveBar and Reset to the built-in set, mirroring Ask presets. Companion settings move out of Desktop into their own Companion group.
4 daysdocs: the shell's JS engine has no flatMapDanilo M.1-0/+5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysassistant settings: a cloud switch per tool; cloud Prefer rows showDanilo M.3-14/+82
The Prefer rows for cloud models never built: the shell's JS engine has no Array.prototype.flatMap, and the Repeater's model threw a TypeError (seen in qs log). The ids are now joined with reduce in the module. Each tool row gains a cloud switch, applied on Save after the renames: it writes or drops a top-level cloud = true, validated with tomllib and replaced atomically, on name.toml or name.toml.off. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysassistant: load the chat's model on open, docs for cloud modelsDanilo M.5-13/+32
The canvas asks for its chat's model, else the preferred one, when it opens and when the pick changes; a cloud id loads nothing. The paperclip also closes the model panel, so it and the picker never stack. The plan's Models.qml import is corrected to the one that resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysassistant: pick the chat's model, local or cloud, from the headerDanilo M.3-13/+186
The canvas keeps the chat's model from the daemon (hello.chat_model, conversation.model), falls back to the preferred one (set from shell.qml later), and sends it as model with every ask, typed or spoken. The To .md write stays without one: the daemon always writes with the local model. Models.qml lists the daemon's models event, router models then cloud ones, in a panel like History. It opens from the header label in chat, from a Model button next to History outside chat, and with Ctrl+M. The models are asked for on hello too, so the cloud marker is right before the panel was ever opened. Moving a chat with turns to a cloud model says once that its history goes to that provider. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 daysassistant settings: a Cloud section, and Prefer for cloud modelsDanilo M.1-3/+182
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
4 daysassistant settings: cloud providers, fetch their models, load the chat's modelDanilo M.1-12/+55
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
4 daysassistant settings: read and write the daemon's [[cloud]] tablesDanilo M.2-2/+126
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
4 daysdocs: plan the assistant's cloud models, settings and canvasDanilo M.1-0/+909
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 dayscompanion: the leotard's timeout is a setting, or none at allDanilo M.5-14/+74
Settings > Desktop > Companion takes the seconds she stays in the leotard after the self-destruct, 60 as before. Switched off, she keeps it until she is hidden and shown again, which already put the dress back early. Mood.outfit takes the time instead of reading T. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>