| Age | Commit message (Collapse) | Author | Files | Lines |
|
The desktop companion waves when an answer is ready. The moment already
existed as the done branch that calls notifyDone; it is now a signal
too, so the companion connects to it instead of reading the turn list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Handled on the card, where Escape already is: keys reach a focused
item, and every field in the card bubbles unhandled keys up to it.
Ctrl+N does what New does and is likewise ignored while disconnected;
Ctrl+H toggles the panel the way the History button does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A reply streams into the canvas state while the card is closed, but
nothing said when it was done, so working elsewhere meant checking back.
Now a finished or failed turn sends a notification whose Open action
brings the card back on that conversation. A stopped reply does not
notify: stopping it was the user's own act.
notify-send -A blocks until the notification is acted on or dismissed and
prints the picked key, so one Process carries it. A newer reply restarts
that Process and its stack tag replaces the balloon, which drops the
older wait: only the latest reply's Open works.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A lit chip alone looks frozen on a clone that takes a minute; the running tool now shows the elapsed seconds and resets when it finishes.
|
|
AssistantModule keeps each router model's input_modalities and exposes
hears: the model loading, else the first not unloaded (the daemon's
rule), reports audio. Unknown inputs or a router that is down count as
yes; the daemon's error covers the rest. The model list is now read on
every canvas open, not only when a preferred model is set, so hears is
current when the card shows.
Checked: the rule against the router's live /models (Gemma resident:
on; Qwen resident or loading: off; router down: on). Not yet seen by
eye after a desktop shell reload.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Each recording is a pw-record Process of its own, made from a Component
like the Do row's runs, so a stopped recording's late exit cannot be
read as the next one's. Stopping sets running to false (SIGTERM), which
lets pw-record write the WAV header; the audio ask goes out from the
process's exit, not from the click.
Recording stops itself at 59 s: the daemon refuses over 60 s by file
size, and the stop lands a little after the tick. Escape cancels a
recording before it does anything else, and closing the card or losing
the daemon cancels it too. A pw-record that ends on its own says
"recording failed".
Checked: a scratch harness saw transcribing, thinking, idle for a 2 s
recording; by hand, every case in the spec passed with no pw-record
left behind, a desktop shell reload mid-recording included.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The repository had no name of its own, only the framework's. It is now
Keystone, in the README, AGENTS.md, the settings window, notes commit
messages, calctl's PRODID and the user page's User-Agent.
Its files move off quickshell's name too:
~/.config/quickshell/greetings -> ~/.config/keystone/
~/.config/quickshell/obs-scene-icons.json -> ~/.config/keystone/
$XDG_STATE_HOME/quickshell/desktop.json -> $XDG_STATE_HOME/keystone/
~/.config/quickshell is Quickshell's own default config directory (a
bare qs loads its shell.qml), so sharing it was a collision rather than
a home. There is no fallback to the old paths: the files are moved once.
The layer namespaces become keystone-*, and the Hyprland blur rules in
hypr-theme are renamed to match in the same change. A running shell
keeps its old namespaces until restarted.
Left alone: the retired standalone mail and vm shells' namespaces,
which their READMEs keep as history; Quickshell's own app id, binary
and process name; and the repository directory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Load set the preference as well as swapping the model in, so loading a
model from the settings page for any reason made it the assistant's
model too: after loading Qwen there, the canvas kept Qwen instead of
bringing the preferred Gemma back. Load and Prefer are now separate
buttons: Load swaps a model in now and leaves the preference alone, and
Prefer only records which model the canvas loads when it opens.
The canvas header also showed a stale model name after a swap; it now
takes the model from the daemon's ctx event, which carries it from
desktop-assistant f9d4644 on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A preferred model that only took effect from the settings page did
nothing the next time another client had swapped it out. On this
desktop one model and one client run at a time, so opening the canvas
is when the assistant's model should come back: if the preferred one is
neither loaded nor loading, it is loaded, and the canvas header says so
until the router reports it in. The daemon still never asks for a model;
with no preference set nothing changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Two settings pages for desktop-assistant.
Assistant edits the daemon's config.toml: server, temperature, tool
rounds, thinking, the system prompt, and the [env] values its tools
read; a switch per tool renames tools/<name>.toml to .toml.off, which
the daemon's glob skips. The daemon reads all of it at startup only, so
the page says when a change is pending and Restart runs assistant.sh
restart, showing its status when the daemon does not come back.
The file is edited line by line, like autostart.lua, so the comments
the example ships with survive: unset keys stay commented out in place.
Every write parses the whole new file with tomllib first and replaces
the old one atomically, so no edit can leave a config the daemon will
not start with. Defaults are read from assistant.py --defaults rather
than copied into QML.
Ask presets edits the canvas's canned questions, which Prefs already
stored for exactly this page: label, question, and the kinds each is
offered for. They apply live.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The Do tile's hover and press fills were Qt.alpha colours, and the
Glow sits beneath the tile (z: -1), so the translucent fill let it
wash out the icon and the label. Qt.tint over Theme.surface keeps the
fill opaque, so the glow reads as a glow around a solid tile rather
than through it.
|
|
The canvas: a To .md ended any other way than its own Stop (the footer
Stop, a question, a drop, a daemon restart, an older daemon refusing the
command) left the card at Working forever. The footer Stop goes through
stopOp(), asking and dropping end the operation first, a disconnect ends
it, and an error while nothing else runs is taken as its outcome. Each
fileops run gets its own Process, so a stopped run's late answer is never
read as the next one's. To .md takes one PDF, as one file is written.
Compress... no longer flips back when file(1) refines a kind, long errors
are elided, and a desktop with no documents folder gets
Documents/Assistant rather than ~/Assistant.
fileops: an animated GIF to PNG or JPEG left one file per frame under
names the rename never found; the first frame is taken. JPEG flattens
transparency onto white. Zipping a folder holding the output folder read
its own growing archive without end; only regular files outside it are
added, which also skips FIFOs and dangling links. qpdf warnings no longer
fail a merge. A folder's free name keeps its dots, a lone .gz or .xz is
decompressed rather than refused, and a dotfile's archive is not hidden.
Tools die with fileops even when it is killed outright, a killed run's
leftovers are swept on the next run, a stop between fork and bookkeeping
cannot miss the child, and a late stop cannot add a second answer.
Error lines lose bsdtar's doubled prefix and its delayed-exit noise.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The actions sat as buttons bunched at the left of the card. Each group is
now a grid of equal tiles across the card's width, icon over label,
about 150 px a column, with a small Ask or Do caption. Icons are Font
Awesome and Octicons codepoints checked in Inconsolata Nerd Font's cmap;
a saved preset without one gets a fallback. The lists referenced from
QML are var, since a library's top-level const is not reliably exposed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Conversions, extraction, merge and compression on the staged files from
the file state, one at a time, with Stop; Compress… opens its formats.
To .md goes through the daemon's write, the rest through fileops. The
card keeps the result line, Saved name with Open and Folder, or the
error, so another operation can follow on the same files. Results land in
Documents/Assistant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
One CLI for converting, extracting, merging and compressing staged files,
answering with one JSON line. Results are written under a temporary name
and renamed to the first free one, so a failure or a stop leaves nothing
half written, and a stop kills the tool's whole process group. This
ffmpeg has no libx264 and no AAC encoder, so MP4 is H.264 through VAAPI
with MP3 audio, and audio extraction copies AAC, MP3 and Opus tracks as
they are. The test builds its inputs and checks every result's type.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A script with no suffix staged as 'other' and was refused. A staged file
the name says nothing about is now handed to file(1) once, and its mime
type gives the kind, so a shell script is code and gets Explain and
Review. The daemon makes its own call on the content.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A row of canned questions matching every staged file's kind, plus Compare
for two or more files: one click asks it, Shift+click puts it in the input
to edit first. Defaults live in Presets.js and the list in use in Prefs, so
a future drawer settings page can edit it; a saved list that does not
validate reads as the defaults. Each prompt asks for an answer in the
document's language. Code and configuration get their own kind, so a
script is offered Explain and Review rather than Summarize. Button's
clicked signal carries the mouse event for the Shift check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
From review. A shell reload reconnected with lastActive at 0, so the next
SUPER+Home started a new conversation thirty seconds into one; hello with
turns now counts as activity. show() could send new under a reply still
running, which stops it unsaved; it waits while busy. ask() cleared the
chips before the daemon accepted them, so a refused file (unreadable, too
big, a model without vision) dropped them and collapsed the card to the
entry line; the user event clears them now, and chatting holds the layout
while a PDF is read.
In the picker, folders ignore name filters and sorted first, so filter
then Enter opened a folder; folders hide while filtering. Folder URLs are
encoded, so a '#' in a name no longer cuts the path, and glob characters
typed in the filter are taken literally. The card says the assistant is
not running in every state, panels sit under the chat header instead of
over it, and History and the picker no longer open together. Dropped
file://localhost/ URLs are accepted, other hosts refused, and the island
receptor keeps the sliver's width at rest so it takes no clicks beside it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The card has three states: an entry line, a file state for staged files with Chat about it, and the chat. SUPER+Home resumes a conversation active in the last 10 minutes and otherwise starts a new one. The paperclip opens a picker drawn in the card, since a system dialog would open beneath the overlay that holds the keyboard. Button gains a font alias for the paperclip glyph, and the canvas a socketPath property so a check can point it at a scratch daemon.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
Files.js decides what the card offers for a staged file; the daemon decides what chat accepts, so the text and image lists match its own. Dropped URLs become paths only for file:// ones.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
From review of the canvas. Escape stopped working in three ways, each
leaving the keyboard grabbed with nothing to receive it: the history
field hiding took focus with it, a disabled input could not hold focus
while the daemon was down, and a click in a streaming reply focused text
the next flush destroyed. The card now gives focus back to the input
whenever it falls out, and the input is read-only rather than disabled.
Only an error the daemon marks as ending the reply (turn) closes the live
row; a command error, possibly another client's, used to freeze the reply
mid-stream. The running tool comes from state events, hello included.
Scrolling up during a stream no longer snaps back, since following stops
when a movement starts. History snippets go through Notify.sanitize like
any model output, links open only for http, https and mailto, and a line
opening with inline triple-backtick code is no longer taken as a fence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The socket, the turn model and the window live in Assistant.qml, outside
the window's loader, so closing the card loses nothing and a reply keeps
streaming while it is closed. Tokens reach the model on a 50 ms tick
rather than per token. Prose goes through Notify.sanitize, because model
output can quote a search result and a remote image in it would be
fetched on render. Code blocks get a copy button once their fence closes.
The history panel lists conversations and searches them through the
daemon's full-text index.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
Qt's markdown renders a fence but gives no per-block hook, so a copy
button per code block needs the fences found first. An unclosed fence is
open code, which is every fence while a reply streams; a fence inside a
list item keeps its indent out of the copied text.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|