Commit Graph

31 Commits

Author SHA1 Message Date
Teknium 1a74e7fb43 feat(desktop): offer Bot Mode agent handles in the composer @ autocomplete
The @ popover only completed filesystem references; bot handles worked
when fully typed (mention middleware parses at submit) but were never
offered, so users had to know the exact handle — worse with multi-source
@name-device handles. Fixes #88060 (ported from Hermes-Bot-Mode#43).

- composer contrib: new 'composer.atCompletions' data area
  (ComposerAtCompletionSource) — contributed rows merge AHEAD of path
  results; a throwing source drops its rows, never the popover
- use-at-completions: merge contributed entries in all three fetch paths
  (gateway results, gateway-less, fetch error)
- SDK: export the new area + types for plugins
- bundled Bot Mode plugin: registers 'mention-completions' — roster
  handles from the query cache (\u22645s stale), active profile excluded,
  'default' offered as @hermes, multi-source @name-device handles via
  botHandle, display name + connection label in the row meta, capped at 8
- registered early in register(ctx) so vm harnesses reach it before the
  pane/UI registrations that stubs can't fully model
2026-08-17 01:43:04 -07:00
Teknium 72785b2657 feat(desktop): Discord-style group chat creation in Bot Mode
The Bots pane header + is now a dropdown (New Agent / New Group Chat).
New Group Chat opens a checkbox-picker modal: searchable roster list,
member cap at GROUP_CHAT_MAX_MEMBERS, group-name input that defaults to
the selected members' names, and a Create button that assigns the
existing per-bot group meta field - so the room rides the ui_meta sync
path unchanged and the user lands directly in the new room.
2026-08-17 01:36:03 -07:00
Teknium 9adc900ab2 fix(bot-mode): route bot-to-bot sends through --create-if-missing
The teammate-messaging protocol told bots to send with
`chat -c "Bot Chat" -Q -q` and, on 'No session found', fall back to a
manual two-step (send without -c, then sessions rename) — a dance the
CLI already made unnecessary when --create-if-missing landed (#86794).
Profiles that never went through the Bots-panel birth flow (CLI-created,
pre-Bot-Mode, remote-source) hit that miss on every first contact, and
background sends swallowed the error entirely (the original silent-drop
in Hermes-Bot-Mode#48 / #88059).

- tools/bot_mode_probe.py: protocol command gains --create-if-missing
- bundled plugin: Bot Chat prompt section + @mention handoff note use
  the flag; rename-dance instructions deleted

The capability epoch hashes the protocol section, so existing eternal
Bot Chat sessions pick the new instructions up on their next message via
the established once-per-change rebuild — no per-turn cache drift.

Live-verified: fresh profile with zero sessions, protocol command
created 'Bot Chat' and delivered (PONG round-trip); second send resolved
the same session by title (no duplicate); missing-title send WITHOUT the
flag still errors loudly on stderr.
2026-08-16 23:28:13 -07:00
Teknium 0b13cafffa feat(cron): continuity toggle across dashboard, Bot Mode routines, and TUI cron RPC
Wire the continuity flag through every cron-creation surface, not just the
model tool:

- dashboard (web/): checkbox in the cron job editor; form state round-trips
  the stored reserved 'self' entry into the toggle and strips it from the
  context_from textarea; web_server dashboard validator skips 'self'
  (create precedes the job's existence)
- Bot Mode Routines tab (hermes-bots plugin): Continuity checkbox in the
  New Cronjob dialog, forwarded through cron.manage
- tui_gateway cron.manage RPC: optional continuity param on action=add

vitest cron-job suite 10/10 (4 new), tsc app project clean, py_compile clean.
2026-08-16 22:09:28 -07:00
Teknium a36583e311 fix(desktop): keep cloud bot avatar eye catchlights inside the eyes
The white catchlight dots in BotFace were static circles pinned at the
circle-face eye line (cy 16.5), while the animation clock moves the
pupils to the shape-aware eye line (cy 22 for the cloud). On the cloud
avatar the highlights floated above the eyes instead of inside them.

- Tag the catchlights (data-hb-hl-l/r) and move them with the pupils in
  paintMathFace, offset upper-left of each pupil center.
- Render the initial eyes/catchlights/shut-lids at the shape-aware eye
  line so the first frame matches the animated frames.
2026-08-16 20:51:58 -07:00
Teknium 8236b41771 feat: sync bundled Bot Mode with multi-source roster (Hermes-Bot-Mode#68)
Pulls the multi-source roster into the bundled plugin: profiles.list rows
from the active gateway are merged with the host.agents() union roster
(hermes-agent #86875), so the Bots panel shows agents from every registered
Desktop connection with @name-device handles for duplicates. Feature-detected
and best-effort — an older Desktop build or roster failure leaves the
single-source list untouched.

Adapted for the bundle:
- useRoster queryFn combines the bot_mode_protocol capability read (which
  landed after #68 was cut) with the multi-source merge
- multi-source-roster tests updated for the namespace SDK import harness
- soul-protocol-backfill anchor widened for the new botHandle(name, bot)
  signature

Plugin suite: 143/143.
2026-08-16 18:30:53 -07:00
Teknium 400400e1d9 fix(hermes-bots): composeSoul honors the bot_mode_protocol capability
Found in live desktop E2E: the generated-identity path of composeSoul
still appended the protocol section even when the backend injects it
into the system prompt. New agents now get a clean identity-only SOUL
against capable backends; older gateways keep the append. Covered in
the capability-suppression test.
2026-08-16 18:30:53 -07:00
Teknium d516496cef fix: track bundled plugin.js sources past the tsc-artifact gitignore
apps/desktop/src/**/*.js is gitignored (stale tsc output shadows .tsx),
which silently dropped the hermes-bots plugin.js from the adoption
commit — tests shipped, source didn't, CI ENOENT'd. Negate the pattern
for src/plugins/*/plugin.js: adopted plain-ESM plugins have no .tsx
sibling, so the shadow hazard cannot apply.
2026-08-16 18:30:53 -07:00
Teknium 366d8814b8 feat(desktop): bundle Bot Mode (hermes-bots) as a built-in, default-on plugin
Adopts the Hermes-Bot-Mode desktop plugin (NousResearch/Hermes-Bot-Mode)
into apps/desktop/src/plugins/hermes-bots/, registered by the bundled
vite glob and ON by default. It stays a pure @hermes/plugin-sdk consumer
in plain-ESM plugin.js form; users disable it live in Settings > Plugins.

- contrib/plugins.ts: bundled glob accepts plugin.js entries
- contrib/runtime-loader.ts: a disk/runtime copy of an id that ships
  bundled is skipped (standalone installs predating adoption cannot
  double-register)
- package.json: check:test:plugins runs the plugin's node:test suite in
  CI (138 tests)
- source: Hermes-Bot-Mode @ c19baba, incl. today's #107/#103/#99 merges
2026-08-16 18:30:53 -07:00
Adolanium 0a9337d2bb feat(desktop): expose busy turn flags on plugin SDK
Plugins can now read host.state.busy and host.state.awaitingResponse
for the focused chat. These follow the same session slice the chat pane
uses, so a draft falls back to the global flags and a background turn
does not leak.
2026-08-16 02:44:54 -07:00
273-B_L0 34f484542e fix(desktop): show platform Kanban modifier 2026-08-15 01:04:06 -07:00
Brooklyn Nicholson 44790bc9c8 feat(desktop): plugin descriptions + open the agent plugins folder
HermesPlugin/PluginRecord gain a description one-liner (kanban gets
one) shown in the inventory instead of the raw file path, and the
agent plugins section can open the backend's plugins dir — path from
config.get profile so it's profile-aware, local backends only since
openDir mkdir-creates.
2026-08-08 17:34:20 -05:00
Brooklyn Nicholson 6f1072c83c fix(desktop): drop the gateway-pill dogfood plugin
It was a 1:1 rebuild of the core statusbar gateway item and shipped
enabled by default, so the pill showed up twice. Core chrome stays in
shell; demos that clone it belong in hermes-example-plugins.
2026-08-06 22:29:33 -05:00
hermes-seaeye[bot] 777512b760 fmt(js): npm run fix on merge (#76498)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-08-02 01:23:45 +00:00
brooklyn! 97971643ab Merge pull request #76417 from NousResearch/bb/kanban-model-picker
Pick a kanban task's model and thinking depth from the board
2026-08-01 16:55:01 -05:00
Brooklyn Nicholson 602fc5f9f5 feat(kanban): pick a task's model and thinking depth from the board
The desktop board had no model control at all: a task ran whatever the profile
you assigned it to happened to be configured with, and the only way to point
one task elsewhere was `hermes kanban set-model` or the browser dashboard's
flat provider:model select.

Adds a Model row to New Task and to the task drawer, rendering the composer's
own picker via the SDK — same search, same provider groups, same submenu — so
the board and the chat bar cannot drift. Unset reads "Profile default" and
changes nothing; a pin reads "provider: model · High" with an inline clear.

Presets are read-only here: picking a model seeds the depth from what you last
used for it, but a per-task choice never rewrites what the composer opens at.
Fast mode is omitted rather than shown-and-ignored — it's a live-session
request parameter with no worker-spawn equivalent.

The New Task dialog opts out of DialogContent's clip: the dialog publishes
itself as the portal container for popovers opened inside it, so its
overflow-y-auto cropped the menu at the dialog's edge. The general fix is in
flight as #75600; this override is scoped to one dialog to avoid conflicting
with it and disappears when that lands.
2026-08-01 16:10:25 -05:00
Brooklyn Nicholson 9175b05b40 fix(desktop): ship example plugin off by default
Match kanban — inventoriable in Settings ▸ Plugins, no statusbar chrome until opted in.
2026-08-01 15:46:36 -05:00
Brooklyn Nicholson 15b0b95413 refactor(desktop): one edge-faded scroller for the whole app
The kanban drawer had grown the only edge-aware masked scroller in the
tree, and the next surface that wants one would have copied it. Lift it
to components/ui as FadeScroll, export it on the plugin SDK, and leave
kanban's ScrollFade as a name its call sites already pass `max` to.

The mask math comes out as two pure functions. jsdom's CSS parser drops
any gradient containing calc(), so a rendered mask-image can't be read
back off the style attribute -- edgeMask/scrollEdges are testable for
real where the component's inline style is not.
2026-08-01 01:23:59 -05:00
hermes-seaeye[bot] 17e5f7244a fmt(js): npm run fix on merge (#75582)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-07-31 18:54:27 +00:00
Brooklyn Nicholson 1238efce13 fix(desktop): track kanban lane phase in state, not a mirrored ref
main landed a lint rule banning refs mirrored from reactive values in an
effect — they lag a render and cause stale reads. The lane-collapse
override tracker did exactly that with a counts ref.

Hold the empty/non-empty signature in state instead. React bails out
when it's unchanged, so a poll where no lane's emptiness moved costs no
extra render, and the comparison always sees the current value.
2026-07-30 07:18:45 -05:00
Brooklyn Nicholson 81e196f236 feat(desktop): kanban new-task hotkey — the plugin command pattern
Creating a task was mouse-only: the header button, the empty state, or a
per-column hover +. Kanban now ships a real command, wired the way any
plugin should wire one.

One action id (kanban.newTask) registered into two areas: KEYBINDS_AREA
gives it dispatch plus a rebindable row in the shortcuts panel, and a
palette row whose `action` field points back at the same id so the live
combo renders as its hotkey hint. The handler is route-independent — it
parks the lane in $newTaskLane and navigates, so the page picks the
request up whether it was already mounted or is mounting for the first
time, then clears it so a remount can't reopen a dismissed dialog.

Default is mod+alt+n (⌘⌥N). mod+n and mod+shift+n are core built-ins a
plugin can't shadow; core uses alt only for the mod+alt+1…9 profile
slots, never with a letter, which leaves ⌘⌥<letter> free as the natural
namespace for plugin commands.

Label ships in the plugin's own locale bundles (en/ja/zh/zh-hant) via
ctx.i18n, so it localizes without a core en.ts edit.
2026-07-30 07:18:45 -05:00
Brooklyn Nicholson eaa61d2aa6 i18n(desktop): move kanban to plugin-scoped ctx.i18n (per #67303)
Now that #67303 shipped the plugin-scoped i18n door, the kanban plugin ships
its OWN locale bundles via ctx.i18n.register instead of a core t.kanban
namespace — nothing added to core en.ts/ja/zh/zh-hant/types.ts. useKanban()
binds usePluginI18n('kanban') to the message SHAPE (one tiny generic) so
components keep their typed k.newTask / k.moveTo(label) access unchanged.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 77f1e84a34 feat(desktop): plugin ctx.onDispose + self-disposing kanban bindApi
The plugin context only tracked contribution/socket disposers, so a plugin's
other side effects (store subscriptions) leaked across disable/re-enable. Add
ctx.onDispose(fn) — an arbitrary cleanup collected alongside the rest and run
on deactivate. bindApi now returns a disposer (unsubscribes its persisted-atom
listeners, closes the socket, drops the rest handle) and the kanban plugin
registers it via ctx.onDispose, so a toggle leaves nothing behind and never
duplicates listeners. Also DRYs the atom-persistence into one `persist` helper.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson f6c8f35a4a i18n(desktop): localize the kanban plugin across all four locales
Every user-facing string in the kanban plugin now routes through useI18n
(new t.kanban namespace) instead of hardcoded English — en, ja, zh, zh-hant
in lockstep (typecheck enforces parity). Column labels/help move out of the
COLUMN_META const (visual-only now) into i18n via columnLabel/columnHelp;
LOCKED_COLUMNS/ARC_TITLES/complexity copy likewise. Matches the rest of the
desktop app, which is fully localized.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 901205420f feat(kanban): talk to a running worker without a restart
A running worker now polls its comment thread and folds new operator notes
into the live turn via the OUT-OF-BAND steer channel (list_comments_after +
a heartbeat-driven bridge, watermarked so history isn't re-injected and the
worker's own notes are skipped). No block→comment→unblock dance. Desktop's
composer sends notes live ("delivered within a few seconds") with "Requeue
with note" as the restart option and a help tooltip.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 346149c4f8 feat(kanban): task effort estimate via the auxiliary model
An "Estimate" action asks the auto-routed auxiliary model for a rough token
count + complexity band (S/M/L) with a one-line rationale — tokens, not
dollars, since providers don't report cost reliably. POST /estimate (typed
title/body, for the create dialog) and POST /tasks/{id}/estimate (existing
cards) share one core. Desktop renders it inline ("~15k tok · Medium") with a
"makes a model call" disclaimer; SDK exports compactNumber.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 027ef381a4 feat(kanban): scope boards to a project
Boards gain an optional project_id. When set, the board's default_workdir
mirrors the project's primary repo and every new task inherits the project —
a deterministic worktree + branch per task — unless it names its own. New
GET /projects; board create/patch/list carry project_id + resolved name; the
create dialog defaults its workspace to the board's and allows a per-task
path override. Desktop: "Board settings…" gains a project picker.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 9be67b7762 fix(desktop): roomier kanban create-task modal
The create form was cramped at max-w-md with a 60vh scroll cap. Widen to a
responsive w-[min(42rem,94vw)] and raise the scroll cap so the fields breathe.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 5c4d1e1ea2 feat(desktop): SDK — useGrabScroll export + dogfood plugin touch-ups 2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 79e7adae2d feat(desktop): Kanban — dashboard-parity board plugin on the SDK
The founding opt-in plugin (defaultEnabled: false): /kanban board + drawer,
live task_events via ctx.socket, ⌘-click bulk ops, auto-nudge dispatch,
collapsible lanes, board switcher, and prose activity — all pure SDK-consumer
work against plugins/kanban/dashboard/plugin_api.py. Backend: /boards totals
count live cards only.
2026-07-30 07:18:08 -05:00
Brooklyn Nicholson 7ed7170960 feat(desktop): plugin manager, runtime loader, and plugins settings 2026-07-13 17:57:53 -04:00