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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ release-please owns it: land conventional commits on `main`, merge the generated
- **After changes run `make review`** (typecheck/unit/integration + pi verdict; posts a PR comment). Build per change: landing → `cd packages/landing && bun run build`; `{core,server,agent-worker,cli}` → `make build-packages`; broad → `bun run typecheck` (`make dev` doesn't rebuild workspace pkgs).
- **E2E before merge (hard gate)** for bug fixes: red→fix→green reproducer in the PR body; if you can't reproduce, BAIL (post the dead-end, don't open a PR). Native-app UI exempt (compile-check + draft, say so).
- Bot behavior → `./scripts/test-bot.sh "@me ..."` (dev `@clawdotfreebot`, prod `@lobuaibot`; clear stale history via `chat_state_lists`). Prompt/behavior → promptfoo (`bun run evals`). Auth'd UI → `docs/BROWSER_TESTING.md`.
- **Owletto e2e (Chrome/Mac):** Chrome → `make e2e-browser` launches/reuses the stable `owletto` agent-browser harness (persistent `~/.config/lobu-dev/chrome` profile + `--extension` from this worktree); drive it with `agent-browser --session owletto <cmd>`, `RESTART=1` to pick up extension/worktree changes. The extension's fixed manifest `key` pins its ID, so chrome.storage.local (gateway URL + auth) persists — pair once, reuse across sessions/worktrees, like the installed Mac app. Mac → use the installed `Owletto.app`; it reads `~/.config/lobu/config.json` each popover so task-setup-registered worktree contexts appear in its picker. Don't reintroduce a per-worktree extension symlink.
- `.env` is the single source of truth for secrets (restart `make dev` after changes). Worker sessions persist via `./workspaces/{agentId}/`. Skills declare network/nix needs that merge into the allowlist — review skills before installing; destructive MCP calls need in-thread approval unless pre-approved in `lobu.toml`.
12 changes: 7 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Development Makefile for Lobu

.PHONY: help setup build test clean dev build-packages ensure-submodule clean-workers test-unit test-integration test-e2e typecheck task-setup task-clean task-use bump review
.PHONY: help setup build test clean dev build-packages ensure-submodule clean-workers test-unit test-integration test-e2e typecheck task-setup task-clean e2e-browser bump review

# Default target
help:
Expand All @@ -16,7 +16,7 @@ help:
@echo " make typecheck - Strict typecheck (same as Dockerfile) for server + owletto"
@echo " make task-setup NAME=<name> - Create a paired worktree at .claude/worktrees/<name> (lobu + submodule on real branch, .env copied, ports auto-assigned, Lobu context registered)"
@echo " make task-clean NAME=<name> [FORCE=1] - Remove the worktree, both branches, and the Lobu context (refuses if there's uncommitted/unpushed work unless FORCE=1)"
@echo " make task-use NAME=<name|main> - Point Chrome ext / Mac app symlinks at this worktree (or 'main' for the canonical checkout)"
@echo " make e2e-browser [RESTART=1] - Launch/reuse the stable 'owletto' Chrome harness (extension from this worktree) for Chrome e2e"
@echo " make bump SUBMODULE=<path> [TARGET=<ref>] - Lightweight worktree + commit + PR for a trivial submodule pointer bump (skips bun install, .env, ports)"
@echo " make review [BASE=<branch>] - Run local review (typecheck+unit+integration + pi); posts pi-review status and PR comment"

Expand Down Expand Up @@ -89,9 +89,11 @@ task-clean:
@: $${NAME?Usage: make task-clean NAME=<name> [FORCE=1]}
@./scripts/task-clean.sh "$(NAME)" $$( [ "$(FORCE)" = "1" ] && echo --force )

task-use:
@: $${NAME?Usage: make task-use NAME=<name|main>}
@./scripts/task-use.sh "$(NAME)"
# Stable Owletto Chrome harness for e2e: one persistent profile, paired once,
# reused from any agent session (mirrors the installed Mac app). Loads the
# extension from the current worktree; RESTART=1 forces a fresh launch.
e2e-browser:
@./scripts/e2e-browser.sh $$( [ "$(RESTART)" = "1" ] && echo --restart )

# Lightweight shortcut for "trivial submodule pointer bump" work. Creates a
# minimal worktree (no bun install, no .env copy, no port allocation), advances
Expand Down
95 changes: 95 additions & 0 deletions scripts/e2e-browser.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bash
# e2e-browser.sh — launch (or reuse) the stable Owletto Chrome harness for e2e.
#
# Mirrors the Mac-app model: one persistent browser profile, paired once,
# reused from every agent session. The extension's fixed manifest "key" pins
# its ID regardless of where it's loaded from, so the extension's
# chrome.storage.local (gateway URL + access/refresh tokens + workerId) lives
# in the --profile dir and survives restarts — and carries across worktrees,
# because the ID never changes. So you pair once and reuse forever, exactly
# like installing Owletto.app once.
#
# Usage:
# scripts/e2e-browser.sh # extension = current worktree, open its gateway
# scripts/e2e-browser.sh --restart # force a fresh launch (pick up extension edits or a new worktree)
# make e2e-browser # same, from a worktree root
#
# Stable handles — reuse these verbatim from any agent session:
# profile ~/.config/lobu-dev/chrome (--profile: persists pairing/cookies/storage)
# session owletto (--session: the daemon-managed browser)
#
# Drive it after launch:
# agent-browser --session owletto snapshot -i # refs for click/fill
# agent-browser --session owletto open <url> # navigate
# agent-browser --session owletto close # shut it down
#
# The headed window may close when left idle, but the daemon keeps the
# session's launch config: the next `agent-browser --session owletto <cmd>`
# (or re-running this script) revives the browser WITH the extension. So a
# vanished window is not a re-pair — just poke the session.
#
# After editing extension source, reload it (chrome://extensions -> reload) or
# re-run with --restart (the --extension flag only applies at browser launch).
# Mac e2e needs no equivalent: the installed Owletto.app reads
# ~/.config/lobu/config.json on every popover, so worktree Lobu contexts
# registered by task-setup show up in its picker automatically.

set -euo pipefail

restart=0
[[ "${1:-}" == "--restart" ]] && restart=1

command -v agent-browser >/dev/null 2>&1 || {
echo "error: agent-browser not on PATH (npm i -g agent-browser, or brew install agent-browser)" >&2
exit 1
}

source_root="$(git rev-parse --show-toplevel)"
ext="$source_root/packages/owletto/apps/chrome"
[[ -d "$ext" ]] || { echo "error: no extension source at $ext" >&2; exit 1; }

# Gateway URL = this worktree's PORT (.env.local), defaulting to the canonical 8787.
port=8787
if [[ -f "$source_root/.env.local" ]]; then
p="$(awk -F= '/^PORT=/{print $2; exit}' "$source_root/.env.local" | tr -d '[:space:]')"
[[ -n "$p" ]] && port="$p"
fi
url="http://localhost:$port"

profile="$HOME/.config/lobu-dev/chrome"
session="owletto"
mkdir -p "$profile"

# Decide reuse vs (re)launch. A session can linger in the daemon's list after
# its browser window has died, so don't trust `session list` alone — probe the
# actual browser with a gateway-independent navigation (about:blank succeeds
# even when `make dev` is down). RESTART=1 always relaunches.
relaunch=1
if [[ $restart -eq 0 ]] \
&& agent-browser session list 2>/dev/null | grep -qE "^[[:space:]]*${session}$"; then
if agent-browser --session "$session" open "about:blank" >/dev/null 2>&1; then
relaunch=0
else
echo "-> '$session' session was stale (browser gone); relaunching"
agent-browser --session "$session" close >/dev/null 2>&1 || true
fi
elif [[ $restart -eq 1 ]]; then
agent-browser --session "$session" close >/dev/null 2>&1 || true
fi

if [[ $relaunch -eq 0 ]]; then
echo "-> reusing running '$session' session"
echo " (use --restart to reload the extension after source/worktree changes)"
# Non-fatal: a down gateway shouldn't fail the harness — the browser is up.
agent-browser --session "$session" open "$url" >/dev/null 2>&1 || true
else
agent-browser --session "$session" --profile "$profile" --extension "$ext" --headed open "$url" >/dev/null 2>&1 || true
echo "-> launched '$session'"
Comment on lines +74 to +75
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not swallow browser launch failures on the main launch path.

At Line 74, || true masks startup failures, but Lines 80-84 still print success. This can mislead e2e runs into proceeding without a real harness.

Proposed fix
-  agent-browser --session "$session" --profile "$profile" --extension "$ext" --headed open "$url" >/dev/null 2>&1 || true
+  if ! agent-browser --session "$session" --profile "$profile" --extension "$ext" --headed open "$url" >/dev/null 2>&1; then
+    echo "error: failed to launch '$session' with extension/profile" >&2
+    exit 1
+  fi
   echo "-> launched '$session'"
   echo "   profile:   $profile"
   echo "   extension: $ext"
 fi

Also applies to: 80-84

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/e2e-browser.sh` around lines 74 - 75, The agent-browser launch is
currently masked by "|| true", hiding failures; remove the "|| true" from the
agent-browser invocation and instead capture its exit status (e.g., check $? or
use set -e) so failures cause the script to fail or be handled explicitly; only
print the success message ("-> launched '$session'") when the agent-browser
command actually succeeded, and apply the same fix to the similar launch block
around lines 80-84 to avoid misleading success output.

echo " profile: $profile"
echo " extension: $ext"
fi

echo "OK Owletto e2e browser ready"
echo " gateway: $url"
echo " sidepanel: set 'Server URL' to $url the first time you pair against this worktree"
echo " drive it: agent-browser --session $session snapshot -i"
10 changes: 1 addition & 9 deletions scripts/task-clean.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fi

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Resolve `repo` to the main checkout, not whatever worktree the script
# happens to live inside. Same fix as task-setup.sh (#900) / task-use.sh
# happens to live inside. Same fix as task-setup.sh (#900) —
# `--git-common-dir --path-format=absolute` returns the shared .git path
# regardless of which worktree the call is made from, so invoking
# `make task-clean` from inside a worktree targets the right paths.
Expand Down Expand Up @@ -126,12 +126,4 @@ else
echo "warning: 'lobu' CLI not on PATH; skipping context removal" >&2
fi

# If this worktree was the active target for the Chrome symlink, fall back
# to 'main' so the active/chrome symlink doesn't dangle into a deleted dir.
active_name_file="$HOME/.config/lobu-dev/active/.active-name"
if [[ -f "$active_name_file" ]] && [[ "$(cat "$active_name_file")" == "$name" ]]; then
"$repo/scripts/task-use.sh" main >/dev/null && \
echo "→ active worktree was '$name'; reset to 'main'"
fi

echo "✓ cleaned up task '$name'"
4 changes: 0 additions & 4 deletions scripts/task-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,6 @@ echo "→ .env.local: PORT=$port WORKER_PROXY_PORT=$proxy"

echo "$name" > "$worktree_dir/.task"

# Auto-activate this worktree for the Chrome extension / Mac app (symlink swap).
# Safe / idempotent — task-use.sh re-points existing symlinks each time.
"$repo/scripts/task-use.sh" "$name" || true

# Register the worktree as a Lobu CLI context so the Mac menubar can spawn
# `lobu run` for it (lifecycle: managed) against the worktree's source. Safe to
# re-run — `lobu context add` overwrites the existing entry. Non-fatal: the
Expand Down
104 changes: 0 additions & 104 deletions scripts/task-use.sh

This file was deleted.

Loading