From 3519995f428d778e1dc8fd82bd429bc119d4f9df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:55:14 +0100 Subject: [PATCH 1/2] =?UTF-8?q?feat(server,scripts):=20local-first=20polis?= =?UTF-8?q?h=20=E2=80=94=20magic-link=20gating,=20task-use=20bug,=20no=5Fu?= =?UTF-8?q?ser=5Fyet=20route?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five small gaps from the post-passkey audit, bundled per @burak's request to ship together. Server changes: 1. auth/config.ts: magic-link is now hidden when RESEND_API_KEY is unset, regardless of NODE_ENV. Previously `magicLink: hasValue(RESEND_API_KEY) || !isProduction` rendered the "Send me a magic link" button in dev — clicking it logged the URL to server stdout but didn't email anything. Operators staring at their inbox never found it. Now `magicLink: hasValue(env.RESEND_API_KEY)` — visible exactly when delivery actually works. 2. auth/routes.ts /api/local-init: the no_user_yet response's signup_url was "/sign-up", but Owletto's SPA routes signup via /auth/sign-up (the /auth/$pathname.tsx shim → /auth/login?intent=sign-up). Bare /sign-up fell into the $owner catch-all and looped through the login redirect. Codex caught this on the polish PR's review. Fixed to "/auth/sign-up". Scripts: 3. task-use.sh: same $script_dir/.. bug fixed in task-setup.sh by PR #900. Without it, running task-use from inside a worktree retargets the chrome/mac symlinks at nested paths inside the calling worktree instead of the main checkout. Fix is the identical one-liner: `git rev-parse --path-format=absolute --git-common-dir`. Submodule bump: 4. packages/owletto → 19221e9 (lobu-ai/owletto#191): - login.tsx branches copy on singleUserMode + auto-enrolls a passkey after first signup. - AppState.swift handles no_user_yet by opening the browser at the signup URL (using URL APIs, not string concat). Verified: - make typecheck clean - bun test packages/server/src/__tests__/unit — 201 pass - xcodebuild Owletto Debug — BUILD SUCCEEDED - Codex reviewed; caught the /sign-up route mismatch + unsafe URL concat; both fixed before push. --- packages/owletto | 2 +- packages/server/src/auth/config.ts | 9 ++++++++- packages/server/src/auth/routes.ts | 6 +++++- scripts/task-use.sh | 10 +++++++++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/owletto b/packages/owletto index d5ae2a44d..19221e9cd 160000 --- a/packages/owletto +++ b/packages/owletto @@ -1 +1 @@ -Subproject commit d5ae2a44d5e7f19ec6c04f646f2c75fcbfa76949 +Subproject commit 19221e9cd07946eff881e1916b18b6a83e988bb5 diff --git a/packages/server/src/auth/config.ts b/packages/server/src/auth/config.ts index 81b1d8b49..4216f04ff 100644 --- a/packages/server/src/auth/config.ts +++ b/packages/server/src/auth/config.ts @@ -403,7 +403,14 @@ export async function getAuthConfig( } } - const magicLink = hasValue(env.RESEND_API_KEY) || !isProduction; + // Magic-link requires actual email delivery. Without RESEND_API_KEY, + // Better Auth's plugin logs the magic URL to server stdout instead of + // emailing it — useful for debugging, useless to a real operator who's + // staring at their inbox. Hide the "Send me a magic link" affordance + // when delivery isn't configured. (Previously this also returned true + // in non-production, which made local dev render a dead button that + // appears to work then silently does nothing.) + const magicLink = hasValue(env.RESEND_API_KEY); const phone = hasValue(env.TWILIO_SID) && hasValue(env.TWILIO_TOKEN) && hasValue(env.TWILIO_WHATSAPP_NUMBER); const hasProviderAuthEnabled = Object.values(social).some(Boolean) || phone; diff --git a/packages/server/src/auth/routes.ts b/packages/server/src/auth/routes.ts index 2296b1695..3dc21d0df 100644 --- a/packages/server/src/auth/routes.ts +++ b/packages/server/src/auth/routes.ts @@ -434,7 +434,11 @@ credentialRoutes.post('/local-init', async (c) => { error: 'no_user_yet', error_description: 'No user exists yet on this install. Open the web UI and sign up first; the menubar / CLI will pick up the new user on the next /api/local-init call.', - signup_url: '/sign-up', + // Owletto's SPA routes signup via /auth/sign-up (mapped by + // auth/$pathname.tsx → /auth/login?intent=sign-up). A bare /sign-up + // would fall into the $owner catch-all and loop through the login + // redirect — pre-PR-908 codex review caught this. + signup_url: '/auth/sign-up', }, 404 ); diff --git a/scripts/task-use.sh b/scripts/task-use.sh index 38e9adbde..43cfce950 100755 --- a/scripts/task-use.sh +++ b/scripts/task-use.sh @@ -31,7 +31,15 @@ if [[ "$name" != "main" ]] && ! [[ "$name" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then fi script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -repo="$(cd "$script_dir/.." && pwd)" +# Resolve `repo` to the main checkout, not whatever worktree the script +# happens to live inside. Worktrees share the working tree (scripts/ +# included), so a naive `$script_dir/..` returns the calling worktree's +# root — and task-use would retarget the active/chrome + active/mac +# symlinks at `/.claude/worktrees//packages/...`, +# nested inside whatever worktree the operator happened to be in. Same +# fix as task-setup.sh (#899/#900): use git's shared .git path with +# --path-format=absolute so the resolution is invariant to cwd. +repo="$(dirname "$(git -C "$script_dir" rev-parse --path-format=absolute --git-common-dir)")" if [[ "$name" == "main" ]]; then source_root="$repo" From bcdb488bf966add8fc297f15f898b301b19a64f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Emre=20Kabakc=C4=B1?= Date: Tue, 19 May 2026 04:56:13 +0100 Subject: [PATCH 2/2] chore(submodule): bump owletto to 2b74ac24ca3a98ac5193cfd0b7f106e6fcded0ce (polish merged) --- packages/owletto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/owletto b/packages/owletto index 19221e9cd..2b74ac24c 160000 --- a/packages/owletto +++ b/packages/owletto @@ -1 +1 @@ -Subproject commit 19221e9cd07946eff881e1916b18b6a83e988bb5 +Subproject commit 2b74ac24ca3a98ac5193cfd0b7f106e6fcded0ce