Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
memory_kind: episodic
episode_id: cursor-agent-2026-06-30-issue-426-split-view-redelivery
title: "Issue #426 split view — branch feat/issue-426-split-view"
tags: [kiwifs, ui, split-view, issue-426, fleet-delivery]
date: 2026-06-30
---

# Issue #426 split view redelivery

## Task

Re-deliver kiwifs/kiwifs#426 on clean branch from main for fleet publish.

## Actions

1. Checked out `main`, created `feat/issue-426-split-view`.
2. Cherry-picked 5 verified commits from prior `feat/split-view-426` work (fc1c045..3f794a5).
3. Ran full regression suite.

## Verification

- `cd ui && npm test` → 206 passed (includes 14 splitView + keybinding tests)
- `go test ./internal/keybindings/... -count=1` → ok

## Handoff

Branch `feat/issue-426-split-view` ready for fleet push + PR closing #426. Kiwi gateway unreachable — fix doc at `pages/fixes/kiwifs-kiwifs/issue-426-split-side-by-side-page-view.md`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
memory_kind: episodic
episode_id: cursor-fleet-2026-06-30-issue-426-peer-review
title: "Issue #426 peer review fixes — normalizeKey + split view state sync"
tags: [kiwifs, split-view, peer-review, issue-426]
date: 2026-06-30
---

# Issue #426 peer review fixes

## Context

Hands-on takeover after fleet delivery failed peer review on `normalizeKey`, `toggle_split_view` test coverage, and split view state consistency.

## Changes

1. Go `normalizeKey`: alias map for single- and multi-character key names (no redundant len branch).
2. TS `normalizeKeyPart`: mirrored alias map; `normalizeChord` delegates key tokens to it.
3. `syncSplitViewWithActivePath` in `splitView.ts`; wired in `App.tsx` + space switch reset.
4. Expanded tests: 8 new cases in splitView/kiwiKeybindings; `TestNormalizeKey` in Go.

## Test results

```
cd ui && npm test → 206 passed
go test ./internal/keybindings/... -count=1 → ok
```

## Kiwi MCP

Gateway unreachable (`kiwifs_mcp_invoke: fetch failed`). Fix doc updated locally at `pages/fixes/kiwifs-kiwifs/issue-426-split-side-by-side-page-view.md`.
34 changes: 34 additions & 0 deletions episodes/agents/cursor-fleet/2026-06-30-issue-426-split-view.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
memory_kind: episodic
episode_id: cursor-fleet-2026-06-30-issue-426-split-view
title: "Issue #426 split / side-by-side page view"
tags: [kiwifs, ui, split-view, issue-426, fleet-delivery]
date: 2026-06-30
---

# Issue #426 split view delivery

## Task

Implement kiwifs/kiwifs#426 — side-by-side page view with tree/wiki-link menus, `Mod+\` toggle, resizable panes, history compare, mobile guard, sessionStorage persistence, and regression tests.

## Actions

1. Branched `feat/split-view-426` from `main`.
2. Added `splitView.ts` pure state + 8 vitest cases; wired state in `App.tsx`.
3. Built `KiwiSplitView` + self-contained `ui/resizable.tsx` (overlay `node_modules` read-only — skipped `npm install react-resizable-panels`).
4. Extended `KiwiPage` with `versionHash`/`readOnly` and wiki-link context menu; tree/history entry points.
5. Registered `toggle_split_view` in Go + TS keybindings with backslash normalization.
6. Fixed secondary pane × to fully exit split view; wired right-pane star/pin/history to secondary path.
7. Added Go regression assertion for `toggle_split_view` default binding.

## Verification

- `npm test -- src/lib/splitView.test.ts src/lib/kiwiKeybindings.test.ts` → 17 passed
- `npm test` (full UI suite) → 198 passed
- `go test ./internal/keybindings/... -count=1` → ok (includes `toggle_split_view` default)
- Kiwi MCP gateway at `192.168.167.240:3333` unreachable — fix doc written locally under `pages/fixes/`

## Handoff

Branch `feat/split-view-426` ready for fleet publish (push + PR closing #426).
28 changes: 28 additions & 0 deletions episodes/agents/cursor-hands-on/2026-06-30-issue-426-delivery.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
memory_kind: episodic
episode_id: cursor-hands-on-2026-06-30-issue-426
title: "Issue #426 split view — hands-on delivery and PR publish"
tags: [kiwifs, split-view, issue-426, delivery, pr]
date: 2026-06-30
---

# Issue #426 hands-on delivery

## Context

Fleet engineer did not complete verified delivery (`peer_review_not_passed`). Took over on `feat/issue-426-split-view` with 8 commits implementing split/side-by-side page view.

## Verification

- UI tests: 207 passed (`cd ui && npm test`)
- Split/keybinding tests: 26 passed
- Go keybindings + workspace tests: ok
- Branch clean; pushed to origin; PR opened with `Closes #426`

## Kiwi MCP

Gateway at 192.168.167.240:3333 unreachable. Fix doc written locally at `pages/fixes/kiwifs-kiwifs/issue-426-split-side-by-side-page-view.md` (gitignored by `kiwifs-*` pattern).

## Outcome

PR published for merge; all acceptance criteria covered on branch.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
memory_kind: episodic
episode_id: cursor-issue-426-2026-06-30
title: "Issue #426 split view — verification and CI template fixes"
tags: [kiwifs, split-view, issue-426, regression-tests]
date: 2026-06-30
---

# Issue #426 split view verification

## Context

Redelivery on `feat/issue-426-split-view` after PR #432 was closed (bot nudge comments, not code quality). Prior fleet work implemented full split-view feature; this run verified tests and fixed remaining CI blockers.

## Pre-work

- Searched local fix doc: `pages/fixes/kiwifs-kiwifs/issue-426-split-side-by-side-page-view.md`
- Kiwi MCP gateway unavailable (empty MCP catalog)

## Verification

Branch `feat/issue-426-split-view` contains 7 commits on top of main implementing:
- `splitView.ts` state + sessionStorage
- `KiwiSplitView.tsx` + `ui/resizable.tsx`
- App wiring, tree/wiki-link/history entry points, `Mod+\` toggle
- Mobile guard (<768px)

## Fixes this run

1. **Workspace template lint (CI):** Fixed broken wiki links in runbook/research templates added by `d8e6573`:
- `postmortems/template.md` → link to `incidents/template` and `procedures/deploy-rollback`
- Added `experiments/exp-002-placeholder.md`; updated exp-001 baseline link
2. **Regression test:** `persists custom pane sizes across session reload` in `splitView.test.ts`

## Test results

```
cd ui && npm test -- src/lib/splitView.test.ts src/lib/kiwiKeybindings.test.ts → 26 passed
go test ./internal/keybindings/... -count=1 → ok
go test ./internal/workspace/... -count=1 → ok
```

## Fleet handoff

- Branch: `feat/issue-426-split-view`
- Do not push from Cursor; fleet publishes PR closing #426
- Fix doc updated at `pages/fixes/kiwifs-kiwifs/issue-426-split-side-by-side-page-view.md`
37 changes: 25 additions & 12 deletions internal/keybindings/keybindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ var knownActions = map[string]struct{}{
"undo": {},
"focus_tree_filter": {},
"close_overlay": {},
"toggle_split_view": {},
}

// DefaultBindings are used when no config overrides are present.
Expand All @@ -43,6 +44,7 @@ var DefaultBindings = map[string]string{
"undo": "Mod+Z",
"focus_tree_filter": "Mod+Alt+F",
"close_overlay": "Escape",
"toggle_split_view": "Mod+\\",
}

// Conflict describes two or more actions bound to the same chord.
Expand Down Expand Up @@ -119,20 +121,31 @@ func NormalizeChord(chord string) (string, error) {
return strings.Join(out, "+"), nil
}

// keyAliases maps common key names (already lowercased) to canonical tokens.
var keyAliases = map[string]string{
"esc": "escape",
"escape": "escape",
"slash": "/",
"/": "/",
"question": "?",
"?": "?",
"backslash": "\\",
"\\": "\\",
"enter": "enter",
"return": "enter",
"tab": "tab",
"space": "space",
" ": "space",
"del": "delete",
"delete": "delete",
"backspace": "backspace",
}

func normalizeKey(key string) string {
switch key {
case "esc", "escape":
return "escape"
case "slash", "/":
return "/"
case "question", "?":
return "?"
default:
if len(key) == 1 {
return key
}
return key
if canonical, ok := keyAliases[key]; ok {
return canonical
}
return key
}

func appendUnique(list []string, item string) []string {
Expand Down
27 changes: 27 additions & 0 deletions internal/keybindings/keybindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,29 @@ import (
"testing"
)

func TestNormalizeKey(t *testing.T) {
tests := []struct {
in string
want string
}{
{"escape", "escape"},
{"esc", "escape"},
{"\\", "\\"},
{"backslash", "\\"},
{"enter", "enter"},
{"return", "enter"},
{"tab", "tab"},
{"k", "k"},
{"f1", "f1"},
}
for _, tc := range tests {
got := normalizeKey(tc.in)
if got != tc.want {
t.Fatalf("normalizeKey(%q) = %q, want %q", tc.in, got, tc.want)
}
}
}

func TestNormalizeChord(t *testing.T) {
tests := []struct {
in string
Expand All @@ -17,6 +40,7 @@ func TestNormalizeChord(t *testing.T) {
{"Escape", "escape"},
{"Ctrl+/", "mod+/"},
{"Mod+?", "mod+?"},
{"Mod+\\", "mod+\\"},
}
for _, tc := range tests {
got, err := NormalizeChord(tc.in)
Expand All @@ -38,6 +62,9 @@ func TestResolveDefaultsWhenMissing(t *testing.T) {
if res.Bindings["search"] != "mod+k" {
t.Fatalf("search = %q, want mod+k", res.Bindings["search"])
}
if res.Bindings["toggle_split_view"] != "mod+\\" {
t.Fatalf("toggle_split_view = %q, want mod+\\", res.Bindings["toggle_split_view"])
}
if len(res.Conflicts) != 0 {
t.Fatalf("expected no conflicts, got %+v", res.Conflicts)
}
Expand Down
Loading
Loading