fix(grunt/tui): hivemind sidebar — text wrapping (no more right-edge truncation)#18
Merged
Merged
Conversation
… inbox (no more right-edge truncation) Refs hivemind anomalyco#229. Nik caught visible truncation in screenshot — peer rows showing 'nik-t...' instead of 'nik-tab-2', summary lines clipped at card edge, inbox subject/body chopped to 'ack:' / 'CLAIM' fragments. ## Root cause Sidebar interior width is ~38 cols (Sidebar is 42 wide, paddingLeft=2 + paddingRight=2). Opentui's <text> renderable clips horizontally by default — no auto-wrap on inline rows. Previous implementation crammed peer-id + summary on a single inline row which overflowed and got clipped at the right edge. ## Fix Each peer / inbox row is now TWO explicit lines: - **Peers**: line 1 = '· <peer-id> <relative-time>'. Line 2 = summary (wrapMode='word', truncated to 90 chars). - **Inbox**: line 1 = '<sender>'. Line 2 = subject-or-body (wrapMode='word', truncated to 110 chars). - **You section**: summary line gets wrapMode='word'; peer-id truncated to (SIDEBAR_INNER_COLS - 6) on overflow. Plus a small truncate(s, max) helper that adds an ellipsis (…) so the eye sees that content was cut, not just disappeared. Constants: SIDEBAR_INNER_COLS=38. Reflects the sidebar.tsx width=42 minus paddingLeft=2 + paddingRight=2. ## Verified bun typecheck clean. Local install reports 1.15.10-grunt.7+local.0d4a394a8.dirty.
|
Hey! Your PR title Please update it to start with one of:
Where See CONTRIBUTING.md for details. |
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
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. |
This was referenced May 27, 2026
terrxo
added a commit
that referenced
this pull request
May 27, 2026
…alyco#266 Phase 1) (#21) Bridges gruntcode's per-turn lifecycle to the hivemind-mcp loop primitive shipped in hivemind-mcp v0.8.2 (PR #18) + extended in v0.8.3 (PR #20 await-review). Every step-finish fires hivemind_record_turn_end into the MCP; every successful tool-result fires hivemind_loop_progress. The MCP decides whether to auto-wake the same peer (continue), wake the parent (escalate / await-review), or no-op. Workers self-drive toward goals WITHOUT Nik typing. This is Phase 1 of the loop primitive program (anomalyco#266). Phase 0 (schema + tools + decision logic) lives in hivemind-mcp; this PR wires the gruntcode side that emits the events. Implementation: - packages/opencode/src/session/hivemind-loop-hook.ts (new): - HivemindLoopHook.recordTurnEnd(...) — called from step-finish handler - HivemindLoopHook.loopProgress(...) — called from tool-result handler - Both take MCP.Service as Option (Effect.serviceOption) so the processor degrades cleanly when MCP isn't in context (tests don't have to provide MCP just to satisfy a single hook env requirement) - Both fire-and-forget via Effect.forkIn(scope) + Effect.ignore — the hook MUST NEVER block or throw into the TUI (loop primitive correctness rule; the loop is supposed to PREVENT failures, not cause them) - findHivemindClient: fast-path matches client named 'hivemind'; slow- path scans tools() map for the tool-name suffix (handles users who renamed their MCP under a non-conventional key) - buildTurnSummary deferred until AFTER client resolution to skip the Database.use read when we're no-opping anyway - packages/opencode/src/effect/runtime-flags.ts: - New hivemindLoopEnabled flag (OPENCODE_HIVEMIND_LOOP_ENABLED env var, default false). Opt-in per-tab in Phase 1; planned default-on in Phase 2 after validating in the wild. - packages/opencode/src/session/processor.ts: - Yield MCP.Service via Effect.serviceOption (doesn't leak through Handle.process's never-environment signature; processor still has MCP at runtime via prompt.ts's layer wiring) - case 'step-finish' (after value.reason captured, after summary fork): fires HivemindLoopHook.recordTurnEnd - case 'tool-result' (after completeToolCall): fires HivemindLoopHook.loopProgress - packages/opencode/test/session/hivemind-loop-hook.test.ts (new): - 5 unit tests covering the gating paths: * flag off + MCP=None → silent no-op * flag on + MCP=None → silent no-op (no error) * flag off + (loopProgress) → silent no-op * flag on + MCP=None + (loopProgress) → silent no-op * flag on + MCP=Some (stub w/ empty clients()) → silent no-op (the findHivemindClient miss path) - GRUNTCODE.md: - Documented as patch #5 with the feature flag + behavior. Testing: - bun typecheck (from packages/opencode): green. - bun test test/session/ : 357 pass / 5 skip / 1 todo / 0 fail (was 352 pre-hook; +5 new hook tests). No regressions across the session module (processor-effect.test.ts + compaction.test.ts + all peers in /session still green). - The wake fire-path is exercised end-to-end by the production loop primitive once Phase 1 is enabled per-tab; that's better validated by live use than by mocked MCP calls in unit tests. Refs: - hivemind anomalyco#266 (parent — Phase 1) - hivemind-mcp PR #18 (Phase 0 — schema + 6 tools) - hivemind-mcp PR #20 (await-review decision branch — receiver-side already live on hivemind-mcp main as of 65a1020) - AGENTS.md + hivemind-peers.md three-layer goal-loop contract (the behavioral rules this PR mechanically enforces)
terrxo
added a commit
that referenced
this pull request
May 28, 2026
… inbox (no more right-edge truncation) (#18) Refs hivemind anomalyco#229. Nik caught visible truncation in screenshot — peer rows showing 'nik-t...' instead of 'nik-tab-2', summary lines clipped at card edge, inbox subject/body chopped to 'ack:' / 'CLAIM' fragments. ## Root cause Sidebar interior width is ~38 cols (Sidebar is 42 wide, paddingLeft=2 + paddingRight=2). Opentui's <text> renderable clips horizontally by default — no auto-wrap on inline rows. Previous implementation crammed peer-id + summary on a single inline row which overflowed and got clipped at the right edge. ## Fix Each peer / inbox row is now TWO explicit lines: - **Peers**: line 1 = '· <peer-id> <relative-time>'. Line 2 = summary (wrapMode='word', truncated to 90 chars). - **Inbox**: line 1 = '<sender>'. Line 2 = subject-or-body (wrapMode='word', truncated to 110 chars). - **You section**: summary line gets wrapMode='word'; peer-id truncated to (SIDEBAR_INNER_COLS - 6) on overflow. Plus a small truncate(s, max) helper that adds an ellipsis (…) so the eye sees that content was cut, not just disappeared. Constants: SIDEBAR_INNER_COLS=38. Reflects the sidebar.tsx width=42 minus paddingLeft=2 + paddingRight=2. ## Verified bun typecheck clean. Local install reports 1.15.10-grunt.7+local.0d4a394a8.dirty.
terrxo
added a commit
that referenced
this pull request
May 28, 2026
…alyco#266 Phase 1) (#21) Bridges gruntcode's per-turn lifecycle to the hivemind-mcp loop primitive shipped in hivemind-mcp v0.8.2 (PR #18) + extended in v0.8.3 (PR #20 await-review). Every step-finish fires hivemind_record_turn_end into the MCP; every successful tool-result fires hivemind_loop_progress. The MCP decides whether to auto-wake the same peer (continue), wake the parent (escalate / await-review), or no-op. Workers self-drive toward goals WITHOUT Nik typing. This is Phase 1 of the loop primitive program (anomalyco#266). Phase 0 (schema + tools + decision logic) lives in hivemind-mcp; this PR wires the gruntcode side that emits the events. Implementation: - packages/opencode/src/session/hivemind-loop-hook.ts (new): - HivemindLoopHook.recordTurnEnd(...) — called from step-finish handler - HivemindLoopHook.loopProgress(...) — called from tool-result handler - Both take MCP.Service as Option (Effect.serviceOption) so the processor degrades cleanly when MCP isn't in context (tests don't have to provide MCP just to satisfy a single hook env requirement) - Both fire-and-forget via Effect.forkIn(scope) + Effect.ignore — the hook MUST NEVER block or throw into the TUI (loop primitive correctness rule; the loop is supposed to PREVENT failures, not cause them) - findHivemindClient: fast-path matches client named 'hivemind'; slow- path scans tools() map for the tool-name suffix (handles users who renamed their MCP under a non-conventional key) - buildTurnSummary deferred until AFTER client resolution to skip the Database.use read when we're no-opping anyway - packages/opencode/src/effect/runtime-flags.ts: - New hivemindLoopEnabled flag (OPENCODE_HIVEMIND_LOOP_ENABLED env var, default false). Opt-in per-tab in Phase 1; planned default-on in Phase 2 after validating in the wild. - packages/opencode/src/session/processor.ts: - Yield MCP.Service via Effect.serviceOption (doesn't leak through Handle.process's never-environment signature; processor still has MCP at runtime via prompt.ts's layer wiring) - case 'step-finish' (after value.reason captured, after summary fork): fires HivemindLoopHook.recordTurnEnd - case 'tool-result' (after completeToolCall): fires HivemindLoopHook.loopProgress - packages/opencode/test/session/hivemind-loop-hook.test.ts (new): - 5 unit tests covering the gating paths: * flag off + MCP=None → silent no-op * flag on + MCP=None → silent no-op (no error) * flag off + (loopProgress) → silent no-op * flag on + MCP=None + (loopProgress) → silent no-op * flag on + MCP=Some (stub w/ empty clients()) → silent no-op (the findHivemindClient miss path) - GRUNTCODE.md: - Documented as patch #5 with the feature flag + behavior. Testing: - bun typecheck (from packages/opencode): green. - bun test test/session/ : 357 pass / 5 skip / 1 todo / 0 fail (was 352 pre-hook; +5 new hook tests). No regressions across the session module (processor-effect.test.ts + compaction.test.ts + all peers in /session still green). - The wake fire-path is exercised end-to-end by the production loop primitive once Phase 1 is enabled per-tab; that's better validated by live use than by mocked MCP calls in unit tests. Refs: - hivemind anomalyco#266 (parent — Phase 1) - hivemind-mcp PR #18 (Phase 0 — schema + 6 tools) - hivemind-mcp PR #20 (await-review decision branch — receiver-side already live on hivemind-mcp main as of 65a1020) - AGENTS.md + hivemind-peers.md three-layer goal-loop contract (the behavioral rules this PR mechanically enforces)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs hivemind anomalyco#229. Nik caught visible truncation in screenshot — peer rows showed 'nik-t...' instead of 'nik-tab-2', summaries clipped at card edge.
Root cause
Sidebar interior is ~38 cols. Opentui's
<text>clips horizontally — no auto-wrap. Previous impl crammed peer-id + summary on one inline row that overflowed.Fix
Two explicit lines per peer / inbox row. Line 1 = compact identifier + time. Line 2 = wrapped summary (
wrapMode='word') truncated to safe char budget.Local install: 1.15.10-grunt.7+local.0d4a394a8.dirty.
bun typecheckclean.