Skip to content

Based/new searchbar definition#876

Open
Khalzz wants to merge 7 commits into
trunkfrom
based/new_searchbar_definition
Open

Based/new searchbar definition#876
Khalzz wants to merge 7 commits into
trunkfrom
based/new_searchbar_definition

Conversation

@Khalzz

@Khalzz Khalzz commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Added new searchbar, connected to the harness allowing:

"Ask": Harness consults with responses on url and markdown format comming as ai responses.
"Navigate": As movement capabilities once refeering a keyword found on the pagefind
"Build": WIP

Summary by CodeRabbit

  • New Features

    • Added a new spotlight search experience in the app header with keyboard shortcuts, recent items, and improved navigation results.
    • Search now includes both site pages and harness-backed results, with clearer result labels and loading/empty states.
    • Added support for richer markdown styling and smoother UI animations.
  • Bug Fixes

    • Search and asset paths now work correctly under the app’s base path.
    • Updated auth handling so API access tokens are available where needed.

@Khalzz Khalzz self-assigned this Jul 2, 2026
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Khalzz, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 38 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 057295c7-3f9a-4e37-ba22-a96c753b5494

📥 Commits

Reviewing files that changed from the base of the PR and between 866d7ab and 70bb02a.

📒 Files selected for processing (1)
  • turbo-repo/packages/miot-harness-client/src/types.ts
📝 Walkthrough

Walkthrough

This PR replaces the navbar search bar with a spotlight-style overlay combining Pagefind-indexed static navigation results and streamed MIOT harness AI answers. It adds a harness search API route, a build-time search-index generator, Auth0 access_token propagation through NextAuth, and a shared Markdown rendering utility.

Changes

Spotlight Search Feature

Layer / File(s) Summary
Harness search API and client types
src/app/api/harness/search/route.ts, packages/miot-harness-client/src/types.ts, package.json, .env.example
Adds a POST route authenticating, resolving harness org scope, streaming a MIOT harness run, and returning parsed answer blocks; extends UserRequest with answer_format/skill_id; adds the harness client dependency and env vars.
Search index build pipeline
scripts/build-search-index.mjs, src/types/pagefind.d.ts, .gitignore, package.json, next.config.mjs
Adds a script generating a Pagefind index from pages/translations, ambient Pagefind typings, build:search npm wiring, generated-output ignore rule, and a client-exposed NEXT_PUBLIC_BASE_PATH.
Spotlight presentational components
spotlight-search/spotlight-backdrop.tsx, spotlight-empty-state.tsx, spotlight-footer.tsx, spotlight-input.tsx, spotlight-result-item.tsx, spotlight-row.tsx, spotlight-results.tsx
Adds overlay backdrop, empty-state, footer, input, row, and results components rendering static and harness answer blocks with skeleton/typewriter effects.
Spotlight state, page registry, and data hooks
models/pages-config.json, models/pages.ts, spotlight-search/navigate-actions.ts, types.ts, use-harness-search.ts, use-pagefind-search.ts, use-spotlight-state.ts
Adds a config-driven page registry, navigation item builder, shared types, and hooks for harness fetching, Pagefind search with fuzzy fallback, and overlay state/keyboard/recents management.
Spotlight orchestrator and navbar wiring
spotlight-search/spotlight-search.tsx, secured-navbar.tsx, secured-layout.tsx, searchbar/search-bar.tsx, kbd-hint.tsx, navegation_params.ts
Adds the orchestrator combining prompt/harness/static results, wires it into the navbar replacing the old search form, hardcodes search enablement, and stubs the legacy SearchBar.
Spotlight localization and animations
src/lang/en.json, src/lang/es.json, src/app/globals.css
Adds spotlight i18n strings and new CSS keyframes/utility classes for icon and thinking animations.

Estimated code review effort: 4 (Complex) | ~60 minutes

Auth0 access_token propagation

Layer / File(s) Summary
Access token storage and dev route
src/auth.config.ts, src/app/api/dev/auth0/route.ts, .env.example
Persists Auth0 access_token into the JWT and session, updates it on refresh, and adds a dev-only route exposing token presence/values behind NODE_ENV/AUTH_DEV_EXPOSE_TOKENS gating.

Shared Markdown rendering utility

Layer / File(s) Summary
MarkdownContent utility and kpi-stat adoption
utils/markdown-components.tsx, kpi-stat/kpi-stat.tsx, package.json
Adds MarkdownContent using ReactMarkdown with remark-breaks, adds the dependency, and updates kpi-stat to use it instead of a local inline component map.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SpotlightSearch
  participant usePagefindSearch
  participant useHarnessSearch
  participant HarnessSearchRoute as "harness/search API"

  User->>SpotlightSearch: open overlay (Cmd/Ctrl+K)
  User->>SpotlightSearch: type query
  SpotlightSearch->>usePagefindSearch: query change
  usePagefindSearch-->>SpotlightSearch: static navigation results
  User->>SpotlightSearch: select "Ask Harness" prompt
  SpotlightSearch->>useHarnessSearch: committedQuery
  useHarnessSearch->>HarnessSearchRoute: POST { query }
  HarnessSearchRoute-->>useHarnessSearch: { results }
  useHarnessSearch-->>SpotlightSearch: harness items (blocks)
  SpotlightSearch-->>User: render markdown/goto answer rows
Loading

Possibly related PRs

  • microboxlabs/modulariot#8: Both PRs modify Auth0/NextAuth token handling in auth.config.ts (persisting/exposing access tokens).
  • microboxlabs/modulariot#103: Both PRs modify Auth0 JWT/session token handling in auth.config.ts, overlapping on the token refresh/session propagation flow.
  • microboxlabs/modulariot#334: Both PRs change the sidebar pages/SidebarItem model and related createAction typing that spotlight search's navigate items depend on.

Suggested labels: enhancement

Suggested reviewers: korutx, odtorres

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the search bar changes, but it is too vague and awkward to clearly describe the main update. Rename it to something specific, like "Add spotlight search bar with harness and Pagefind support".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch based/new_searchbar_definition

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Khalzz Khalzz requested a review from korutx July 2, 2026 21:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 16

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
turbo-repo/packages/miot-harness-client/src/types.ts (1)

11-18: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Remove the duplicate skill_id property turbo-repo/packages/miot-harness-client/src/types.ts:11-18UserRequest declares skill_id twice in the same interface body, which breaks TypeScript compilation. Keep the documented field and remove the earlier duplicate.

🤖 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 `@turbo-repo/packages/miot-harness-client/src/types.ts` around lines 11 - 18,
Remove the duplicate skill_id declaration in UserRequest so the interface only
defines it once. In types.ts, keep the documented skill_id field with the
SKILL.md guidance comment and delete the earlier duplicate property so the
TypeScript type compiles cleanly.
🧹 Nitpick comments (10)
turbo-repo/apps/app/src/features/common/utils/markdown-components.tsx (1)

33-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

No distinct styling for fenced code blocks vs inline code.

code applies the same inline-style background/padding regardless of whether it's inline code or a fenced block (no pre override), so multi-line code blocks won't get a bounded/scrollable container.

🤖 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 `@turbo-repo/apps/app/src/features/common/utils/markdown-components.tsx` around
lines 33 - 38, The markdown renderer’s `code` component in
`markdown-components.tsx` treats all code the same, so fenced blocks render with
inline styling instead of a proper block container. Update the markdown
component mapping to distinguish inline `code` from fenced code blocks, likely
by adding a `pre` override and/or checking the rendered element type from the
markdown library. Keep `code` for inline snippets only, and wrap multi-line
blocks in a scrollable/bounded container with block-friendly styles.
turbo-repo/apps/app/src/app/api/harness/search/route.ts (1)

53-55: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider capping query length before forwarding to the harness.

The raw query is sent to the harness message field with no upper bound, allowing arbitrarily long input to reach the LLM run and drive up cost/latency for a search box use case.

🤖 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 `@turbo-repo/apps/app/src/app/api/harness/search/route.ts` around lines 53 -
55, The search route forwards the raw query from route.ts straight into the
harness message with no length limit, so cap the input before building the
request. Update the query handling in the search route to trim and then truncate
or reject overly long values before they reach the harness call, keeping the
existing empty-query early return intact. Use the existing route logic around
the query variable and the harness request construction to apply the limit
consistently.
turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx (2)

169-176: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Harness go-to item ids can collide if the API ever returns multiple results.

i resets to 0 for each result in the flatMap, so harness-url-0 etc. would collide across multiple results. Currently benign since route.ts always returns a single-element results array, but worth making the id derivation result-scoped for robustness if that contract changes.

🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx`
around lines 169 - 176, The Harness go-to item IDs in spotlight-search are
derived from an index that resets for each result inside harnessGoToItems, so
multiple API results could generate duplicate ids. Update the id derivation in
spotlight-search.tsx to be result-scoped in the flatMap path, using a stable
unique prefix from each harness result together with the block index, and keep
the urlBlockToItem mapping unique even if harnessResults contains more than one
element.

257-262: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

No-op onKeyDown stub on a non-interactive <div> used only to gate onClick.

onKeyDown={() => {}} doesn't provide real keyboard equivalence for the onClick={stopPropagation} handler — it just satisfies a11y lint without functional keyboard support. Since this handler only guards against backdrop-close-on-click, consider moving stopPropagation to the parent <dialog> element (already a semantically valid container) instead of adding click semantics to a <div>.

🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx`
around lines 257 - 262, The non-interactive div in spotlight-search is using a
no-op onKeyDown just to satisfy accessibility lint, but it does not provide real
keyboard behavior for the click stopPropagation. Update the spotlight-search
component so the stopPropagation logic is handled on the parent dialog element
instead of on this div, and remove the fake onKeyDown/onClick semantics from the
div while preserving the backdrop-close behavior.

Source: Path instructions

turbo-repo/apps/app/next.config.mjs (1)

11-15: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Derive NEXT_PUBLIC_BASE_PATH from basePath instead of duplicating the literal.

Two independent "/app" literals can drift if basePath is ever updated.

♻️ Proposed fix
-  basePath: "/app",
-  env: {
-    // Expose basePath so client code can build asset URLs (e.g. /app/pagefind/pagefind.js)
-    NEXT_PUBLIC_BASE_PATH: "/app",
-  },
+  basePath: "/app",
+  env: {
+    // Expose basePath so client code can build asset URLs (e.g. /app/pagefind/pagefind.js)
+    NEXT_PUBLIC_BASE_PATH: "/app", // keep in sync with `basePath` above
+  },

Consider referencing a single shared constant if next.config.mjs supports importing one before both usages.

🤖 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 `@turbo-repo/apps/app/next.config.mjs` around lines 11 - 15, The
next.config.mjs settings duplicate the "/app" value in both basePath and
NEXT_PUBLIC_BASE_PATH, which can drift if one changes. Update the config so
NEXT_PUBLIC_BASE_PATH is derived from the same shared value used by basePath,
ideally via a single constant or import in next.config.mjs, and keep both the
config key and env assignment in sync.
turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/types.ts (1)

1-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

File naming and type source deviate from repo convention.

This file is named types.ts rather than the *.types.ts convention, and re-exports HarnessBlock from a server API route module instead of a colocated types file. Consider renaming to spotlight.types.ts and moving HarnessBlock into a shared type file (e.g. under src/types/ or this same file) that both the route and the client import from.

As per coding guidelines, "Colocate types as *.types.ts files; shared types in src/types/".

🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/types.ts`
around lines 1 - 24, The Spotlight search types are defined in a nonconforming
file name and the shared HarnessBlock type is imported from a server route
module. Rename this module to spotlight.types.ts and move HarnessBlock into a
colocated shared type source (either this file or src/types/) that both the
search route and SpotlightItem-related client code import from; keep
SpotlightResultKind and SpotlightItem in the shared types module and update all
imports to use the new location.

Source: Coding guidelines

turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts (1)

8-15: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Duplicate Pagefind type shapes vs. pagefind.d.ts.

PagefindInstance/PagefindResultData here duplicate the shapes already declared in src/types/pagefind.d.ts. Because PAGEFIND_PATH is typed as a generic string (to bypass static module resolution), the ambient declaration never actually applies to this import, so both files must be kept manually in sync. Consider exporting these interfaces from pagefind.d.ts (or a shared *.types.ts file) and importing them here, or dropping the now-dead ambient declaration.

🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts`
around lines 8 - 15, The Pagefind shape definitions are duplicated between
usePagefindSearch and the ambient pagefind.d.ts typing, so keep only one source
of truth. Move PagefindInstance and PagefindResultData into a shared exported
type location (preferably pagefind.d.ts or a common types file) and update
usePagefindSearch to import those symbols instead of redefining them, or remove
the unused ambient declaration if it is no longer needed.
turbo-repo/apps/app/src/types/pagefind.d.ts (1)

1-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Likely unused given the actual import path.

This ambient declaration only applies to the literal specifier "/pagefind/pagefind.js". use-pagefind-search.ts imports ${NEXT_PUBLIC_BASE_PATH}/pagefind/pagefind.js typed as a plain string specifically to bypass static resolution, so this type is never actually applied there, and a separate local interface is duplicated instead. See the paired comment in use-pagefind-search.ts for a consolidation suggestion.

🤖 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 `@turbo-repo/apps/app/src/types/pagefind.d.ts` around lines 1 - 17, The ambient
module declaration for pagefind is only matching a literal specifier and is not
being used by the dynamic import in use-pagefind-search.ts, which leads to
duplicated local types. Update the pagefind typing setup so the import in
use-pagefind-search.ts can reuse the shared PagefindResultData/PagefindResult
declarations from pagefind.d.ts, and remove the duplicated local interface there
while keeping the dynamic import pattern intact.
turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-input.tsx (1)

31-34: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

useLayoutEffect + setTimeout gains nothing over useEffect.

Since the focus call is deferred via setTimeout, it no longer runs synchronously before paint, so useLayoutEffect provides no benefit over useEffect here and only adds an SSR-mismatch warning risk in dev.

♻️ Suggested change
-  useLayoutEffect(() => {
+  useEffect(() => {
     const id = setTimeout(() => inputRef.current?.focus(), 60);
     return () => clearTimeout(id);
   }, []);
🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-input.tsx`
around lines 31 - 34, The delayed focus logic in spotlight-input’s effect
doesn’t need a layout effect because setTimeout already defers it past paint.
Replace useLayoutEffect with useEffect in the SpotlightInput component, keeping
the same inputRef focus and cleanup behavior, so the effect stays non-blocking
and avoids SSR mismatch warnings.
turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/search-bar.tsx (1)

1-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider deleting the file instead of stubbing it out.

Now that SearchBar always returns null and is unused (per secured-navbar.tsx), removing the file (and its now-dead sibling kbd-hint.tsx/navegation_params.ts if unused) is cleaner than keeping a no-op stub around.

🤖 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
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/search-bar.tsx`
around lines 1 - 3, Remove the no-op SearchBar stub instead of keeping a
component that always returns null, and update any imports/usage from
secured-navbar.tsx or related navbar code to stop referencing SearchBar. Also
check the sibling kbd-hint.tsx and navegation_params.ts files for dead
references and delete them too if they are no longer used, so the secured-navbar
feature only contains active code.
🤖 Prompt for all review comments with 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.

Inline comments:
In `@turbo-repo/apps/app/scripts/build-search-index.mjs`:
- Around line 48-58: The Pagefind records in build-search-index.mjs are tagged
with the wrong locale, causing a mismatch with the app’s Spanish UI set in the
layout. Update the indexing logic around index.addCustomRecord so the record
language matches the app locale (use es instead of en), or otherwise align the
generated index with a shared forceLanguage setting. Keep the change consistent
with the existing page.href, page.label, and meta fields so search results come
from the same locale as the app.

In `@turbo-repo/apps/app/src/app/api/dev/auth0/route.ts`:
- Around line 16-23: The debug response in the auth0 route is exposing raw
credentials by default; update the handler in the dev auth route to return only
non-sensitive flags/metadata unless an explicit local-only debug opt-in is
enabled. In the route’s response object, keep fields like email, hasAccessToken,
hasRawJWT, and hasTicket, but gate accessToken and rawJWT behind a stricter
check than NODE_ENV === "development" (for example, a dedicated opt-in flag or
local-only guard). Make sure the logic is contained in the auth0 route handler
so the default behavior never returns bearer tokens in shared dev deployments.

In `@turbo-repo/apps/app/src/app/api/harness/search/route.ts`:
- Around line 30-36: parseAnswerBlocks currently trusts JSON.parse output and
casts it to HarnessBlock[] without validating structure or URL safety, so add a
lightweight manual guard in parseAnswerBlocks to verify each parsed item has a
known HarnessBlock type and that any value.url only uses http:// or https://
before returning it. Keep malformed or unsafe entries from reaching
use-harness-search.ts and spotlight-search.tsx, where urlBlockToItem and
globalThis.open would otherwise consume the data unchecked.

In `@turbo-repo/apps/app/src/auth.config.ts`:
- Line 252: The token refresh logic in auth.config.ts leaves a stale bearer
token on the token object when the refresh response has no access_token, while
the expiry metadata is still updated. In the refresh handling block around the
token assignment, update the token state so that accessToken is cleared or
otherwise invalidated whenever tokens.access_token is missing, and keep the
existing tokens.access_token assignment path intact for the success case.
- Line 318: The session callback is copying the bearer token into session.user,
which makes it client-visible; remove the accessToken assignment from the
session object in auth.config.ts and keep the token only in the JWT. Update the
relevant session/JWT handling in the auth callbacks so any server-side consumers
read accessToken from the token path instead of session.user.
- Line 235: The refresh check in auth.config.ts is based only on time-to-expiry,
so it can miss tokens that are still far from expiry but already too old for the
harness. Update the refresh logic around shouldRefresh to also consider token
age from the issuance time (or equivalent timestamp available in the
token/session data), and refresh when either the token is near expiry or older
than the harness-safe age threshold. Use the existing auth refresh flow in this
block to keep the behavior consistent.

In `@turbo-repo/apps/app/src/features/common/utils/markdown-components.tsx`:
- Around line 15-20: The list renderers in markdown-components.tsx are
hardcoding text-sm on ul and ol, which overrides inherited sizing from callers
like DescriptionElement. Remove the fixed text size from the ul/ol components
and let them inherit font size so compact/scalable wrappers can control list
typography consistently. Keep the existing layout and spacing classes, and use
the ul/ol render functions as the place to adjust any list-specific styling
only.
- Around line 5-42: Type MARKDOWN_COMPONENTS with react-markdown’s exported
Components type instead of leaving it untyped, and remove any as never
suppression so prop mismatches are checked. Update each renderer (p, strong, em,
ul, ol, li, h1, h2, h3, hr, code, a) to use Readonly<ComponentProps<...> &
ExtraProps> or the matching react-markdown component prop shape so the component
signatures stay compatible and type-safe.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-backdrop.tsx`:
- Around line 20-29: The backdrop in SpotlightBackdrop is a non-interactive div
being used as a dismiss target via onClick, so update it to be
keyboard-accessible. Either switch the overlay in createPortal to a button-based
control, or add the required accessibility affordances on the backdrop element:
a proper role, tabIndex, and onKeyDown handling for Enter/Space to trigger
onClose. Keep the portal structure and children behavior unchanged.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-footer.tsx`:
- Around line 20-22: SpotlightFooter’s props are typed inline instead of using
the required read-only wrapper, so update the SpotlightFooter component
signature to wrap its props in Readonly just like the Key and Hint components in
this file. Keep the memo(function SpotlightFooter...) structure, but change the
parameter type so hasResults is declared through a Readonly<Props> style shape
to match the component prop convention.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-results.tsx`:
- Around line 173-182: The harness empty-state message in SpotlightResults is
hardcoded Spanish text and bypasses i18n. Update the `SpotlightResults`
component to render a passed-in `harnessEmptyLabel` prop instead of the literal
string, following the same pattern used for `recentLabel` and `navigateHeading`.
Then wire `harnessEmptyLabel` through the orchestrator from the i18n service so
the message comes from the locale files rather than being embedded in the
component.
- Around line 105-122: The Spotlight search result action in
spotlight-results.tsx opens an AI-provided URL directly, so update the
SpotlightRow item’s onSelect path to validate/sanitize block.value.url before
opening it. Use the existing harness-url mapping in the urlBlocks.map callback
to reject unsafe schemes like javascript: and only allow trusted http/https
destinations, then open the URL with window.open using noopener,noreferrer to
prevent reverse-tabnabbing and window.opener access.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx`:
- Around line 61-69: The `urlBlockToItem` handler opens harness-supplied URLs
with `globalThis.open(..., "_blank")` without `noopener,noreferrer` or scheme
validation. Update the `onSelect` logic in `urlBlockToItem` to only allow safe
URL schemes and open the target with explicit `noopener,noreferrer` behavior so
the new tab cannot access `window.opener`.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts`:
- Line 86: The cancellation guard in usePagefindSearch is shared across effect
reruns, so a newer search can reset cancelRef.current before an older
pagefind.search promise resolves. Replace the hook-level cancelRef with a
per-invocation local cancellation flag inside the effect, and have the cleanup
for that effect set that local flag so each search run in usePagefindSearch has
its own independent guard before calling setResults.
- Around line 25-37: The loadPagefind() helper caches a failed dynamic import
forever because loadPromise is never cleared when the import rejects, so
subsequent calls cannot retry. Update loadPagefind() so that a failed import
resets loadPromise (and leaves pagefindSingleton unset) before returning null,
while still caching only successful imports via pagefindSingleton. This change
should be made in the loadPagefind function used by the spotlight-search
Pagefind loader.

In `@turbo-repo/apps/app/src/features/layout/models/pages-searchable.json`:
- Around line 1-83: The search index is a duplicated, hand-edited copy of the
sidebar page model, so it can drift from the real access rules and hierarchy.
Update the generation flow that builds pages-searchable.json from the same
source used by pages.ts, instead of maintaining a separate static list. Make
sure the generated output preserves each page’s label, href, requiredGroups,
blockedGroups, and nested items recursively so the search index always matches
the sidebar.

---

Outside diff comments:
In `@turbo-repo/packages/miot-harness-client/src/types.ts`:
- Around line 11-18: Remove the duplicate skill_id declaration in UserRequest so
the interface only defines it once. In types.ts, keep the documented skill_id
field with the SKILL.md guidance comment and delete the earlier duplicate
property so the TypeScript type compiles cleanly.

---

Nitpick comments:
In `@turbo-repo/apps/app/next.config.mjs`:
- Around line 11-15: The next.config.mjs settings duplicate the "/app" value in
both basePath and NEXT_PUBLIC_BASE_PATH, which can drift if one changes. Update
the config so NEXT_PUBLIC_BASE_PATH is derived from the same shared value used
by basePath, ideally via a single constant or import in next.config.mjs, and
keep both the config key and env assignment in sync.

In `@turbo-repo/apps/app/src/app/api/harness/search/route.ts`:
- Around line 53-55: The search route forwards the raw query from route.ts
straight into the harness message with no length limit, so cap the input before
building the request. Update the query handling in the search route to trim and
then truncate or reject overly long values before they reach the harness call,
keeping the existing empty-query early return intact. Use the existing route
logic around the query variable and the harness request construction to apply
the limit consistently.

In `@turbo-repo/apps/app/src/features/common/utils/markdown-components.tsx`:
- Around line 33-38: The markdown renderer’s `code` component in
`markdown-components.tsx` treats all code the same, so fenced blocks render with
inline styling instead of a proper block container. Update the markdown
component mapping to distinguish inline `code` from fenced code blocks, likely
by adding a `pre` override and/or checking the rendered element type from the
markdown library. Keep `code` for inline snippets only, and wrap multi-line
blocks in a scrollable/bounded container with block-friendly styles.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/search-bar.tsx`:
- Around line 1-3: Remove the no-op SearchBar stub instead of keeping a
component that always returns null, and update any imports/usage from
secured-navbar.tsx or related navbar code to stop referencing SearchBar. Also
check the sibling kbd-hint.tsx and navegation_params.ts files for dead
references and delete them too if they are no longer used, so the secured-navbar
feature only contains active code.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-input.tsx`:
- Around line 31-34: The delayed focus logic in spotlight-input’s effect doesn’t
need a layout effect because setTimeout already defers it past paint. Replace
useLayoutEffect with useEffect in the SpotlightInput component, keeping the same
inputRef focus and cleanup behavior, so the effect stays non-blocking and avoids
SSR mismatch warnings.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx`:
- Around line 169-176: The Harness go-to item IDs in spotlight-search are
derived from an index that resets for each result inside harnessGoToItems, so
multiple API results could generate duplicate ids. Update the id derivation in
spotlight-search.tsx to be result-scoped in the flatMap path, using a stable
unique prefix from each harness result together with the block index, and keep
the urlBlockToItem mapping unique even if harnessResults contains more than one
element.
- Around line 257-262: The non-interactive div in spotlight-search is using a
no-op onKeyDown just to satisfy accessibility lint, but it does not provide real
keyboard behavior for the click stopPropagation. Update the spotlight-search
component so the stopPropagation logic is handled on the parent dialog element
instead of on this div, and remove the fake onKeyDown/onClick semantics from the
div while preserving the backdrop-close behavior.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/types.ts`:
- Around line 1-24: The Spotlight search types are defined in a nonconforming
file name and the shared HarnessBlock type is imported from a server route
module. Rename this module to spotlight.types.ts and move HarnessBlock into a
colocated shared type source (either this file or src/types/) that both the
search route and SpotlightItem-related client code import from; keep
SpotlightResultKind and SpotlightItem in the shared types module and update all
imports to use the new location.

In
`@turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts`:
- Around line 8-15: The Pagefind shape definitions are duplicated between
usePagefindSearch and the ambient pagefind.d.ts typing, so keep only one source
of truth. Move PagefindInstance and PagefindResultData into a shared exported
type location (preferably pagefind.d.ts or a common types file) and update
usePagefindSearch to import those symbols instead of redefining them, or remove
the unused ambient declaration if it is no longer needed.

In `@turbo-repo/apps/app/src/types/pagefind.d.ts`:
- Around line 1-17: The ambient module declaration for pagefind is only matching
a literal specifier and is not being used by the dynamic import in
use-pagefind-search.ts, which leads to duplicated local types. Update the
pagefind typing setup so the import in use-pagefind-search.ts can reuse the
shared PagefindResultData/PagefindResult declarations from pagefind.d.ts, and
remove the duplicated local interface there while keeping the dynamic import
pattern intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 55fb78a6-7399-4b52-ae10-51459a54c8ff

📥 Commits

Reviewing files that changed from the base of the PR and between 0d42082 and 613348f.

⛔ Files ignored due to path filters (1)
  • turbo-repo/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (34)
  • turbo-repo/apps/app/.env.example
  • turbo-repo/apps/app/.gitignore
  • turbo-repo/apps/app/next.config.mjs
  • turbo-repo/apps/app/package.json
  • turbo-repo/apps/app/scripts/build-search-index.mjs
  • turbo-repo/apps/app/src/app/api/dev/auth0/route.ts
  • turbo-repo/apps/app/src/app/api/harness/search/route.ts
  • turbo-repo/apps/app/src/app/globals.css
  • turbo-repo/apps/app/src/auth.config.ts
  • turbo-repo/apps/app/src/features/common/components/kpi-stat/kpi-stat.tsx
  • turbo-repo/apps/app/src/features/common/utils/markdown-components.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-layout.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/kbd-hint.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/navegation_params.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/search-bar.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/secured-navbar.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/navigate-actions.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-backdrop.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-empty-state.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-footer.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-input.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-result-item.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-results.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-row.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/types.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-harness-search.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-spotlight-state.ts
  • turbo-repo/apps/app/src/features/layout/models/pages-searchable.json
  • turbo-repo/apps/app/src/lang/en.json
  • turbo-repo/apps/app/src/lang/es.json
  • turbo-repo/apps/app/src/types/pagefind.d.ts
  • turbo-repo/packages/miot-harness-client/src/types.ts
💤 Files with no reviewable changes (1)
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/searchbar/navegation_params.ts

Comment thread turbo-repo/apps/app/scripts/build-search-index.mjs
Comment thread turbo-repo/apps/app/src/app/api/dev/auth0/route.ts
Comment thread turbo-repo/apps/app/src/app/api/harness/search/route.ts
Comment thread turbo-repo/apps/app/src/auth.config.ts Outdated
if (token.refreshToken && !account && !token.ticket) {
const expiresAt = Number(token.accessTokenExpiresAt ?? 0) * 1000;
const shouldRefresh = expiresAt - Date.now() < 5 * 60 * 1000; // 5 min before expiry
const shouldRefresh = expiresAt - Date.now() < 3 * 60 * 60 * 1000; // 3 h — harness rejects tokens older than ~4 h

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Refresh based on token age, not only time-to-expiry.

Line 235 says the harness rejects tokens older than ~4h, but this condition only refreshes near expiry. Any token lifetime over ~7h can become too old for harness while still being more than 3h from expiry.

🐛 Proposed fix
           token.rawJWT = account.id_token;
           token.accessToken = account.access_token;
           token.accessTokenExpiresAt = account.expires_at;
+          token.accessTokenIssuedAt = Math.floor(Date.now() / 1000);
           token.refreshToken = account.refresh_token;
           const expiresAt = Number(token.accessTokenExpiresAt ?? 0) * 1000;
-          const shouldRefresh = expiresAt - Date.now() < 3 * 60 * 60 * 1000; // 3 h — harness rejects tokens older than ~4 h
+          const now = Date.now();
+          const issuedAt = Number(token.accessTokenIssuedAt ?? 0) * 1000;
+          const isNearExpiry = expiresAt - now < 5 * 60 * 1000;
+          const isTooOldForHarness =
+            issuedAt === 0 || now - issuedAt > 3 * 60 * 60 * 1000;
+          const shouldRefresh = isNearExpiry || isTooOldForHarness;
               if (tokens.access_token) token.accessToken = tokens.access_token;
               token.accessTokenExpiresAt = Math.floor(Date.now() / 1000) + tokens.expires_in;
+              token.accessTokenIssuedAt = Math.floor(Date.now() / 1000);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const shouldRefresh = expiresAt - Date.now() < 3 * 60 * 60 * 1000; // 3 h — harness rejects tokens older than ~4 h
token.accessTokenIssuedAt = Math.floor(Date.now() / 1000);
const expiresAt = Number(token.accessTokenExpiresAt ?? 0) * 1000;
const now = Date.now();
const issuedAt = Number(token.accessTokenIssuedAt ?? 0) * 1000;
const isNearExpiry = expiresAt - now < 5 * 60 * 1000;
const isTooOldForHarness =
issuedAt === 0 || now - issuedAt > 3 * 60 * 60 * 1000;
const shouldRefresh = isNearExpiry || isTooOldForHarness;
token.accessTokenIssuedAt = Math.floor(Date.now() / 1000);
🤖 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 `@turbo-repo/apps/app/src/auth.config.ts` at line 235, The refresh check in
auth.config.ts is based only on time-to-expiry, so it can miss tokens that are
still far from expiry but already too old for the harness. Update the refresh
logic around shouldRefresh to also consider token age from the issuance time (or
equivalent timestamp available in the token/session data), and refresh when
either the token is near expiry or older than the harness-safe age threshold.
Use the existing auth refresh flow in this block to keep the behavior
consistent.

Comment thread turbo-repo/apps/app/src/auth.config.ts Outdated
Comment thread turbo-repo/apps/app/src/features/layout/models/pages-config.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
turbo-repo/apps/app/src/features/layout/models/pages.ts (1)

29-34: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Prefer satisfies over as to keep compile-time shape checking.

The trailing as SidebarItem[] silences structural mismatches between the JSON-derived shape and SidebarItem (e.g., a target string that isn't a valid HTMLAttributeAnchorTarget, or a missing required field) that would otherwise be caught by the compiler. As per coding guidelines: "Avoid any and unknown types; prefer type inference" and "Don't cast types when the type is already correct - avoid unnecessary type assertions."

♻️ Proposed refactor
-export const pages: SidebarItem[] = pagesConfig.map((p) => ({
+export const pages = pagesConfig.map((p) => ({
   ...p,
   icon: PAGE_ICONS[p.label],
   totals: {},
   items: (p.items ?? []).map((c) => ({ ...c, totals: {} })),
-})) as SidebarItem[];
+})) satisfies SidebarItem[];
🤖 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 `@turbo-repo/apps/app/src/features/layout/models/pages.ts` around lines 29 -
34, The `pages` mapping currently ends with a broad `as SidebarItem[]` cast,
which bypasses structural checks on the JSON-derived objects. Update the `pages`
export in `pages.ts` to use `satisfies SidebarItem[]` on the mapped result (or
an equivalent compile-time shape check) so `PAGE_ICONS`, `totals`, and each item
in the `map` path are validated without suppressing type errors. Keep the
`pagesConfig.map` and `items` transformation intact, but remove the unsafe
assertion so mismatches in `SidebarItem` are caught by the compiler.

Source: Path instructions

🤖 Prompt for all review comments with 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.

Nitpick comments:
In `@turbo-repo/apps/app/src/features/layout/models/pages.ts`:
- Around line 29-34: The `pages` mapping currently ends with a broad `as
SidebarItem[]` cast, which bypasses structural checks on the JSON-derived
objects. Update the `pages` export in `pages.ts` to use `satisfies
SidebarItem[]` on the mapped result (or an equivalent compile-time shape check)
so `PAGE_ICONS`, `totals`, and each item in the `map` path are validated without
suppressing type errors. Keep the `pagesConfig.map` and `items` transformation
intact, but remove the unsafe assertion so mismatches in `SidebarItem` are
caught by the compiler.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3bbaaf47-04d2-4043-a588-6328734b7ce6

📥 Commits

Reviewing files that changed from the base of the PR and between 613348f and 866d7ab.

📒 Files selected for processing (9)
  • turbo-repo/apps/app/scripts/build-search-index.mjs
  • turbo-repo/apps/app/src/app/api/dev/auth0/route.ts
  • turbo-repo/apps/app/src/app/api/harness/search/route.ts
  • turbo-repo/apps/app/src/auth.config.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-results.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts
  • turbo-repo/apps/app/src/features/layout/models/pages-config.json
  • turbo-repo/apps/app/src/features/layout/models/pages.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • turbo-repo/apps/app/src/app/api/harness/search/route.ts
  • turbo-repo/apps/app/scripts/build-search-index.mjs
  • turbo-repo/apps/app/src/app/api/dev/auth0/route.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/use-pagefind-search.ts
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-results.tsx
  • turbo-repo/apps/app/src/features/layout/components/secured-navbar/spotlight-search/spotlight-search.tsx

@sonarqubecloud

sonarqubecloud Bot commented Jul 3, 2026

Copy link
Copy Markdown

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

App preview image

The latest app preview image for this PR is ready.

  • Immutable image: ghcr.io/microboxlabs/miot-app@sha256:cf5bdc8474dc563fdc8c4284df48a4fdb4f603cab90dfcfd938cdf0eebe65980
  • Moving tag: ghcr.io/microboxlabs/miot-app:pr-876
  • SHA tag: ghcr.io/microboxlabs/miot-app:pr-876-sha-70bb02a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant