Skip to content
This repository was archived by the owner on Aug 17, 2026. It is now read-only.

feat(grunt/tui): hivemind sidebar + clickable #N ticket refs - #12

Merged
terrxo merged 2 commits into
devfrom
grunt-feat/hivemind-sidebar-and-clickable-refs
May 26, 2026
Merged

terrxo merged 2 commits into
devfrom
grunt-feat/hivemind-sidebar-and-clickable-refs

Conversation

@terrxo

@terrxo terrxo commented May 26, 2026

Copy link
Copy Markdown

Closes hivemind anomalyco#229 + anomalyco#233 — makes hivemind state ambient in the gruntcode TUI.

What ships

Hivemind sidebar (anomalyco#229)

A 'hivemind' card inside the existing right-side Sidebar, between the session title block and the 'grunt' + 'code' footer. Polls hivemind-api every 2s and renders:

  • You — peer id, summary, wakeable flag, last_seen
  • Peers — other alive sessions with one-line summaries
  • Inbox — unread DMs targeting you (client-side filtered; polling does NOT auto-markRead)
  • Board — open / claimed / stale counts, with high-prio and 'mine' highlights

When hivemind-api is down: 'api offline' placeholder. When session isn't announced: 'not announced yet — set --peer-id to register' hint.

Wake-log section deferred (hivemind-api doesn't expose /api/wake-log yet; filed as follow-up). The other 4 sections cover the ambient-awareness use case Nik called out: 'open gruntcode tab → see hivemind context without context-switching.'

Clickable #N ticket refs (anomalyco#233)

Assistant message text now gets a tiny preprocess pass that turns #229 into the markdown link [#229](http://localhost:5173/tasks/229). The markdown renderer styles the result with theme.markdownLink (blue/cyan); terminals supporting OSC 8 (iTerm2, kitty) make it clickable.

Regex ((^|[^\\w/#])#(\\d{1,5})\\b) avoids false positives:

URL base configurable via HIVEMIND_UI_BASE env; defaults to http://localhost:5173 to match the running hivemind-ui dev server.

Files

File What
packages/opencode/src/cli/cmd/tui/context/hivemind.tsx New — solid-js context + poll loop + state store
packages/opencode/src/cli/cmd/tui/routes/session/hivemind-sections.tsx New — the 4 rendered sections
packages/opencode/src/cli/cmd/tui/app.tsx Wraps tree in HivemindProvider
packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx Renders HivemindSections in the scrollbox
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx linkifyTicketRefs() + TextPart preprocesses text before markdown render

Verified

  • bun typecheck clean
  • scripts/install-local.sh builds + signs + installs without errors
  • Bin reports v1.15.10-grunt.7-5-g18407fd53-dirty-local

Out of scope (file follow-ups)

  • Wake-log section in sidebar — needs hivemind-api endpoint (filed)
  • PR ref linkification (grunt-it/gruntcode#11) — text-only nice-to-have; markdown already auto-linkifies bare URLs
  • Hover-preview tooltips — would need direct opentui events; OSC 8 click is the v1
  • Settings page exposing the apiBase / uiBase / poll interval — env-overridable today, opencode.json schema can follow

Refs hivemind anomalyco#229 + anomalyco#233 — make hivemind state ambient in the gruntcode TUI
so Nik has operator awareness without window-switching to hivemind-ui.

## Hivemind sidebar (anomalyco#229)

New 'hivemind' panel inside the existing right sidebar, between the session
title block and the gruntcode footer. Polls hivemind-api on
localhost:7890 every 2s for:

- This peer's status (id, summary, wakeable flag, last_seen)
- Live peers (other alive sessions, with summaries)
- Unread inbox (DMs targeting this peer; client-side filtered, doesn't
  auto-markRead just from polling)
- Board pulse (open / claimed / stale counts; high-prio + mine highlights)

When hivemind-api is down, shows a 'api offline' placeholder. When the
session isn't announced (no --peer-id), shows 'not announced yet'.

Wake-log section deferred — hivemind-api doesn't yet expose
/api/wake-log; filed as a follow-up. The other 4 sections cover the
core ambient-awareness use case.

New files:
- packages/opencode/src/cli/cmd/tui/context/hivemind.tsx — solid-js
  context with poll loop + state store
- packages/opencode/src/cli/cmd/tui/routes/session/hivemind-sections.tsx
  — the 4 rendered sections

Wired:
- app.tsx wraps the tree in HivemindProvider
- sidebar.tsx renders <HivemindSections /> in the existing scrollbox

## Clickable #N ticket refs (anomalyco#233)

In the assistant message TextPart, before passing markdown to the renderer,
linkify hivemind ticket refs: 'anomalyco#229' becomes the markdown link
'[anomalyco#229](http://localhost:5173/tasks/229)'. The markdown renderer styles
links with theme.markdownLink (blue/cyan); terminals supporting OSC 8
(iTerm2, kitty) make the link clickable. Falls back to colored-but-non-
clickable in older terminals.

Regex `(^|[^\w/#])#(\d{1,5})\b` avoids false positives on hex colors
(#fff has letters), already-linked refs ([anomalyco#229] won't match because
prev char is '['), and longer-than-5-digit numbers.

URL base configurable via HIVEMIND_UI_BASE env (defaults to
http://localhost:5173 to match the running hivemind-ui dev server).

## Tested

bun typecheck clean. Local install via scripts/install-local.sh works;
binary reports v1.15.10-grunt.7-5-g18407fd53-dirty-local.
@github-actions

Copy link
Copy Markdown

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

@github-actions

Copy link
Copy Markdown

Hey! Your PR title feat(grunt/tui): hivemind sidebar + clickable #N ticket refs doesn't follow conventional commit format.

Please update it to start with one of:

  • feat: or feat(scope): new feature
  • fix: or fix(scope): bug fix
  • docs: or docs(scope): documentation changes
  • chore: or chore(scope): maintenance tasks
  • refactor: or refactor(scope): code refactoring
  • test: or test(scope): adding or updating tests

Where scope is the package name (e.g., app, desktop, opencode).

See CONTRIBUTING.md for details.

…visible from first frame)

Refs hivemind anomalyco#229. The hivemind sidebar lives inside the session route — so
bare `gruntcode` landing on the home/splash route HID the sidebar until the
user submitted their first prompt. Nik's intent was 'open gruntcode tab and
already be in that view, ready to type'.

This effect auto-creates an empty session and navigates when:
- No explicit --session / --continue / --fork
- No --prompt (--prompt has its own auto-submit path on home)
- Currently on home route
- sync + model are ready (session.create requires agent + model)

Escape hatch: OPENCODE_DISABLE_AUTO_SESSION=1 keeps legacy 'land on splash'
behavior for users who prefer the home route.
@terrxo
terrxo merged commit 1e35d25 into dev May 26, 2026
2 of 8 checks passed
@terrxo
terrxo deleted the grunt-feat/hivemind-sidebar-and-clickable-refs branch May 26, 2026 23:58
terrxo added a commit that referenced this pull request May 28, 2026
* feat(grunt/tui): hivemind sidebar + clickable #N ticket refs

Refs hivemind anomalyco#229 + anomalyco#233 — make hivemind state ambient in the gruntcode TUI
so Nik has operator awareness without window-switching to hivemind-ui.

New 'hivemind' panel inside the existing right sidebar, between the session
title block and the gruntcode footer. Polls hivemind-api on
localhost:7890 every 2s for:

- This peer's status (id, summary, wakeable flag, last_seen)
- Live peers (other alive sessions, with summaries)
- Unread inbox (DMs targeting this peer; client-side filtered, doesn't
  auto-markRead just from polling)
- Board pulse (open / claimed / stale counts; high-prio + mine highlights)

When hivemind-api is down, shows a 'api offline' placeholder. When the
session isn't announced (no --peer-id), shows 'not announced yet'.

Wake-log section deferred — hivemind-api doesn't yet expose
/api/wake-log; filed as a follow-up. The other 4 sections cover the
core ambient-awareness use case.

New files:
- packages/opencode/src/cli/cmd/tui/context/hivemind.tsx — solid-js
  context with poll loop + state store
- packages/opencode/src/cli/cmd/tui/routes/session/hivemind-sections.tsx
  — the 4 rendered sections

Wired:
- app.tsx wraps the tree in HivemindProvider
- sidebar.tsx renders <HivemindSections /> in the existing scrollbox

In the assistant message TextPart, before passing markdown to the renderer,
linkify hivemind ticket refs: 'anomalyco#229' becomes the markdown link
'[anomalyco#229](http://localhost:5173/tasks/229)'. The markdown renderer styles
links with theme.markdownLink (blue/cyan); terminals supporting OSC 8
(iTerm2, kitty) make the link clickable. Falls back to colored-but-non-
clickable in older terminals.

Regex `(^|[^\w/#])#(\d{1,5})\b` avoids false positives on hex colors
(#fff has letters), already-linked refs ([anomalyco#229] won't match because
prev char is '['), and longer-than-5-digit numbers.

URL base configurable via HIVEMIND_UI_BASE env (defaults to
http://localhost:5173 to match the running hivemind-ui dev server).

bun typecheck clean. Local install via scripts/install-local.sh works;
binary reports v1.15.10-grunt.7-5-g18407fd53-dirty-local.

* feat(grunt/tui): bare gruntcode auto-lands in session route (sidebar visible from first frame)

Refs hivemind anomalyco#229. The hivemind sidebar lives inside the session route — so
bare `gruntcode` landing on the home/splash route HID the sidebar until the
user submitted their first prompt. Nik's intent was 'open gruntcode tab and
already be in that view, ready to type'.

This effect auto-creates an empty session and navigates when:
- No explicit --session / --continue / --fork
- No --prompt (--prompt has its own auto-submit path on home)
- Currently on home route
- sync + model are ready (session.create requires agent + model)

Escape hatch: OPENCODE_DISABLE_AUTO_SESSION=1 keeps legacy 'land on splash'
behavior for users who prefer the home route.
terrxo added a commit that referenced this pull request Jun 1, 2026
…gle <markdown> (no flicker) (anomalyco#331)

Definitive fix after exhausting the alternatives (all build-tested):
- single <markdown> is the ONLY flicker-free renderer; per-block split flickered
  on stream + lost formatting.
- markdown [#N](url) links always leak the URL in this app (no tree-sitter);
  inline <a> can't live inside <markdown>.
- JS-side column estimation drifted (hover 'all over the place').

So: keep ONE <markdown> rendering plain  (clean, full formatting, wrap-correct,
flicker-free), and resolve hover/click by reading the renderer's actual FRAMEBUFFER —
renderer.currentRenderBuffer.buffers.char is a public Uint32Array indexed y*width+x.
ticketIdAtCell() inspects the characters painted under the cursor and returns the
#N id (with the same boundary rules as the text regex: rejects foo#12, ##12, #fff).
Pixel-accurate (uses rendered cells, not a reconstruction), null off-ref so the
hover card closes. Drives the existing TicketHoverCard; onMouseUp opens hivemind-ui.

10 framebuffer hit-test unit tests + TUI suite (143 pass) + typecheck green.
terrxo added a commit that referenced this pull request Jun 1, 2026
…-process (anomalyco#331)

Refs render as plain #N inside <markdown> (a markdown link leaks its URL), so
they were base text color. Recolor the painted #N cells in a renderer
post-process (renderer.addPostProcessFn): single buffer scan re-drawing matched
#N runs in theme.markdownLink + underline. Same boundary rules as the hit-test
(skips foo#12 / ##12 / #fff). Theme proxy is read each frame so it tracks theme
switches.

4 recolor unit tests (+ existing 10 hit-test) + TUI suite (147 pass) + typecheck green.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant