aboutsummaryrefslogtreecommitdiffstats
path: root/desktop/assistant
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-11-10 12:15:23 +0100
committerDanilo M. <danix@danix.xyz>2026-11-10 12:15:23 +0100
commit80306b3a3ad59e3a06a7e694c69be3ada976ff03 (patch)
tree6d9652b779203a45ce3715770c5de25ba37ca0bf /desktop/assistant
parent4736a1a80ba984d3dfb9ff3bcfef6b63b570c6a1 (diff)
downloadquickshell-80306b3a3ad59e3a06a7e694c69be3ada976ff03.tar.gz
quickshell-80306b3a3ad59e3a06a7e694c69be3ada976ff03.zip
feat(assistant): catalog IPC for deck-it, presets sent as written
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/assistant')
-rw-r--r--desktop/assistant/Files.js5
-rw-r--r--desktop/assistant/Ops.js7
-rw-r--r--desktop/assistant/Presets.js25
-rw-r--r--desktop/assistant/README.md7
-rw-r--r--desktop/assistant/test_presets.js8
5 files changed, 37 insertions, 15 deletions
diff --git a/desktop/assistant/Files.js b/desktop/assistant/Files.js
index a75e693..bcbd9bc 100644
--- a/desktop/assistant/Files.js
+++ b/desktop/assistant/Files.js
@@ -48,6 +48,11 @@ function kind(path) {
function chats(k) { return CHAT.includes(k); }
+// kind -> suffixes, for a file dialog's filter (deck-it's picker).
+function exts() {
+ return { text: TEXT, code: CODE, image: IMAGE, video: VIDEO, archive: ARCHIVE, pdf: [".pdf"] };
+}
+
// For a file the name says nothing about (a script with no suffix), from
// the mime type `file -b --mime-type` reports. Prose and data are text;
// any other text type, scripts and source among them, is code.
diff --git a/desktop/assistant/Ops.js b/desktop/assistant/Ops.js
index 4d7ef96..2fb6ab0 100644
--- a/desktop/assistant/Ops.js
+++ b/desktop/assistant/Ops.js
@@ -42,6 +42,13 @@ var COMPRESS = [
{ label: ".tar.bz2", icon: "\uf1c6", op: "tbz2" },
];
+// Every operation as one flat list, for deck-it's tablet tab: the Compress
+// submenu's formats become ops of their own, for any kind.
+function catalog() {
+ return OPS.filter(o => o.op !== "compress")
+ .concat(COMPRESS.map(c => Object.assign({ kinds: ["any"] }, c)));
+}
+
function ext(name) {
const n = name.toLowerCase(), dot = n.lastIndexOf(".");
return dot > 0 ? n.slice(dot) : "";
diff --git a/desktop/assistant/Presets.js b/desktop/assistant/Presets.js
index 0fd6f31..f7cce1c 100644
--- a/desktop/assistant/Presets.js
+++ b/desktop/assistant/Presets.js
@@ -18,15 +18,15 @@
// more files are staged. The list in use is Prefs.presets when one is
// saved (the settings window's Ask presets page edits it), these otherwise.
const DEFAULTS = [
- { label: "Summarize", icon: "\uf036", kinds: ["pdf", "text"], prompt: "Summarize this in a few short paragraphs." },
- { label: "Key points", icon: "\uf0ca", kinds: ["pdf"], prompt: "List the key points as bullets." },
- { label: "Explain simply", icon: "\uf0eb", kinds: ["pdf", "text"], prompt: "Explain this simply, as to a non-expert." },
- { label: "Describe", icon: "\uf06e", kinds: ["image"], prompt: "Describe this image." },
- { label: "Extract text", icon: "\uf031", kinds: ["image", "pdf"], prompt: "Transcribe all the text, keeping the layout where it helps." },
- { label: "What is this?", icon: "\uf059", kinds: ["image"], prompt: "What is this, and what is it for?" },
- { label: "Explain", icon: "\uf121", kinds: ["code"], prompt: "Explain what this code does." },
- { label: "Review", icon: "\uf188", kinds: ["code"], prompt: "Review this code: bugs, risks, and simplifications." },
- { label: "Compare", icon: "\uf0db", kinds: ["many"], prompt: "Compare these files: what they share and how they differ." },
+ { label: "Summarize", icon: "\uf036", kinds: ["pdf", "text"], prompt: "Summarize this in a few short paragraphs. Answer in the language of the document." },
+ { label: "Key points", icon: "\uf0ca", kinds: ["pdf"], prompt: "List the key points as bullets. Answer in the language of the document." },
+ { label: "Explain simply", icon: "\uf0eb", kinds: ["pdf", "text"], prompt: "Explain this simply, as to a non-expert. Answer in the language of the document." },
+ { label: "Describe", icon: "\uf06e", kinds: ["image"], prompt: "Describe this image. Answer in the language of the document." },
+ { label: "Extract text", icon: "\uf031", kinds: ["image", "pdf"], prompt: "Transcribe all the text, keeping the layout where it helps. Answer in the language of the document." },
+ { label: "What is this?", icon: "\uf059", kinds: ["image"], prompt: "What is this, and what is it for? Answer in the language of the document." },
+ { label: "Explain", icon: "\uf121", kinds: ["code"], prompt: "Explain what this code does. Answer in the language of the document." },
+ { label: "Review", icon: "\uf188", kinds: ["code"], prompt: "Review this code: bugs, risks, and simplifications. Answer in the language of the document." },
+ { label: "Compare", icon: "\uf0db", kinds: ["many"], prompt: "Compare these files: what they share and how they differ. Answer in the language of the document." },
];
var FALLBACK = "\uf086";
@@ -45,6 +45,7 @@ function offered(presets, files) {
: files.every(f => p.kinds.includes(f.kind)));
}
-// The model answers in the language it is asked in; a preset is asked in
-// English, so it says which language to use.
-function prompt(p) { return p.prompt + " Answer in the language of the document."; }
+// Sent as written: a preset says which language to answer in, so a
+// Translate preset can name its target. The defaults ask for the
+// document's own language.
+function prompt(p) { return p.prompt; }
diff --git a/desktop/assistant/README.md b/desktop/assistant/README.md
index 4c76a66..a76e9c7 100644
--- a/desktop/assistant/README.md
+++ b/desktop/assistant/README.md
@@ -9,6 +9,13 @@ what is typed. The protocol is specified in that repo,
`docs/superpowers/specs/2026-10-16-text-daemon-design.md`.
qs -p ./desktop ipc call assistant toggle
+ qs -p ./desktop ipc call assistant catalog
+
+`catalog` answers one JSON line for deck-it's tablet tab: the Ask presets
+in use, the Do ops (Compress's formats as ops of their own), kind →
+suffixes, the fileops path, the output folder, the To .md prompt and the
+preferred model. Presets are sent as written, so each says which language
+to answer in.
| File | Does |
| --- | --- |
diff --git a/desktop/assistant/test_presets.js b/desktop/assistant/test_presets.js
index e4a18f4..c2cbcf3 100644
--- a/desktop/assistant/test_presets.js
+++ b/desktop/assistant/test_presets.js
@@ -32,9 +32,11 @@ assert.deepStrictEqual(labels(files("image")), ["Describe", "Extract text", "Wha
assert.deepStrictEqual(labels(files("video")), []);
assert.deepStrictEqual(labels([]), []);
-// Every prompt asks for the document's language.
-for (const p of P.DEFAULTS)
- assert.ok(P.prompt(p).endsWith(" Answer in the language of the document."), p.label);
+// A prompt is sent as written; the defaults ask for the document's language.
+for (const p of P.DEFAULTS) {
+ assert.strictEqual(P.prompt(p), p.prompt, p.label);
+ assert.ok(p.prompt.endsWith(" Answer in the language of the document."), p.label);
+}
// A saved list is used when valid; anything else reads as the defaults.
const mine = [{ label: "Mine", prompt: "Do it.", kinds: ["pdf"] }];