Skip to content
Merged
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
18 changes: 17 additions & 1 deletion .claude/agent-memory/code-reviewer/MEMORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,23 @@
- `window-resizing` class disables ALL layout transitions during native window resize
- `[data-resize-handle-active]` sibling/parent selector disables panel transitions during drag

## Cross-Component Event Bus Pattern

- `window.dispatchEvent(new CustomEvent("insert-to-chat", { detail }))` is the established
pattern for browser panel → chat input communication (both text and element insertion).
The listener lives in `MainLayout.tsx` useEffect with no deps (stable ref via `workspaceChatPanelRef`).
- Multi-tab (ChatArea with multiple SessionPanel tabs): only ONE SessionPanel tab is assigned the
ref at a time (last rendered wins via ref={workspaceChatPanelRef} directly on the component).
Element insertion always goes to the currently-active chat tab. Acceptable current limitation.

## XML Attribute Serialization Risk Pattern

- `serializeInspectElement` in `parseInspectTags.ts` embeds user-controlled string values (innerText,
path, tagName, reactComponent) into XML attribute values using double-quote delimiters with NO
escaping. A `"` in any of these fields breaks `attrRegex = /(\w+)="([^"]*)"/g` parsing and
corrupts the tag. Real DOM innerText can contain `"` (button labels, link text, etc.).
Fix pattern: HTML-escape values before embedding in attributes.

## Distribution / CI Patterns

- `sed -i ''` is macOS/BSD syntax. On ubuntu-latest (GNU sed), use `sed -i "..."` (no empty-string arg). Scripts that use `sed -i ''` WILL fail in CI.
Expand All @@ -39,7 +56,6 @@
- `tauri-action@v0` needs `includeUpdaterJson: true` (or it defaults true when updater is configured) — verify latest.json is uploaded as a release asset alongside the DMG.
- `workflow_dispatch` without a branch filter can tag + push from any branch; restrict by adding `branches: [main]` under `on.workflow_dispatch` or add a guard step.
- The app spawns system `node` binary (not bundled) — hardened runtime notarization may need `com.apple.security.cs.disable-library-validation` in Entitlements.plist if node's dylibs fail team-ID checks.

## Icon Component Patterns (New)

- `AppIcon` registry pattern: static `APP_ICON_MAP` record maps appId → icon component function
Expand Down
18 changes: 18 additions & 0 deletions .claude/agent-memory/deep-reviewer/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Deep Reviewer Memory

## Browser Automation Architecture
- Inject scripts live in `src/features/browser/automation/inject/` (TypeScript source)
- Compiled via esbuild to `dist-inject/` (IIFE format, gitignored)
- Consumer files import compiled output via Vite `?raw` imports
- Three independent scripts: `browser-utils` (`__hiveBrowserUtils`), `visual-effects` (`__hiveVisuals`), `inspect-mode` (`__hiveInspect`)
- Title-channel protocol uses `\x01` (SOH) prefix bytes -- verify hex dump, not text grep
- Build command: `bun run build:inject` (runs before dev/build)

## Common Patterns to Watch
- `waitForDomSettle` timer cleanup: ensure all timers are cleared on all exit paths
- Dead parameters: `slowly` in `buildTypeJs` is accepted but never used
- `data-hive-ref` is used for both tree snapshots and inspect mode element refs

## Review Infrastructure
- Reviews go to `.context/reviews/review-NN.md`
- First review was review-01 on 2026-02-21
3 changes: 3 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ jobs:
- name: Install dependencies
run: bun install --frozen-lockfile

- name: Build inject scripts
run: bun run build:inject

- name: Run sidecar unit tests
run: bun run test:sidecar:unit

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ src-tauri/target/
src-tauri/WixTools/
# Sidecar build artifact (built via `bun run build:sidecar`)
src-tauri/resources/bin/index.bundled.cjs
# Browser inject build artifacts (built via `bun run build:inject`)
src/features/browser/automation/dist-inject/

# Misc
.DS_Store
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
"packageManager": "bun@1.2.19",
"type": "module",
"scripts": {
"dev": "bun run build:sidecar && tauri dev",
"dev": "bun run build:inject && bun run build:sidecar && tauri dev",
"dev:web": "./scripts/dev.sh",
"dev:frontend": "vite",
"dev:backend": "node backend/server.cjs",
"build": "bun run build:sidecar && tsc && vite build",
"build:tauri": "bun run build:sidecar && tauri build",
"build": "bun run build:inject && bun run build:sidecar && tsc && vite build",
"build:tauri": "bun run build:inject && bun run build:sidecar && tauri build",
"build:inject": "bunx tsx src/features/browser/automation/build-inject.ts",
"build:sidecar": "bunx tsx sidecar/build.ts && bun install --frozen-lockfile --cwd packages/mcp-notebook && bunx tsx packages/mcp-notebook/build.ts",
"preview": "vite preview",
"tauri": "tauri",
Expand Down
6 changes: 6 additions & 0 deletions scripts/dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ if [ -n "$STALE_PID" ]; then
sleep 0.3
fi

# Build browser inject scripts (TypeScript → IIFE for WKWebView)
echo -e "${BLUE}Building browser inject scripts...${NC}"
bun run build:inject
echo -e "${GREEN}✓ Inject scripts built${NC}"
echo ""

# Start backend server with dynamic port
echo -e "${BLUE}Starting backend server with dynamic port...${NC}"
PORT=0 node backend/server.cjs > /tmp/backend.log 2>&1 &
Expand Down
2 changes: 1 addition & 1 deletion sidecar/agents/hive-tools/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { FrontendClient } from "../../frontend-client";
// Snapshot file-based fallback constants
// ============================================================================

// Two-tier thresholds matching Cursor's approach:
// Two-tier thresholds:
// - Action tools (click, type, hover, etc.): 25 KB — keeps context compact
// - Dedicated snapshot tool: 200 KB — user explicitly asked for a snapshot
const SNAPSHOT_SIZE_THRESHOLD = 25 * 1024; // 25 KB for action tools
Expand Down
17 changes: 6 additions & 11 deletions sidecar/test/browser-templates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { describe, it, expect } from "vitest";
// Import templates directly — they're pure functions with no platform deps
import {
SNAPSHOT_JS,
BROWSER_UTILS,
CONSOLE_MESSAGES_JS,
NETWORK_REQUESTS_JS,
buildClickJs,
Expand All @@ -38,10 +37,14 @@ import {
// Helpers
// ========================================================================

/** Check that a JS string is a self-invoking function expression */
/** Check that a JS string is a self-invoking function expression.
* Accepts both classic IIFEs `(function(){...})()` and arrow IIFEs
* `(() => {...})()` — esbuild's `format: "iife"` emits the latter. */
function assertIsIIFE(js: string, name: string) {
const trimmed = js.trim();
expect(trimmed, `${name} should start with (function`).toMatch(/^\(function\s*\(/);
// esbuild may prepend "use strict"; — strip it for the shape check
const body = trimmed.replace(/^"use strict";\s*/, "");
expect(body, `${name} should start with (function or (() =>`).toMatch(/^\((?:function\s*\(|(?:\(\)\s*=>))/);
expect(trimmed, `${name} should end with )()`).toMatch(/\)\(\)\s*;?\s*$/);
}

Expand Down Expand Up @@ -191,14 +194,6 @@ describe("browser-utils JS templates", () => {
assertHasReturnJson(buildPressKeyJs("Enter"), "buildPressKeyJs");
});

it("includes BROWSER_UTILS inside the IIFE", () => {
const js = buildPressKeyJs("Tab");
// BROWSER_UTILS should be inside the IIFE, not before it
const iifeStart = js.indexOf("(function(){");
const utilsStart = js.indexOf("buildPageSnapshot");
expect(iifeStart).toBeLessThan(utilsStart);
});

it("supports modifier keys", () => {
const js = buildPressKeyJs("a", { ctrl: true, shift: true });
expect(js).toContain("ctrlKey: true");
Expand Down
Loading