New mjs#344
Conversation
- Updated global CSS to introduce a new color palette and enhanced styles for various elements. - Modified layout to utilize new font imports and improved structure for better responsiveness. - Revamped the Hero component with animated backgrounds and a more engaging design. - Enhanced the Services component to display offerings in a more structured format with code-like presentation. - Updated the Header component for better navigation and visual consistency. - Adjusted the Portfolio component to include new project details and improved layout. These changes aim to enhance the overall user experience and visual appeal of the application.
- Introduced the AgentTerminal component in the Hero section for enhanced interactivity. - Adjusted layout styles in the Hero component for improved visual structure and responsiveness. - Updated next.config.mjs to include outputFileTracingIncludes for API content. These changes aim to enrich user engagement and streamline the component structure.
- Introduced a friendly error handling function in the agent API to provide user-friendly messages based on different error scenarios. - Updated the AgentTerminal component to include an Escape key functionality for aborting ongoing processes. - Added a ThinkingIndicator component to visually represent the agent's processing state with animated feedback. - Improved input validation in the agent API to ensure the last message is from the user. These changes aim to improve user interaction and provide clearer feedback during agent operations.
- Updated the AgentTerminal component to improve layout responsiveness and structure. - Enhanced the Hero component with a more flexible layout and removed unnecessary elements for a cleaner design. - Adjusted styles to ensure better visual consistency across components. These changes aim to enhance user experience and improve the overall aesthetic of the application.
- Implemented a custom hook for speech recognition, allowing users to interact with the terminal via voice commands. - Added a toggle button for starting and stopping speech recognition, enhancing user experience. - Updated input placeholder to reflect listening state, improving feedback during voice input. These changes aim to enrich user interaction and provide a more accessible way to engage with the AgentTerminal.
- Added a new breeze-wallpaper class to global CSS for a visually appealing background. - Removed the Header component from the layout for a cleaner structure. - Updated the main page layout to include KdeWindow components for Portfolio, Services, and Contact sections, improving organization and interactivity. - Refined the Hero component layout and styles for better responsiveness and visual consistency. These changes aim to improve the overall user experience and aesthetic of the application.
- Modified the className of the KdeWindow component to include max-width and margin properties, enhancing its layout and ensuring better responsiveness across different screen sizes. These changes aim to improve the overall user experience and visual consistency of the application.
- Replaced KdeWindow with BrowserWindow for the Portfolio section, improving the layout and interactivity. - Updated ProjectCard styles for a more modern appearance and better user experience. - Adjusted header spacing in the Portfolio component for improved visual consistency. These changes aim to enhance the overall user experience and aesthetic of the application.
- Replaced individual section components with a unified DesktopShell component for improved organization and readability. - Updated the Hero component to include the AgentTerminal, enhancing interactivity and user engagement. - Refined KdePanel to support dynamic navigation and mode switching, improving user experience. These changes aim to streamline the layout and enhance the overall functionality of the application.
- Introduced new TypeScript interfaces for speech recognition, enhancing type safety and clarity in the application. - Updated the next-env.d.ts file to reference the correct types for improved compatibility. - Wrapped the main page layout in a Suspense component to support lazy loading of components, improving performance and user experience. These changes aim to enhance the application's functionality and maintainability.
- Updated the contact section layout for improved responsiveness and visual appeal by consolidating styles and structure. - Enhanced markdown rendering in the AgentTerminal component to support inline links and email addresses, improving user interaction. - Adjusted type definitions in next-env.d.ts for better compatibility with development types. These changes aim to improve user experience and maintainability of the application.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughStreaming OpenRouter agent, SSE POST /api/agent with rate limits and tool-call loop; corpus of projects/jobs/resume with search; executeTool dispatcher; client AgentTerminal UI with speech I/O and TTS; new DesktopShell, window components, and site-wide midnight dark theme. ChangesAgent Terminal & Portfolio Website Redesign
sequenceDiagram
participant User
participant AgentTerminal
participant API_Agent as POST_/api/agent
participant OpenRouter
participant ToolExecutor as executeTool
participant Corpus
User->>AgentTerminal: submit message
AgentTerminal->>API_Agent: POST { messages }
API_Agent->>API_Agent: validate, sanitize, rate-limit
API_Agent->>OpenRouter: streaming POST (system + messages + models)
OpenRouter-->>API_Agent: stream data: text, tool_calls, usage, finish
loop tool rounds
API_Agent->>ToolExecutor: executeTool(toolCall)
ToolExecutor->>Corpus: list/read/search
Corpus-->>ToolExecutor: JSON result
ToolExecutor-->>API_Agent: tool_result
API_Agent->>OpenRouter: append tool result and continue
OpenRouter-->>API_Agent: more stream events
end
API_Agent-->>AgentTerminal: SSE events (text, tool_call, tool_result, usage, done/error)
AgentTerminal->>User: render streaming transcript and tool outputs
🎯 4 (Complex) | ⏱️ ~75 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (16)
apps/mikeallisonjs.com/src/lib/agent/projects.ts (1)
136-147: ⚡ Quick winQuick style pass: switch exported helpers to const arrows for repo consistency.
listProjectsandgetProjectare function declarations right now; convert them toconst ... = (...) =>to match project conventions.
As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/projects.ts` around lines 136 - 147, Convert the exported helpers listProjects and getProject from function declarations to const arrow functions for consistency: replace "export function listProjects() { ... }" with "export const listProjects = () => { ... }" and "export function getProject(slug: string): ProjectData | undefined { ... }" with "export const getProject = (slug: string): ProjectData | undefined => { ... }", preserving their implementations, return types, exports, and any existing references in the module.apps/mikeallisonjs.com/src/lib/agent/corpus.ts (2)
149-152: ⚡ Quick winSearch path does serial file reads and that’s gonna feel slow under load, buddy.
Lines 149–152 await each job read one-by-one. Batch with
Promise.allso corpus search latency doesn’t grow linearly with job count.Patch idea
const jobs = await listJobs() - for (const j of jobs) { - const record = await getJob(j.slug) + const jobRecords = await Promise.all(jobs.map((j) => getJob(j.slug))) + for (const [index, j] of jobs.entries()) { + const record = jobRecords[index] if (!record) continue const haystack = [j.company, j.role, record.body].join('\n').toLowerCase()🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/corpus.ts` around lines 149 - 152, The code currently awaits getJob serially over the jobs list (variable jobs from listJobs), causing linear latency; change the loop to fetch records concurrently by mapping jobs to getJob promises and awaiting Promise.all (e.g., const records = await Promise.all(jobs.map(j => getJob(j.slug)))), then filter out null/undefined records before continuing; update any logic that used the per-job record variable to iterate over the filtered records array instead.
19-107: ⚡ Quick winStyle consistency check: these TS helpers should be const arrow functions.
parseFrontmatter,readJobFile, and exported helpers are declared withfunction; repo convention asks for const arrows.
As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/corpus.ts` around lines 19 - 107, Convert the top-level function declarations to const arrow functions to match repo convention: change parseFrontmatter to "const parseFrontmatter = (raw: string): { data: Record<string, unknown>; body: string } => { ... }", change readJobFile to "const readJobFile = async (slug: string): Promise<JobRecord | null> => { ... }", and do the same for the exported helpers (listJobs, getJob, readResume and searchCorpus) so they become "export const listJobs = async (...) => { ... }", etc.; preserve all parameter and return type annotations, async keywords, and existing logic/returns when converting to arrow functions.apps/mikeallisonjs.com/src/components/desktop-shell.tsx (1)
14-24: ⚡ Quick winUse a const arrow declaration for
DesktopShell.Line 14 should be a const arrow component to match repo conventions.
As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/components/desktop-shell.tsx` around lines 14 - 24, Replace the function declaration DesktopShell with a const arrow component to match repo conventions: change "export function DesktopShell({ ... }: { ... }) { ... }" to an exported const arrow like "export const DesktopShell = ({ agent, portfolio, services, contact }: { agent: ReactNode; portfolio: ReactNode; services: ReactNode; contact: ReactNode }) => { ... }", preserving the same props names and types and keeping the implementation body intact.apps/mikeallisonjs.com/src/components/browser-window.tsx (2)
3-15: ⚡ Quick winConvert
BrowserWindowto a const arrow component.Line 3 is a function declaration; please switch to
const BrowserWindow = (...) => {}for consistency.As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/components/browser-window.tsx` around lines 3 - 15, The BrowserWindow component is declared with a function declaration; convert it to a const arrow component by replacing "export function BrowserWindow({...}) { ... }" with "export const BrowserWindow = ({...}) => { ... }" while preserving the same props (id, title, url, contentClassName, children) and exported name so external imports still work; ensure TypeScript typings remain attached to the parameter destructuring exactly as before.
22-27: ⚡ Quick winReplace inline
styleobjects with Tailwind utility classes.Lines 22-27 and 41-44 use inline styles; move these values into Tailwind classes/arbitrary values so styling stays in className land.
As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
Also applies to: 41-44
🤖 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 `@apps/mikeallisonjs.com/src/components/browser-window.tsx` around lines 22 - 27, The header/container div in the BrowserWindow component uses inline style for a vertical gradient and border-bottom; replace those inline style properties with Tailwind utility classes (use bg-[linear-gradient(...)] or bg-gradient-to-b with appropriate arbitrary color stops and use border-b/[1px] border-b-[`#2e3338`] for the bottom border) and remove the style prop from the element; do the same for the second inline-styled element referenced around the later block (lines 41-44) so all styling lives in className using Tailwind arbitrary values (e.g., bg-[linear-gradient(...)] and border-b-[`#2e3338`]) and keep existing utility classes like font-mono and px-2.5 untouched.apps/mikeallisonjs.com/src/components/kde-window.tsx (2)
3-11: ⚡ Quick winUse a const arrow declaration for
KdeWindow.Line 3 should follow the project pattern with
const KdeWindow = (...) =>.As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-window.tsx` around lines 3 - 11, The KdeWindow component is declared with a function declaration; change it to a const arrow function per project style by replacing "export function KdeWindow(...)" with an exported const arrow like "export const KdeWindow = (...) => { ... }", keeping the same props type annotation ({ id?: string; title: string; children: ReactNode }) and returning the same JSX; ensure any named export usage remains valid and update any tooling expectations (e.g., displayName) if your project relies on it.
20-23: ⚡ Quick winMove title-bar inline styles into Tailwind classes.
The inline
styleon Line 20 should be converted to Tailwind/arbitrary utilities to stay aligned with component styling rules.As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-window.tsx` around lines 20 - 23, The title-bar element in kde-window.tsx uses an inline style object for the gradient background and bottom border; replace that style prop with Tailwind classes (either the built-in gradient utilities like bg-gradient-to-b from-[`#3b4045`] to-[`#31363b`] and border-b border-[`#2e3338`] or an equivalent arbitrary bg-[linear-gradient(...)] utility) and move the classes onto the same element (the title bar in the KDEWindow component) via className so no inline style remains.apps/mikeallisonjs.com/src/components/kde-panel.tsx (2)
23-45: ⚡ Quick winUse const arrow components for
ClockandKdePanel.Lines 23 and 35 are function declarations; switch both to const-arrow style for consistency.
As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-panel.tsx` around lines 23 - 45, Replace the function declarations with const arrow components to follow the project's style guide: change the top-level "function Clock()" to "const Clock = () =>" and change "export function KdePanel(...)" to "export const KdePanel = ({...}) =>"; ensure you keep the existing props/type annotations, hooks (useState/useEffect), return JSX, and the export semantics intact so behavior doesn't change.
49-49: ⚡ Quick winSwap inline color styles for Tailwind classes/tokens.
The inline
styleprops here should be expressed in className utilities so the component stays fully Tailwind-driven.As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
Also applies to: 56-57
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-panel.tsx` at line 49, The inline style on the element in kde-panel.tsx (currently using style={{ background: '#1b1e20', borderBottom: '1px solid `#2d3136`' }}) should be replaced with equivalent Tailwind className utilities—use a bg-... token or a custom color token (e.g., bg-[theme-color] or bg-[`#1b1e20`] if necessary) and a border-b with the appropriate border color class (e.g., border-b border-[`#2d3136`] or a token like border-gray-700) on the same element; also update the other inline style occurrences referenced around the same component (lines ~56-57) to use Tailwind classes so the KDEPanel component (kde-panel.tsx) is fully Tailwind-driven.apps/mikeallisonjs.com/src/app/page.tsx (1)
12-12: ⚡ Quick winConvert
PageandContactSectionto const arrow functions.Lines 12 and 47 should use const-arrow declarations to stay in lockstep with the project pattern, champ.
As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
Also applies to: 47-47
🤖 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 `@apps/mikeallisonjs.com/src/app/page.tsx` at line 12, Replace the function declarations with const arrow functions: change "export default function Page()" to "const Page = () => { ... }" and then add "export default Page" (since "export default const" is invalid), and change "function ContactSection()" to "const ContactSection = () => { ... }"; preserve all internal logic/props/returns and update any local references if needed so the module still exports Page as default and uses ContactSection internally.apps/mikeallisonjs.com/src/app/layout.tsx (1)
29-33: ⚡ Quick winUse a const arrow for
RootLayoutdeclaration.Line 29 uses a function declaration; swap to a
const RootLayout = (...) =>to match project style, my dude.As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/app/layout.tsx` around lines 29 - 33, Replace the function declaration for RootLayout with a const arrow function to match project style: change the declaration of RootLayout (currently "export default function RootLayout({ children }: { children: React.ReactNode })") to a const arrow assigned to the same exported identifier (e.g., "const RootLayout = ({ children }: { children: React.ReactNode }) => { ... }" and keep the existing export default), ensuring the props type and returned JSX remain unchanged.apps/mikeallisonjs.com/src/lib/agent/openrouter.ts (2)
60-76: 💤 Low valueO-o-okay, Mister Helper Function Man — let's make this an arrow, alright?
Per the repo's coding guidelines, this should be a
constarrow. T-t-totally easy fix, no biggie.♻️ Proposed tweak
-function parseOpenRouterErrorBody(body: string): { - code?: number | string - message?: string -} { +const parseOpenRouterErrorBody = ( + body: string +): { code?: number | string; message?: string } => { if (!body) return {} ... return { message: body.slice(0, 300) } }As per coding guidelines: "Use const arrow functions instead of function declarations (e.g., 'const toggle = () =>')".
🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/openrouter.ts` around lines 60 - 76, The function parseOpenRouterErrorBody is a function declaration but must follow the coding guideline to be a const arrow; replace the declaration with a const arrow assigned to the same name (const parseOpenRouterErrorBody = (body: string): { code?: number | string; message?: string } => { ... }) keeping the exact logic and return types intact, preserve the JSON.parse try/catch and final return, and ensure exports/usage still reference parseOpenRouterErrorBody unchanged.
127-240: ⚡ Quick winT-T-Tommy boy, the reader's gettin' a little stuck in there — wrap it in try/finally, would ya?
The reader grabbed on line 127 never gets
releaseLock()'d (orcancel()'d) on the earlyreturnat line 153, thethrowat line 184, or any abort duringreader.read(). The response body keeps that lock until garbage collection clears it, which is sloppy hygiene on a hot streaming path. Stick atry/finallyaround the read loop so the lock is always let go.🧹 Suggested cleanup
const reader = res.body.getReader() const decoder = new TextDecoder() let buffer = '' const toolAcc = new Map<number, ToolCallAccumulator>() let textOut = '' let finishReason: string | null = null let usage: Usage | null = null - while (true) { - const { done, value } = await reader.read() - ... - } + try { + while (true) { + const { done, value } = await reader.read() + if (done) break + buffer += decoder.decode(value, { stream: true }) + ... + } + } finally { + reader.releaseLock() + }(You'll also want the
[DONE]early-returnand thethrow new OpenRouterError(...)mid-stream to flow through thatfinally.)🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/openrouter.ts` around lines 127 - 240, The stream reader obtained via res.body.getReader() in the async function (the reader/read loop starting at the const reader = res.body.getReader() and the while(true) reader.read() loop) must be wrapped in a try/finally so the reader.releaseLock() (or reader.cancel()) is always called on all exits (the early [DONE] return, the mid-stream throw where OpenRouterError is thrown, and any aborts during reader.read()); refactor by moving the read-loop into a try block and call reader.releaseLock() (or cancel) in the finally block so the lock is always released regardless of returns or exceptions.apps/mikeallisonjs.com/src/lib/agent/rate-limit.ts (1)
1-28: ⚡ Quick winWhoa, whoa, whoa — this bucket Map's gonna get real fat and it ain't even sharin' with the other servers.
Two friendly heads-ups on this little rate-limiter, T-Bone:
- Per-instance only. On Vercel/Next.js serverless (or any horizontally scaled deploy), each function instance keeps its own
bucketsMap. A determined visitor can blow way past 30/hour just by hitting different cold starts. If this needs to be real protection (and not just a polite speed bump for the happy path), back it with Redis/Upstash/KV.- Buckets never get evicted. Expired entries hang around in the Map forever — fine for a single short-lived instance, but a slow leak on a long-running one. Easy fix: drop expired keys on access (or sweep them).
🧹 Easy eviction-on-access tweak
const now = Date.now() const existing = buckets.get(key) if (!existing || existing.resetAt < now) { + if (existing) buckets.delete(key) const fresh: Bucket = { count: 1, resetAt: now + WINDOW_MS } buckets.set(key, fresh)(That alone doesn't bound growth across many unique keys — a periodic sweep would, but in serverless the instance churn usually wipes it for you.)
If single-instance is intentional and the 30/hour is just a soft guardrail, totally fine — maybe leave a comment to that effect for the next person to wander in.
🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/rate-limit.ts` around lines 1 - 28, The current in-memory buckets Map used by checkRateLimit (symbols: buckets, checkRateLimit, WINDOW_MS, LIMIT) is per-instance and never evicts expired entries; fix it by (1) making checkRateLimit remove an entry when existing.resetAt < now (delete from buckets before creating a fresh bucket) so expired keys are not retained, and (2) if you need cross-instance enforcement replace or back this Map with a shared store (Redis/Upstash/KV) rather than per-instance state; if per-instance soft-guard behavior is intentional, add a code comment near buckets explaining that limitation and why it's acceptable.apps/mikeallisonjs.com/src/components/agent-terminal.tsx (1)
454-459: ⚡ Quick winLet’s ditch the inline style here and keep it Tailwind-only.
This title bar styling is static, so it can live in classes instead of a
styleprop.Proposed refactor
- <div - className="relative flex h-[30px] shrink-0 items-center px-2.5 font-mono text-[11px]" - style={{ - background: 'linear-gradient(to bottom, `#3b4045` 0%, `#31363b` 100%)', - borderBottom: '1px solid `#2e3338`', - }} - > + <div className="relative flex h-[30px] shrink-0 items-center border-b border-[`#2e3338`] bg-[linear-gradient(to_bottom,`#3b4045_0`%,`#31363b_100`%)] px-2.5 font-mono text-[11px]">As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
🤖 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 `@apps/mikeallisonjs.com/src/components/agent-terminal.tsx` around lines 454 - 459, The title bar div in the AgentTerminal component uses an inline style prop for the background gradient and border-bottom; remove the style prop and add equivalent Tailwind classes to the existing className (keep "relative flex h-[30px] shrink-0 items-center px-2.5 font-mono text-[11px]"). Specifically, add bg-gradient-to-b from-[`#3b4045`] to-[`#31363b`] and border-b border-[`#2e3338`] to the className so the gradient and border are expressed with Tailwind instead of inline style.
🤖 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 `@apps/mikeallisonjs.com/content/jobs/agilix.md`:
- Line 13: The job entry contains placeholder text (e.g., the string
"Placeholder — replace with the real story." and other occurrences of the word
"replace") in the Agilix job markdown; replace these placeholder phrases with
the finalized job description and accurate work-history content so the agent
won't return filler responses, ensuring all instances of "replace" in that
Agilix entry are updated to the final copy.
In `@apps/mikeallisonjs.com/content/jobs/jesusfilm.md`:
- Line 13: Replace the literal placeholder text "Placeholder — replace with the
real story. Keep the wins concrete." in the jesusfilm content with a finalized
narrative paragraph that describes the real story and concrete wins (no
placeholder wording), remove the placeholder line entirely, and commit the
updated markdown so the knowledge base/build no longer contains the placeholder
string.
In `@apps/mikeallisonjs.com/content/resume.md`:
- Around line 14-16: The resume.md still contains placeholder directives at the
spots indicated in the diff (the "Replace the contents below..." block around
lines 14–16 and the placeholder at line 35); open content/resume.md, remove
those draft instruction lines and replace them with the final resume copy (full
bio, skills, employment history, education, and contact details) so that the
read_resume tool returns only user-facing resume text; ensure no remaining
developer/instructional comments remain in the file and save/commit the updated
content.
In `@apps/mikeallisonjs.com/src/app/api/agent/route.ts`:
- Around line 22-25: The current MODELS computation uses the nullish coalescing
operator so an empty OPENROUTER_MODEL string yields an empty list and later
errors; change the logic that builds MODELS (the constant named MODELS that
references process.env.OPENROUTER_MODEL and DEFAULT_MODELS) to treat an
empty/whitespace OPENROUTER_MODEL as "not set" and fall back to DEFAULT_MODELS
(e.g. trim and check for truthiness before splitting), so streamOpenRouter
always sees at least the default model(s).
- Around line 153-263: The stream created in the ReadableStream start handler
doesn't propagate client disconnects so streamOpenRouter keeps running; fix by
creating an AbortController, forward req.signal into it (or abort
controller.signal into req.signal by listening to req.signal), add a
controller.cancel = () => abortController.abort() on the ReadableStream, and
pass abortController.signal into the streamOpenRouter(...) call (the generator
variable) so the generator can halt when the client disconnects; ensure any
awaits inside the loop (e.g., generator.next() and executeTool calls) will be
cancelled when the signal aborts.
In `@apps/mikeallisonjs.com/src/components/agent-terminal.tsx`:
- Around line 239-244: The effect that always sets el.scrollTop =
el.scrollHeight on turns updates is forcing scroll-to-bottom; change it so the
auto-scroll only happens when the user is already at (or very near) the bottom.
Use the existing scrollRef, isAtBottom and setIsAtBottom state (or derive a new
isAtBottom boolean) and add a scroll listener on the container to update
isAtBottom based on el.scrollHeight - el.scrollTop - el.clientHeight <=
threshold; in the useEffect that currently watches turns, only set el.scrollTop
= el.scrollHeight and setIsAtBottom(true) when isAtBottom is true (otherwise
leave the scroll position alone).
- Around line 716-734: The toggle button should expose its expanded/collapsed
state and be linked to the details panel: add aria-expanded={open},
aria-controls pointing to a stable id (e.g. `call-result-${call.id}`), and an
accessible aria-label (e.g. `Toggle ${call.name} details`) on the button
element, add an onKeyDown handler that toggles via Enter/Space (calling setOpen)
to complement onClick, and give the result pane that same id plus role="region"
and aria-hidden={!open} so screen readers know when it is visible; reference the
existing setOpen, open, call.result, call.name, summarizeArgs and ensure the
generated id uses a unique call identifier (call.id or similar).
In `@apps/mikeallisonjs.com/src/components/browser-window.tsx`:
- Around line 45-93: The decorative browser control buttons (elements with
aria-labels "Back", "Forward", "Reload", "More" in the browser-window.tsx
markup) are currently interactive but have no behavior; either make them truly
interactive by wiring click and keyboard handlers or make them non-interactive
decorative elements. Fix option A: implement onClick handlers (e.g., handleBack,
handleForward, handleReload, handleMore) and corresponding onKeyDown to support
Enter/Space, keep tabIndex={0}, and ensure accessible labels remain. Fix option
B: if they are purely decorative, replace the <button> tags with non-interactive
elements (e.g., <span> or <div>) or add aria-hidden="true" and remove tabIndex
to prevent keyboard focus. Update the elements referenced by their aria-labels
and the URL span usage accordingly so the component behavior and accessibility
match intent.
In `@apps/mikeallisonjs.com/src/components/portfolio.tsx`:
- Around line 72-93: The overlay controls are only revealed via group-hover
which breaks keyboard/touch access; update the overlay div (the element using
class "group-hover:opacity-100") to be visible by default on small screens and
only hide/show by hover/focus on larger screens (e.g. use responsive Tailwind
like default opacity-100 and sm:opacity-0 sm:group-hover:opacity-100
sm:focus-within:opacity-100), and add accessibility attributes/handlers to the
action links (the Link elements rendering visit and source): include descriptive
aria-labels (e.g. aria-label={`Visit ${project.name}`} and aria-label={`View
source for ${project.name}`}), ensure each link is keyboard-focusable (anchors
are by default, but add tabindex if you changed element types), and attach
onClick and onKeyDown handlers that perform the same navigation behavior for
activation via keyboard. Reference the overlay div class
(group-hover:opacity-100) and the Link instances that use project.websiteUrl and
project.githubUrl to locate changes.
In `@apps/mikeallisonjs.com/src/lib/agent/corpus.ts`:
- Around line 93-95: getJob may miss jobs on case-sensitive filesystems because
it validates with a case-insensitive regex but then passes the original slug to
readJobFile; normalize the slug first by calling trim().toLowerCase() and assign
it to a local variable, validate that normalizedSlug against /^[a-z0-9-]+$/ and
then call readJobFile(normalizedSlug) so both validation and file access use the
same canonical lowercased value (refer to getJob and readJobFile).
---
Nitpick comments:
In `@apps/mikeallisonjs.com/src/app/layout.tsx`:
- Around line 29-33: Replace the function declaration for RootLayout with a
const arrow function to match project style: change the declaration of
RootLayout (currently "export default function RootLayout({ children }: {
children: React.ReactNode })") to a const arrow assigned to the same exported
identifier (e.g., "const RootLayout = ({ children }: { children: React.ReactNode
}) => { ... }" and keep the existing export default), ensuring the props type
and returned JSX remain unchanged.
In `@apps/mikeallisonjs.com/src/app/page.tsx`:
- Line 12: Replace the function declarations with const arrow functions: change
"export default function Page()" to "const Page = () => { ... }" and then add
"export default Page" (since "export default const" is invalid), and change
"function ContactSection()" to "const ContactSection = () => { ... }"; preserve
all internal logic/props/returns and update any local references if needed so
the module still exports Page as default and uses ContactSection internally.
In `@apps/mikeallisonjs.com/src/components/agent-terminal.tsx`:
- Around line 454-459: The title bar div in the AgentTerminal component uses an
inline style prop for the background gradient and border-bottom; remove the
style prop and add equivalent Tailwind classes to the existing className (keep
"relative flex h-[30px] shrink-0 items-center px-2.5 font-mono text-[11px]").
Specifically, add bg-gradient-to-b from-[`#3b4045`] to-[`#31363b`] and border-b
border-[`#2e3338`] to the className so the gradient and border are expressed with
Tailwind instead of inline style.
In `@apps/mikeallisonjs.com/src/components/browser-window.tsx`:
- Around line 3-15: The BrowserWindow component is declared with a function
declaration; convert it to a const arrow component by replacing "export function
BrowserWindow({...}) { ... }" with "export const BrowserWindow = ({...}) => {
... }" while preserving the same props (id, title, url, contentClassName,
children) and exported name so external imports still work; ensure TypeScript
typings remain attached to the parameter destructuring exactly as before.
- Around line 22-27: The header/container div in the BrowserWindow component
uses inline style for a vertical gradient and border-bottom; replace those
inline style properties with Tailwind utility classes (use
bg-[linear-gradient(...)] or bg-gradient-to-b with appropriate arbitrary color
stops and use border-b/[1px] border-b-[`#2e3338`] for the bottom border) and
remove the style prop from the element; do the same for the second inline-styled
element referenced around the later block (lines 41-44) so all styling lives in
className using Tailwind arbitrary values (e.g., bg-[linear-gradient(...)] and
border-b-[`#2e3338`]) and keep existing utility classes like font-mono and px-2.5
untouched.
In `@apps/mikeallisonjs.com/src/components/desktop-shell.tsx`:
- Around line 14-24: Replace the function declaration DesktopShell with a const
arrow component to match repo conventions: change "export function
DesktopShell({ ... }: { ... }) { ... }" to an exported const arrow like "export
const DesktopShell = ({ agent, portfolio, services, contact }: { agent:
ReactNode; portfolio: ReactNode; services: ReactNode; contact: ReactNode }) => {
... }", preserving the same props names and types and keeping the implementation
body intact.
In `@apps/mikeallisonjs.com/src/components/kde-panel.tsx`:
- Around line 23-45: Replace the function declarations with const arrow
components to follow the project's style guide: change the top-level "function
Clock()" to "const Clock = () =>" and change "export function KdePanel(...)" to
"export const KdePanel = ({...}) =>"; ensure you keep the existing props/type
annotations, hooks (useState/useEffect), return JSX, and the export semantics
intact so behavior doesn't change.
- Line 49: The inline style on the element in kde-panel.tsx (currently using
style={{ background: '#1b1e20', borderBottom: '1px solid `#2d3136`' }}) should be
replaced with equivalent Tailwind className utilities—use a bg-... token or a
custom color token (e.g., bg-[theme-color] or bg-[`#1b1e20`] if necessary) and a
border-b with the appropriate border color class (e.g., border-b
border-[`#2d3136`] or a token like border-gray-700) on the same element; also
update the other inline style occurrences referenced around the same component
(lines ~56-57) to use Tailwind classes so the KDEPanel component (kde-panel.tsx)
is fully Tailwind-driven.
In `@apps/mikeallisonjs.com/src/components/kde-window.tsx`:
- Around line 3-11: The KdeWindow component is declared with a function
declaration; change it to a const arrow function per project style by replacing
"export function KdeWindow(...)" with an exported const arrow like "export const
KdeWindow = (...) => { ... }", keeping the same props type annotation ({ id?:
string; title: string; children: ReactNode }) and returning the same JSX; ensure
any named export usage remains valid and update any tooling expectations (e.g.,
displayName) if your project relies on it.
- Around line 20-23: The title-bar element in kde-window.tsx uses an inline
style object for the gradient background and bottom border; replace that style
prop with Tailwind classes (either the built-in gradient utilities like
bg-gradient-to-b from-[`#3b4045`] to-[`#31363b`] and border-b border-[`#2e3338`] or an
equivalent arbitrary bg-[linear-gradient(...)] utility) and move the classes
onto the same element (the title bar in the KDEWindow component) via className
so no inline style remains.
In `@apps/mikeallisonjs.com/src/lib/agent/corpus.ts`:
- Around line 149-152: The code currently awaits getJob serially over the jobs
list (variable jobs from listJobs), causing linear latency; change the loop to
fetch records concurrently by mapping jobs to getJob promises and awaiting
Promise.all (e.g., const records = await Promise.all(jobs.map(j =>
getJob(j.slug)))), then filter out null/undefined records before continuing;
update any logic that used the per-job record variable to iterate over the
filtered records array instead.
- Around line 19-107: Convert the top-level function declarations to const arrow
functions to match repo convention: change parseFrontmatter to "const
parseFrontmatter = (raw: string): { data: Record<string, unknown>; body: string
} => { ... }", change readJobFile to "const readJobFile = async (slug: string):
Promise<JobRecord | null> => { ... }", and do the same for the exported helpers
(listJobs, getJob, readResume and searchCorpus) so they become "export const
listJobs = async (...) => { ... }", etc.; preserve all parameter and return type
annotations, async keywords, and existing logic/returns when converting to arrow
functions.
In `@apps/mikeallisonjs.com/src/lib/agent/openrouter.ts`:
- Around line 60-76: The function parseOpenRouterErrorBody is a function
declaration but must follow the coding guideline to be a const arrow; replace
the declaration with a const arrow assigned to the same name (const
parseOpenRouterErrorBody = (body: string): { code?: number | string; message?:
string } => { ... }) keeping the exact logic and return types intact, preserve
the JSON.parse try/catch and final return, and ensure exports/usage still
reference parseOpenRouterErrorBody unchanged.
- Around line 127-240: The stream reader obtained via res.body.getReader() in
the async function (the reader/read loop starting at the const reader =
res.body.getReader() and the while(true) reader.read() loop) must be wrapped in
a try/finally so the reader.releaseLock() (or reader.cancel()) is always called
on all exits (the early [DONE] return, the mid-stream throw where
OpenRouterError is thrown, and any aborts during reader.read()); refactor by
moving the read-loop into a try block and call reader.releaseLock() (or cancel)
in the finally block so the lock is always released regardless of returns or
exceptions.
In `@apps/mikeallisonjs.com/src/lib/agent/projects.ts`:
- Around line 136-147: Convert the exported helpers listProjects and getProject
from function declarations to const arrow functions for consistency: replace
"export function listProjects() { ... }" with "export const listProjects = () =>
{ ... }" and "export function getProject(slug: string): ProjectData | undefined
{ ... }" with "export const getProject = (slug: string): ProjectData | undefined
=> { ... }", preserving their implementations, return types, exports, and any
existing references in the module.
In `@apps/mikeallisonjs.com/src/lib/agent/rate-limit.ts`:
- Around line 1-28: The current in-memory buckets Map used by checkRateLimit
(symbols: buckets, checkRateLimit, WINDOW_MS, LIMIT) is per-instance and never
evicts expired entries; fix it by (1) making checkRateLimit remove an entry when
existing.resetAt < now (delete from buckets before creating a fresh bucket) so
expired keys are not retained, and (2) if you need cross-instance enforcement
replace or back this Map with a shared store (Redis/Upstash/KV) rather than
per-instance state; if per-instance soft-guard behavior is intentional, add a
code comment near buckets explaining that limitation and why it's acceptable.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d5987562-ced7-4851-a065-6c62b3e0e6b3
📒 Files selected for processing (26)
apps/mikeallisonjs.com/.env.exampleapps/mikeallisonjs.com/content/jobs/_template.mdapps/mikeallisonjs.com/content/jobs/agilix.mdapps/mikeallisonjs.com/content/jobs/jesusfilm.mdapps/mikeallisonjs.com/content/resume.mdapps/mikeallisonjs.com/index.d.tsapps/mikeallisonjs.com/next-env.d.tsapps/mikeallisonjs.com/next.config.mjsapps/mikeallisonjs.com/src/app/api/agent/route.tsapps/mikeallisonjs.com/src/app/global.cssapps/mikeallisonjs.com/src/app/layout.tsxapps/mikeallisonjs.com/src/app/page.tsxapps/mikeallisonjs.com/src/components/agent-terminal.tsxapps/mikeallisonjs.com/src/components/browser-window.tsxapps/mikeallisonjs.com/src/components/desktop-shell.tsxapps/mikeallisonjs.com/src/components/header.tsxapps/mikeallisonjs.com/src/components/hero.tsxapps/mikeallisonjs.com/src/components/kde-panel.tsxapps/mikeallisonjs.com/src/components/kde-window.tsxapps/mikeallisonjs.com/src/components/portfolio.tsxapps/mikeallisonjs.com/src/components/services.tsxapps/mikeallisonjs.com/src/lib/agent/corpus.tsapps/mikeallisonjs.com/src/lib/agent/openrouter.tsapps/mikeallisonjs.com/src/lib/agent/projects.tsapps/mikeallisonjs.com/src/lib/agent/rate-limit.tsapps/mikeallisonjs.com/src/lib/agent/tools.ts
| <button | ||
| className="flex h-7 w-7 items-center justify-center rounded-full text-[#7f8c8d] opacity-40" | ||
| aria-label="Back" | ||
| tabIndex={-1} | ||
| > | ||
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> | ||
| <path d="m15 18-6-6 6-6" /> | ||
| </svg> | ||
| </button> | ||
| <button | ||
| className="flex h-7 w-7 items-center justify-center rounded-full text-[#7f8c8d] opacity-40" | ||
| aria-label="Forward" | ||
| tabIndex={-1} | ||
| > | ||
| <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> | ||
| <path d="m9 18 6-6-6-6" /> | ||
| </svg> | ||
| </button> | ||
| <button | ||
| className="flex h-7 w-7 items-center justify-center rounded-full text-[#7f8c8d] transition-colors hover:bg-white/[0.06] hover:text-[#eff0f1]" | ||
| aria-label="Reload" | ||
| tabIndex={-1} | ||
| > | ||
| <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> | ||
| <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> | ||
| <path d="M3 3v5h5" /> | ||
| </svg> | ||
| </button> | ||
|
|
||
| {/* URL bar */} | ||
| <div className="flex flex-1 items-center gap-2 rounded-full bg-[#1e2226] px-3 py-[5px] font-mono text-[12px]"> | ||
| <svg className="h-3.5 w-3.5 shrink-0 text-[#3daee9]" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"> | ||
| <rect width="18" height="11" x="3" y="11" rx="2" ry="2" /> | ||
| <path d="M7 11V7a5 5 0 0 1 10 0v4" /> | ||
| </svg> | ||
| <span className="truncate text-[#eff0f1]">{url}</span> | ||
| </div> | ||
|
|
||
| <button | ||
| className="flex h-7 w-7 items-center justify-center rounded-full text-[#7f8c8d] transition-colors hover:bg-white/[0.06] hover:text-[#eff0f1]" | ||
| aria-label="More" | ||
| tabIndex={-1} | ||
| > | ||
| <svg width="4" height="18" viewBox="0 0 4 20" fill="currentColor"> | ||
| <circle cx="2" cy="2" r="2" /> | ||
| <circle cx="2" cy="10" r="2" /> | ||
| <circle cx="2" cy="18" r="2" /> | ||
| </svg> | ||
| </button> |
There was a problem hiding this comment.
Decorative browser controls should not be interactive buttons without behavior.
Right now these controls look interactive but don’t perform actions; that’s rough for keyboard/screen-reader users. Either wire real handlers (including keyboard behavior) or render them as non-interactive elements.
As per coding guidelines, "Implement accessibility features on interactive elements including tabindex, aria-label, onClick, and onKeyDown handlers".
🤖 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 `@apps/mikeallisonjs.com/src/components/browser-window.tsx` around lines 45 -
93, The decorative browser control buttons (elements with aria-labels "Back",
"Forward", "Reload", "More" in the browser-window.tsx markup) are currently
interactive but have no behavior; either make them truly interactive by wiring
click and keyboard handlers or make them non-interactive decorative elements.
Fix option A: implement onClick handlers (e.g., handleBack, handleForward,
handleReload, handleMore) and corresponding onKeyDown to support Enter/Space,
keep tabIndex={0}, and ensure accessible labels remain. Fix option B: if they
are purely decorative, replace the <button> tags with non-interactive elements
(e.g., <span> or <div>) or add aria-hidden="true" and remove tabIndex to prevent
keyboard focus. Update the elements referenced by their aria-labels and the URL
span usage accordingly so the component behavior and accessibility match intent.
| <div className="absolute inset-0 flex items-center justify-center gap-3 bg-[color:var(--deep-space)]/70 opacity-0 backdrop-blur-sm transition-opacity duration-300 group-hover:opacity-100"> | ||
| <Link | ||
| href={project.websiteUrl} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="inline-flex items-center gap-1.5 rounded-md bg-[color:var(--spring-green)] px-4 py-2 font-mono text-xs font-medium text-white shadow-[0_0_20px_-4px_rgba(8,135,43,0.6)] transition-transform hover:scale-105" | ||
| > | ||
| <IconExternalLink size={14} /> | ||
| visit | ||
| </Link> | ||
| {project.githubUrl && ( | ||
| <Link | ||
| href={project.githubUrl} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="inline-flex items-center gap-1.5 rounded-md border border-[color:var(--subtle-gray)] bg-black/50 px-4 py-2 font-mono text-xs font-medium text-[color:var(--polar-blue)] transition-colors hover:border-[color:var(--polar-blue)]/60" | ||
| > | ||
| <IconBrandGithub size={14} /> | ||
| source | ||
| </Link> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Uh-oh, these action links are hover-only right now.
Line 72 hides controls behind group-hover only, which hurts keyboard and touch access. Make them visible by default on small screens and reveal on focus-within/hover for larger screens.
Proposed fix
- <div className="absolute inset-0 flex items-center justify-center gap-3 bg-[color:var(--deep-space)]/70 opacity-0 backdrop-blur-sm transition-opacity duration-300 group-hover:opacity-100">
+ <div className="absolute inset-0 flex items-center justify-center gap-3 bg-[color:var(--deep-space)]/70 opacity-100 backdrop-blur-sm transition-opacity duration-300 md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100">
@@
- className="inline-flex items-center gap-1.5 rounded-md bg-[color:var(--spring-green)] px-4 py-2 font-mono text-xs font-medium text-white shadow-[0_0_20px_-4px_rgba(8,135,43,0.6)] transition-transform hover:scale-105"
+ className="inline-flex items-center gap-1.5 rounded-md bg-[color:var(--spring-green)] px-4 py-2 font-mono text-xs font-medium text-white shadow-[0_0_20px_-4px_rgba(8,135,43,0.6)] transition-transform hover:scale-105 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[color:var(--polar-blue)]"
@@
- className="inline-flex items-center gap-1.5 rounded-md border border-[color:var(--subtle-gray)] bg-black/50 px-4 py-2 font-mono text-xs font-medium text-[color:var(--polar-blue)] transition-colors hover:border-[color:var(--polar-blue)]/60"
+ className="inline-flex items-center gap-1.5 rounded-md border border-[color:var(--subtle-gray)] bg-black/50 px-4 py-2 font-mono text-xs font-medium text-[color:var(--polar-blue)] transition-colors hover:border-[color:var(--polar-blue)]/60 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[color:var(--polar-blue)]"As per coding guidelines, "Implement accessibility features on interactive elements including tabindex, aria-label, onClick, and onKeyDown handlers".
📝 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.
| <div className="absolute inset-0 flex items-center justify-center gap-3 bg-[color:var(--deep-space)]/70 opacity-0 backdrop-blur-sm transition-opacity duration-300 group-hover:opacity-100"> | |
| <Link | |
| href={project.websiteUrl} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="inline-flex items-center gap-1.5 rounded-md bg-[color:var(--spring-green)] px-4 py-2 font-mono text-xs font-medium text-white shadow-[0_0_20px_-4px_rgba(8,135,43,0.6)] transition-transform hover:scale-105" | |
| > | |
| <IconExternalLink size={14} /> | |
| visit | |
| </Link> | |
| {project.githubUrl && ( | |
| <Link | |
| href={project.githubUrl} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="inline-flex items-center gap-1.5 rounded-md border border-[color:var(--subtle-gray)] bg-black/50 px-4 py-2 font-mono text-xs font-medium text-[color:var(--polar-blue)] transition-colors hover:border-[color:var(--polar-blue)]/60" | |
| > | |
| <IconBrandGithub size={14} /> | |
| source | |
| </Link> | |
| )} | |
| </div> | |
| <div className="absolute inset-0 flex items-center justify-center gap-3 bg-[color:var(--deep-space)]/70 opacity-100 backdrop-blur-sm transition-opacity duration-300 md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100"> | |
| <Link | |
| href={project.websiteUrl} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="inline-flex items-center gap-1.5 rounded-md bg-[color:var(--spring-green)] px-4 py-2 font-mono text-xs font-medium text-white shadow-[0_0_20px_-4px_rgba(8,135,43,0.6)] transition-transform hover:scale-105 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[color:var(--polar-blue)]" | |
| > | |
| <IconExternalLink size={14} /> | |
| visit | |
| </Link> | |
| {project.githubUrl && ( | |
| <Link | |
| href={project.githubUrl} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="inline-flex items-center gap-1.5 rounded-md border border-[color:var(--subtle-gray)] bg-black/50 px-4 py-2 font-mono text-xs font-medium text-[color:var(--polar-blue)] transition-colors hover:border-[color:var(--polar-blue)]/60 focus-visible:outline focus-visible:outline-2 focus-visible:outline-[color:var(--polar-blue)]" | |
| > | |
| <IconBrandGithub size={14} /> | |
| source | |
| </Link> | |
| )} | |
| </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 `@apps/mikeallisonjs.com/src/components/portfolio.tsx` around lines 72 - 93,
The overlay controls are only revealed via group-hover which breaks
keyboard/touch access; update the overlay div (the element using class
"group-hover:opacity-100") to be visible by default on small screens and only
hide/show by hover/focus on larger screens (e.g. use responsive Tailwind like
default opacity-100 and sm:opacity-0 sm:group-hover:opacity-100
sm:focus-within:opacity-100), and add accessibility attributes/handlers to the
action links (the Link elements rendering visit and source): include descriptive
aria-labels (e.g. aria-label={`Visit ${project.name}`} and aria-label={`View
source for ${project.name}`}), ensure each link is keyboard-focusable (anchors
are by default, but add tabindex if you changed element types), and attach
onClick and onKeyDown handlers that perform the same navigation behavior for
activation via keyboard. Reference the overlay div class
(group-hover:opacity-100) and the Link instances that use project.websiteUrl and
project.githubUrl to locate changes.
| export async function getJob(slug: string): Promise<JobRecord | null> { | ||
| if (!/^[a-z0-9-]+$/i.test(slug)) return null | ||
| return readJobFile(slug) |
There was a problem hiding this comment.
Slug lookup can miss valid jobs when callers pass uppercase.
Line 94 allows uppercase (/i), but the file read on Line 95 uses the raw slug; on case-sensitive filesystems this can return null for existing jobs. Normalize once (trim().toLowerCase()) before validation/read.
Patch idea
export async function getJob(slug: string): Promise<JobRecord | null> {
- if (!/^[a-z0-9-]+$/i.test(slug)) return null
- return readJobFile(slug)
+ const normalizedSlug = slug.trim().toLowerCase()
+ if (!/^[a-z0-9-]+$/.test(normalizedSlug)) return null
+ return readJobFile(normalizedSlug)
}🤖 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 `@apps/mikeallisonjs.com/src/lib/agent/corpus.ts` around lines 93 - 95, getJob
may miss jobs on case-sensitive filesystems because it validates with a
case-insensitive regex but then passes the original slug to readJobFile;
normalize the slug first by calling trim().toLowerCase() and assign it to a
local variable, validate that normalizedSlug against /^[a-z0-9-]+$/ and then
call readJobFile(normalizedSlug) so both validation and file access use the same
canonical lowercased value (refer to getJob and readJobFile).
- Increased years of experience from 24 to 25 in the resume. - Enhanced the summary to reflect a more comprehensive overview of skills and career highlights. - Added a new specialization section detailing areas of expertise. - Updated job title and responsibilities for the Agilix position, emphasizing leadership and contributions to the EdTech platform. - Included new certifications and education details to provide a fuller picture of qualifications. These changes aim to present a more accurate and detailed professional profile for Mike Allison.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@apps/mikeallisonjs.com/content/jobs/emdeon.md`:
- Line 9: Update the front-matter "stack" array in emdeon.md to include the
missing technologies that appear in the body (add "JavaScript" and "CSS" to the
stack array) so the metadata matches the "## Tech" section; locate the "stack"
key in the front matter and append these entries (and repeat the same fix for
the other affected files referenced around lines 34-35) to keep search/agent
indexing consistent.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 465249f9-83ac-48bb-98b6-57ed9b7df05b
📒 Files selected for processing (8)
apps/mikeallisonjs.com/content/jobs/agilix.mdapps/mikeallisonjs.com/content/jobs/captainssounds.mdapps/mikeallisonjs.com/content/jobs/compasslearning.mdapps/mikeallisonjs.com/content/jobs/cru.mdapps/mikeallisonjs.com/content/jobs/duthie.mdapps/mikeallisonjs.com/content/jobs/ecteon.mdapps/mikeallisonjs.com/content/jobs/emdeon.mdapps/mikeallisonjs.com/content/resume.md
✅ Files skipped from review due to trivial changes (6)
- apps/mikeallisonjs.com/content/jobs/duthie.md
- apps/mikeallisonjs.com/content/jobs/compasslearning.md
- apps/mikeallisonjs.com/content/resume.md
- apps/mikeallisonjs.com/content/jobs/cru.md
- apps/mikeallisonjs.com/content/jobs/captainssounds.md
- apps/mikeallisonjs.com/content/jobs/ecteon.md
- Introduced an AbortController to manage request cancellation, improving resource management and responsiveness. - Updated the stream handling logic to check for abort signals, ensuring that the stream can be gracefully closed when needed. - Refactored the send and close functions for better error handling and clarity. These changes aim to enhance the reliability and performance of the agent's streaming functionality.
- Updated the technology stack for multiple job entries to include JavaScript and CSS, replacing CoffeeScript in Agilix and Ecteon, and removing it from the services component. - Removed the Services component entirely from the project, streamlining the application structure and focusing on core functionalities. These changes aim to enhance the accuracy of job descriptions and simplify the codebase.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/mikeallisonjs.com/src/components/kde-panel.tsx (1)
47-47: ⚡ Quick winLet’s ditch inline
styleprops here and keep it Tailwind-only, champ.Move these inline colors/border styles into Tailwind classes (or shared utility classes) to match the TSX styling rule used across this PR.
As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
Also applies to: 54-55
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-panel.tsx` at line 47, The element in kde-panel.tsx currently uses an inline style prop for background and border-bottom; remove the style prop and replace it with Tailwind classes on the same element (e.g., use className="bg-[`#1b1e20`] border-b border-[`#2d3136`]" or equivalent configured color tokens) and do the same for the other inline style occurrences referenced in this component (the other two style props noted). Update any merging of existing className values accordingly so the component (KDEPanel) uses only Tailwind utility classes instead of inline styles.apps/mikeallisonjs.com/src/components/agent-terminal.tsx (1)
166-166: ⚡ Quick winDude, let’s move inline styles into Tailwind classes.
This component still uses
style={...}in a couple spots, which breaks the repo’s TSX styling rule. Please replace them with Tailwind utilities (or a utility class in global styles if needed for the gradient).As per coding guidelines, "Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags in React/Next.js components".
Also applies to: 456-459
🤖 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 `@apps/mikeallisonjs.com/src/components/agent-terminal.tsx` at line 166, The div in the AgentTerminal component that currently uses style={{ paddingLeft: indent.length * 12 }} (the element with key={i}) should be changed to use a Tailwind utility class instead of inline styles — replace the inline style with a dynamic Tailwind arbitrary value class like className={`flex gap-2 ${`pl-[${indent.length * 12}px]`}`} so padding is driven by indent.length, and similarly replace the other inline style(s) around lines 456-459 (the gradient element) with either Tailwind utilities or a named global CSS utility (e.g., .agent-gradient) and reference that class in the component; locate these in the AgentTerminal component and update className usages accordingly.
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-panel.tsx`:
- Around line 64-78: Buttons that hide their text at smaller viewports (the
navigation button rendering Icon + hidden label using `hidden sm:inline`, and
the mode-toggle icon button) lack accessible names and keyboard handlers; add an
explicit aria-label to each icon-only button (e.g., on the navigation <button>
that calls onNavigate(id) and on the mode-toggle button), ensure they are
focusable (tabIndex if necessary), and add onKeyDown handlers that mirror the
onClick behavior so keyboard users can activate them. Locate the navigation
button that uses onNavigate and Icon, and the mode-toggle icon button, and
update them to include aria-label values derived from `label` or the toggle
intent plus corresponding onKeyDown (Enter/Space) handlers and tabindex support.
---
Nitpick comments:
In `@apps/mikeallisonjs.com/src/components/agent-terminal.tsx`:
- Line 166: The div in the AgentTerminal component that currently uses style={{
paddingLeft: indent.length * 12 }} (the element with key={i}) should be changed
to use a Tailwind utility class instead of inline styles — replace the inline
style with a dynamic Tailwind arbitrary value class like className={`flex gap-2
${`pl-[${indent.length * 12}px]`}`} so padding is driven by indent.length, and
similarly replace the other inline style(s) around lines 456-459 (the gradient
element) with either Tailwind utilities or a named global CSS utility (e.g.,
.agent-gradient) and reference that class in the component; locate these in the
AgentTerminal component and update className usages accordingly.
In `@apps/mikeallisonjs.com/src/components/kde-panel.tsx`:
- Line 47: The element in kde-panel.tsx currently uses an inline style prop for
background and border-bottom; remove the style prop and replace it with Tailwind
classes on the same element (e.g., use className="bg-[`#1b1e20`] border-b
border-[`#2d3136`]" or equivalent configured color tokens) and do the same for the
other inline style occurrences referenced in this component (the other two style
props noted). Update any merging of existing className values accordingly so the
component (KDEPanel) uses only Tailwind utility classes instead of inline
styles.
🪄 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: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 883a51eb-ee66-4898-8982-23bab204de68
📒 Files selected for processing (11)
apps/mikeallisonjs.com/content/jobs/agilix.mdapps/mikeallisonjs.com/content/jobs/compasslearning.mdapps/mikeallisonjs.com/content/jobs/cru.mdapps/mikeallisonjs.com/content/jobs/ecteon.mdapps/mikeallisonjs.com/content/jobs/emdeon.mdapps/mikeallisonjs.com/src/app/page.tsxapps/mikeallisonjs.com/src/components/agent-terminal.tsxapps/mikeallisonjs.com/src/components/desktop-shell.tsxapps/mikeallisonjs.com/src/components/header.tsxapps/mikeallisonjs.com/src/components/kde-panel.tsxapps/mikeallisonjs.com/src/components/services.tsx
💤 Files with no reviewable changes (1)
- apps/mikeallisonjs.com/src/components/services.tsx
✅ Files skipped from review due to trivial changes (4)
- apps/mikeallisonjs.com/content/jobs/cru.md
- apps/mikeallisonjs.com/content/jobs/compasslearning.md
- apps/mikeallisonjs.com/content/jobs/agilix.md
- apps/mikeallisonjs.com/content/jobs/ecteon.md
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/mikeallisonjs.com/src/components/header.tsx
| <button | ||
| key={id} | ||
| onClick={() => onNavigate(id)} | ||
| className={`flex h-8 items-center gap-1.5 rounded px-2.5 text-xs transition-colors ${ | ||
| isActive | ||
| ? 'bg-white/[0.1] text-[#eff0f1]' | ||
| : 'text-[#eff0f1] hover:bg-white/[0.06]' | ||
| }`} | ||
| > | ||
| <Icon | ||
| size={14} | ||
| className={`shrink-0 ${isActive ? 'text-[#3daee9]' : 'text-[#3daee9]'}`} | ||
| /> | ||
| <span className="hidden sm:inline">{label}</span> | ||
| </button> |
There was a problem hiding this comment.
Buttons can become unlabeled for screen readers on smaller viewports.
When task text is hidden (hidden sm:inline), those controls are icon-only and need explicit accessible names. Same deal for the mode-toggle icon button: title is not a reliable accessible name. Please add aria-label for each button.
As per coding guidelines, "Implement accessibility features on interactive elements including tabindex, aria-label, onClick, and onKeyDown handlers".
Also applies to: 85-91
🤖 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 `@apps/mikeallisonjs.com/src/components/kde-panel.tsx` around lines 64 - 78,
Buttons that hide their text at smaller viewports (the navigation button
rendering Icon + hidden label using `hidden sm:inline`, and the mode-toggle icon
button) lack accessible names and keyboard handlers; add an explicit aria-label
to each icon-only button (e.g., on the navigation <button> that calls
onNavigate(id) and on the mode-toggle button), ensure they are focusable
(tabIndex if necessary), and add onKeyDown handlers that mirror the onClick
behavior so keyboard users can activate them. Locate the navigation button that
uses onNavigate and Icon, and the mode-toggle icon button, and update them to
include aria-label values derived from `label` or the toggle intent plus
corresponding onKeyDown (Enter/Space) handlers and tabindex support.
Summary by CodeRabbit
New Features
Content
Style