feat(ags-v3): brain HUD terminal — kitty toggle + single instance + COSMIC window rule

- BrainPower panel: dashboard only (VTE embed pas compatible AGS JSX)
- toggle-brain.sh: ouvre/ferme panel AGS + terminal Kitty (single instance via pgrep)
- Kitty class brain-hud-terminal pour COSMIC window rule (floating)
- app.ts: cleanup focusBrainTerm removed
- style.scss: brain-terminal class + brain-commits-list
This commit is contained in:
2026-03-26 15:54:49 +01:00
parent 9eaaa01663
commit 29b4c54370
3 changed files with 57 additions and 81 deletions

View File

@@ -124,4 +124,11 @@ window.BrainPower {
font-family: "Maple Mono NF", monospace;
padding: 4px 0 4px 16px;
}
.brain-terminal {
background: #1a0e27;
border-radius: 0 0 $radius 0;
padding: 4px;
min-height: 400px;
}
}

View File

@@ -1,3 +1,32 @@
#!/bin/bash
# Toggle Brain Power panel via AGS IPC
ags request "toggle-brain" 2>/dev/null
# Toggle Brain Power — dashboard AGS + terminal Kitty (single instance)
BRAIN_ROOT="${BRAIN_ROOT:-$HOME/Dev/Brain}"
KITTY_CLASS="brain-hud-terminal"
# Check if brain kitty is already running (by window class)
kitty_pid=$(pgrep -f "class $KITTY_CLASS" | head -1)
if [ -n "$kitty_pid" ]; then
# Close everything
ags request "toggle-brain" 2>/dev/null
kill "$kitty_pid" 2>/dev/null
else
# Open everything
ags request "toggle-brain" 2>/dev/null
kitty \
--class "$KITTY_CLASS" \
--title "🧠 Brain HUD" \
--override remember_window_size=no \
--override initial_window_width=60c \
--override initial_window_height=30c \
--override background_opacity=0.94 \
--override background=#1a0e27 \
--override foreground=#f0eaf8 \
--override cursor=#ff4da6 \
--override font_size=13 \
--override confirm_os_window_close=0 \
--directory "$BRAIN_ROOT" \
-e zsh -c "echo '🧠 Brain HUD — navigate mode'; echo ''; exec zsh" \
&
disown
fi

View File

@@ -2,6 +2,7 @@ import app from "ags/gtk3/app"
import { Astal, Gtk, Gdk } from "ags/gtk3"
import { createPoll } from "ags/time"
import { getBrainState } from "../../lib/brain"
import GLib from "gi://GLib"
function BrainContent() {
const state = createPoll("", 10000, () => JSON.stringify(getBrainState()))
@@ -9,109 +10,55 @@ function BrainContent() {
const version = state((s: string) => {
try { return `kernel v${JSON.parse(s).kernelVersion}` } catch { return "" }
})
const focus = state((s: string) => {
try { return JSON.parse(s).focus } catch { return "..." }
})
const session = state((s: string) => {
try {
const sess = JSON.parse(s).session
return sess || "aucune session active"
} catch { return "..." }
try { return JSON.parse(s).session || "aucune session active" } catch { return "..." }
})
const intentionsTitle = state((s: string) => {
try {
const i = JSON.parse(s).intentions
return ` INTENTIONS (${i.active} active${i.active > 1 ? "s" : ""})`
} catch { return " INTENTIONS" }
})
const intentionsList = state((s: string) => {
try {
const names = JSON.parse(s).intentions.names
return names.map((n: string) => `${n}`).join("\n") || " aucune"
return JSON.parse(s).intentions.names.map((n: string) => `${n}`).join("\n") || " aucune"
} catch { return "..." }
})
const todosTitle = state((s: string) => {
try {
const t = JSON.parse(s).todos
return `${t.open} ouverts / ${t.done} faits`
} catch { return "" }
try { const t = JSON.parse(s).todos; return `${t.open} ouverts / ${t.done} faits` } catch { return "" }
})
const todosList = state((s: string) => {
try {
const t = JSON.parse(s).todos.top3
return t.map((item: string) => `${item}`).join("\n") || " rien"
} catch { return "..." }
})
const reposStatus = state((s: string) => {
try {
const repos = JSON.parse(s).repos
return repos.map((r: any) => ` ${r.name.padEnd(14)} ${r.status}`).join("\n")
} catch { return "..." }
})
const commitsList = state((s: string) => {
try {
const commits = JSON.parse(s).commits
return commits.map((c: string) => ` ${c}`).join("\n") || " aucun"
return JSON.parse(s).todos.top3.map((item: string) => `${item}`).join("\n") || " rien"
} catch { return "..." }
})
return (
<box orientation={Gtk.Orientation.VERTICAL} class="brain-content">
{/* FOCUS */}
<box class="brain-section">
<label class="brain-section-title" label=" FOCUS" xalign={0} />
<label class="brain-version" label={version} xalign={1} hexpand />
</box>
<label class="brain-focus" label={focus} xalign={0} wrap />
<box class="brain-divider" />
{/* SESSION */}
<box class="brain-section">
<label class="brain-section-title" label=" SESSION" xalign={0} />
</box>
<label class="brain-session" label={session} xalign={0} />
<box class="brain-divider" />
{/* INTENTIONS */}
<box class="brain-section">
<label class="brain-section-title" label={intentionsTitle} xalign={0} />
</box>
<label class="brain-intentions-list" label={intentionsList} xalign={0} />
<box class="brain-divider" />
{/* TODOS */}
<box class="brain-section">
<label class="brain-section-title" label="󰄲 TODOS" xalign={0} />
<label class="brain-todos-count" label={todosTitle} xalign={1} hexpand />
</box>
<label class="brain-todos-list" label={todosList} xalign={0} />
<box class="brain-divider" />
{/* REPOS */}
<box class="brain-section">
<label class="brain-section-title" label=" REPOS" xalign={0} />
</box>
<label class="brain-repos-status" label={reposStatus} xalign={0} />
<box class="brain-divider" />
{/* COMMITS */}
<box class="brain-section">
<label class="brain-section-title" label=" DERNIERS COMMITS" xalign={0} />
</box>
<label class="brain-commits-list" label={commitsList} xalign={0} />
</box>
)
}
@@ -129,12 +76,6 @@ export default function BrainPower(gdkmonitor: Gdk.Monitor) {
anchor={TOP | LEFT | BOTTOM}
application={app}
layer={Astal.Layer.OVERLAY}
>
<eventbox
onHoverLost={() => {
const win = app.get_window("brain-power")
if (win) win.visible = false
}}
>
<box orientation={Gtk.Orientation.VERTICAL} class="brain-panel">
<box class="brain-header">
@@ -151,7 +92,6 @@ export default function BrainPower(gdkmonitor: Gdk.Monitor) {
</box>
<BrainContent />
</box>
</eventbox>
</window>
)
}