Skip to content

feat: Add meeting-action-agent kit#89

Closed
harishghasolia07 wants to merge 2 commits intoLamatic:mainfrom
harishghasolia07:meeting-action-agent
Closed

feat: Add meeting-action-agent kit#89
harishghasolia07 wants to merge 2 commits intoLamatic:mainfrom
harishghasolia07:meeting-action-agent

Conversation

@harishghasolia07
Copy link
Copy Markdown

@harishghasolia07 harishghasolia07 commented Mar 22, 2026

  • New kit added: kits/automation/meeting-action-agent — Next.js app + Lamatic flow to convert raw meeting notes into decisions, prioritized action items (owner/deadline/priority), markdown summary, and follow-up email.
  • Server: analyzeMeeting (actions/orchestrate.ts) calls Lamatic flow, robustly parses/normalizes JSON output, and returns structured result or raw fallback with mapped error messages.
  • UI: app/page.tsx — textarea input with samples, submit to analyzeMeeting, shows decisions, action items (priority badges), markdown summary and follow-up email with copy buttons, loading/error states, and reset.
  • Flow: meeting-action-flow — 3-node flow (API trigger → LLM gpt-4o-mini → JSON response) with strict 4-key output schema.
  • Includes: complete shadcn-style component set (50+ UI primitives), theme/utility files, hooks (useIsMobile, useToast), lamatic client, and utilities.
  • Config & tooling: package.json, tsconfig, postcss, next.config, .env.example, kit config, README with setup/deploy (Vercel) and required env vars: MEETING_ACTION_FLOW_ID, LAMATIC_API_URL, LAMATIC_PROJECT_ID, LAMATIC_API_KEY.
  • Repo hygiene: .gitignore updates (env, node_modules, .next, kit path).

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 22, 2026

📝 Walkthrough

Walkthrough

Adds a new "Meeting Action Agent" kit: a Next.js app that captures meeting notes, calls a Lamatic flow via a server action to extract structured meeting outputs, includes a large shadcn-style UI component library, tooling/config, flow definitions, and documentation.

Changes

Cohort / File(s) Summary
Repository config
/.gitignore, kits/automation/meeting-action-agent/.gitignore
Updated ignore rules and added project-level .gitignore for Node/Next/Tailwind/dev artifacts and env files.
Project config & metadata
kits/automation/meeting-action-agent/package.json, .../tsconfig.json, .../next.config.mjs, .../postcss.config.mjs, .../components.json, .../config.json, .../.env.example
New package and build configs, shadcn components.json, kit metadata, and example env file.
App shell & styles
kits/automation/meeting-action-agent/app/globals.css, kits/automation/meeting-action-agent/app/layout.tsx
Global Tailwind theme variables, dark-mode tokens, and top-level RootLayout with metadata.
Pages & actions
kits/automation/meeting-action-agent/app/page.tsx, kits/automation/meeting-action-agent/actions/orchestrate.ts
Client page for meeting input/UX and server-side analyzeMeeting action that executes Lamatic flow, parses/normalizes output, and returns structured or raw results with error mapping.
Lamatic integration
kits/automation/meeting-action-agent/lib/lamatic-client.ts, kits/automation/meeting-action-agent/flows/.../*
Lamatic client initialization (env validation) and flow artifacts (config.json, inputs.json, meta.json, README) defining the 3-node meeting-action flow.
UI components
kits/automation/meeting-action-agent/components/*, kits/automation/meeting-action-agent/components/ui/*
Large set of shadcn-style UI primitives and higher-level components (accordion, alert, dialog, form, sidebar, chart, calendar, carousel, table, toast, etc.) with styling wrappers and utilities.
Hooks & utilities
kits/automation/meeting-action-agent/hooks/use-toast.ts, .../hooks/use-mobile.ts, .../lib/utils.ts
In-memory toast store + hook, mobile detection hook, and cn class merge utility.
Docs
kits/automation/meeting-action-agent/README.md, kits/automation/meeting-action-agent/flows/meeting-action-flow/README.md
New README files describing setup, required env vars, Lamatic flow setup, and deployment instructions.
Other
kits/automation/meeting-action-agent/components.json, kits/automation/meeting-action-agent/next.config.mjs
Shadcn UI config and Next.js config added.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as Browser<br/>MeetingAgentPage
    participant Server as Server<br/>analyzeMeeting
    participant Lamatic as Lamatic<br/>API
    participant LLM as LLM<br/>gpt-4o-mini

    User->>UI: Enter meeting notes & submit
    UI->>Server: POST analyzeMeeting(meetingNotes)
    Server->>Lamatic: executeFlow(flowId, { meeting_notes })
    Lamatic->>LLM: system/user prompts + meeting_notes
    LLM->>Lamatic: generatedResponse (text/JSON)
    Lamatic->>Server: full SDK response
    Server->>Server: extractParsed(), normalize priorities, map action_items
    Server-->>UI: { success: true, data } or { success: true, rawResult } / { success: false, error }
    UI->>User: Render decisions, action items, summary, follow-up email (or raw output)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Fix : Config Removal #42: Changes to Lamatic client initialization and environment-based configuration; overlaps with new lib/lamatic-client.ts handling of API URL/project/key and flow ID.
  • Fix : New Agent Kit Ignore #66: Modifies repository ignore rules; related to the added/updated .gitignore files.

Suggested reviewers

  • d-pamneja
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (17)
kits/automation/meeting-action-agent/components/ui/kbd.tsx-18-24 (1)

18-24: ⚠️ Potential issue | 🟡 Minor

Fix KbdGroup prop typing to match rendered element.

KbdGroup is typed as React.ComponentProps<'div'> but renders a <kbd> element. This mismatch allows invalid props to be passed and breaks the type contract.

Change to React.ComponentProps<'kbd'> to match the actual rendered element and align with the Kbd component pattern.

kits/automation/meeting-action-agent/components/ui/menubar.tsx-67-85 (1)

67-85: ⚠️ Potential issue | 🟡 Minor

Add missing closed-state animation trigger in MenubarContent.

On Line 82, close-state transition classes are present, but data-[state=closed]:animate-out is missing. Without it, close animation utilities may not apply.

💡 Proposed patch
-          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md',
+          'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md',
.gitignore-5-5 (1)

5-5: ⚠️ Potential issue | 🟡 Minor

Fix the .gitignore path to match the actual kit location.

The rule /meeting-action-agent/ ignores a non-existent directory at the repository root. The actual kit is located at kits/automation/meeting-action-agent/, as confirmed throughout the codebase (package.json, config.json, README.md, and Vercel deployment configurations). Update the path to /kits/automation/meeting-action-agent/ or remove the rule if unintended.

kits/automation/meeting-action-agent/components/ui/empty.tsx-71-81 (1)

71-81: ⚠️ Potential issue | 🟡 Minor

Type mismatch: props typed as <p> but renders <div>.

EmptyDescription accepts React.ComponentProps<'p'> but renders a <div>. This creates a type inconsistency. While functionally similar, <p> cannot contain block-level elements like <div>, so using a <div> here is correct — but the type annotation should match.

🐛 Proposed fix: align type with rendered element
-function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
+function EmptyDescription({ className, ...props }: React.ComponentProps<'div'>) {
kits/automation/meeting-action-agent/components/ui/form.tsx-45-54 (1)

45-54: ⚠️ Potential issue | 🟡 Minor

Runtime guard is ineffective — will never throw.

The context is initialized with {} as FormFieldContextValue, so fieldContext will always be a truthy object (even when used outside <FormField>). The check if (!fieldContext) will never be true.

🐛 Proposed fix: check for the presence of a valid name property
 const useFormField = () => {
   const fieldContext = React.useContext(FormFieldContext)
   const itemContext = React.useContext(FormItemContext)
+
+  if (!fieldContext.name) {
+    throw new Error('useFormField should be used within <FormField>')
+  }
+
   const { getFieldState } = useFormContext()
   const formState = useFormState({ name: fieldContext.name })
   const fieldState = getFieldState(fieldContext.name, formState)
 
-  if (!fieldContext) {
-    throw new Error('useFormField should be used within <FormField>')
-  }
-
   const { id } = itemContext
kits/automation/meeting-action-agent/components/ui/navigation-menu.tsx-1-6 (1)

1-6: ⚠️ Potential issue | 🟡 Minor

Missing 'use client' directive.

This file uses @radix-ui/react-navigation-menu which requires client-side rendering, but unlike the other UI component files in this PR (tabs.tsx, dropdown-menu.tsx, dialog.tsx, command.tsx, select.tsx), it's missing the 'use client' directive. This will cause errors in Next.js App Router if imported from a Server Component.

🔧 Proposed fix
+'use client'
+
 import * as React from 'react'
 import * as NavigationMenuPrimitive from '@radix-ui/react-navigation-menu'
kits/automation/meeting-action-agent/components/ui/command.tsx-45-59 (1)

45-59: ⚠️ Potential issue | 🟡 Minor

DialogHeader is rendered outside DialogContent.

The DialogHeader with title/description is placed as a sibling to DialogContent rather than inside it. While the sr-only class hides it visually, this breaks the expected semantic structure where header content should be within the dialog's content container.

🔧 Proposed fix
   return (
     <Dialog {...props}>
-      <DialogHeader className="sr-only">
-        <DialogTitle>{title}</DialogTitle>
-        <DialogDescription>{description}</DialogDescription>
-      </DialogHeader>
       <DialogContent
         className={cn('overflow-hidden p-0', className)}
         showCloseButton={showCloseButton}
       >
+        <DialogHeader className="sr-only">
+          <DialogTitle>{title}</DialogTitle>
+          <DialogDescription>{description}</DialogDescription>
+        </DialogHeader>
         <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
           {children}
         </Command>
       </DialogContent>
     </Dialog>
   )
kits/automation/meeting-action-agent/components/ui/carousel.tsx-183-197 (1)

183-197: ⚠️ Potential issue | 🟡 Minor

Compose button props instead of letting them override navigation.

Because ...props is spread after onClick and disabled, a caller-provided handler or disabled state can replace the carousel control logic. That makes these wrappers easy to break for common cases like analytics hooks.

Suggested fix
 function CarouselPrevious({
   className,
   variant = 'outline',
   size = 'icon',
+  onClick,
+  disabled,
   ...props
 }: React.ComponentProps<typeof Button>) {
@@
     <Button
+      {...props}
       data-slot="carousel-previous"
       variant={variant}
       size={size}
@@
-      disabled={!canScrollPrev}
-      onClick={scrollPrev}
-      {...props}
+      disabled={disabled || !canScrollPrev}
+      onClick={(event) => {
+        onClick?.(event)
+        if (!event.defaultPrevented) scrollPrev()
+      }}
     >

Apply the same pattern to CarouselNext.

Also applies to: 213-226

kits/automation/meeting-action-agent/components/ui/carousel.tsx-78-89 (1)

78-89: ⚠️ Potential issue | 🟡 Minor

Scope keyboard navigation to the right keys and targets.

Using onKeyDownCapture here steals arrow keys from every focused descendant, so inputs/textareas/contenteditable content inside a slide lose normal caret navigation. It also never switches to ArrowUp/ArrowDown for vertical carousels.

Suggested fix
   const handleKeyDown = React.useCallback(
     (event: React.KeyboardEvent<HTMLDivElement>) => {
-      if (event.key === 'ArrowLeft') {
+      const target = event.target as HTMLElement
+      if (
+        target.closest(
+          'input, textarea, select, [contenteditable="true"], [role="textbox"]'
+        )
+      ) {
+        return
+      }
+
+      if (orientation === 'horizontal' && event.key === 'ArrowLeft') {
         event.preventDefault()
         scrollPrev()
-      } else if (event.key === 'ArrowRight') {
+      } else if (orientation === 'horizontal' && event.key === 'ArrowRight') {
+        event.preventDefault()
+        scrollNext()
+      } else if (orientation === 'vertical' && event.key === 'ArrowUp') {
+        event.preventDefault()
+        scrollPrev()
+      } else if (orientation === 'vertical' && event.key === 'ArrowDown') {
         event.preventDefault()
         scrollNext()
       }
     },
-    [scrollPrev, scrollNext],
+    [orientation, scrollPrev, scrollNext],
   )
@@
-        onKeyDownCapture={handleKeyDown}
+        onKeyDown={handleKeyDown}

Also applies to: 121-123

kits/automation/meeting-action-agent/components/ui/chart.tsx-289-300 (1)

289-300: ⚠️ Potential issue | 🟡 Minor

Provide a legend label fallback when config.label is omitted.

ChartConfig.label is optional, but the legend only renders itemConfig?.label, so series that define only color/theme show up as blank legend entries.

Suggested fix
-            {itemConfig?.label}
+            {itemConfig?.label ?? item.value ?? key}
kits/automation/meeting-action-agent/components/ui/chart.tsx-235-238 (1)

235-238: ⚠️ Potential issue | 🟡 Minor

Don't drop zero-valued points from the tooltip.

item.value && treats 0 as absent, so legitimate zero values render without a value in the tooltip.

Suggested fix
-                    {item.value && (
+                    {item.value !== undefined && item.value !== null && (
                       <span className="text-foreground font-mono font-medium tabular-nums">
                         {item.value.toLocaleString()}
                       </span>
                     )}
kits/automation/meeting-action-agent/flows/meeting-action-flow/config.json-11-11 (1)

11-11: ⚠️ Potential issue | 🟡 Minor

Typo: "responeType" should be "responseType".

This may cause issues if the Lamatic platform validates this field name.

📝 Proposed fix
-          "responeType": "realtime",
+          "responseType": "realtime",
kits/automation/meeting-action-agent/app/page.tsx-150-161 (1)

150-161: ⚠️ Potential issue | 🟡 Minor

Add error handling for clipboard operations.

navigator.clipboard.writeText() can throw if clipboard access is denied or unavailable. Wrap in try/catch to prevent unhandled promise rejections.

🛡️ Proposed fix
 const handleCopyEmail = async () => {
   if (!result?.followup_email) return
-  await navigator.clipboard.writeText(result.followup_email)
-  setCopiedEmail(true)
-  setTimeout(() => setCopiedEmail(false), 2000)
+  try {
+    await navigator.clipboard.writeText(result.followup_email)
+    setCopiedEmail(true)
+    setTimeout(() => setCopiedEmail(false), 2000)
+  } catch {
+    // Clipboard access denied or unavailable
+  }
 }

 const handleCopyReport = async () => {
   if (!result?.summary_report) return
-  await navigator.clipboard.writeText(result.summary_report)
-  setCopiedReport(true)
-  setTimeout(() => setCopiedReport(false), 2000)
+  try {
+    await navigator.clipboard.writeText(result.summary_report)
+    setCopiedReport(true)
+    setTimeout(() => setCopiedReport(false), 2000)
+  } catch {
+    // Clipboard access denied or unavailable
+  }
 }
kits/automation/meeting-action-agent/components/ui/item.tsx-8-17 (1)

8-17: ⚠️ Potential issue | 🟡 Minor

Consider adding role="listitem" to Item for complete ARIA semantics.

ItemGroup has role="list" (Line 11), but Item doesn't have the corresponding role="listitem". For proper ARIA list semantics, items within a list container should be marked as list items.

♿ Suggested fix
 function Item({
   className,
   variant = 'default',
   size = 'default',
   asChild = false,
   ...props
 }: React.ComponentProps<'div'> &
   VariantProps<typeof itemVariants> & { asChild?: boolean }) {
   const Comp = asChild ? Slot : 'div'
   return (
     <Comp
+      role="listitem"
       data-slot="item"
       data-variant={variant}
       data-size={size}

Also applies to: 54-72

kits/automation/meeting-action-agent/components/ui/sidebar.tsx-85-89 (1)

85-89: ⚠️ Potential issue | 🟡 Minor

Consider adding SameSite attribute to the cookie.

The cookie is set without a SameSite attribute. Modern browsers default to SameSite=Lax, but explicitly setting it improves cross-browser consistency and security posture.

🔒 Suggested fix
-      document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+      document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}; SameSite=Lax`
kits/automation/meeting-action-agent/components/ui/toast.tsx-73-89 (1)

73-89: ⚠️ Potential issue | 🟡 Minor

Add accessible label to the close button.

The ToastClose button contains only an icon (<X />) without any accessible text. Screen reader users won't know the button's purpose.

♿ Suggested fix
   >
     <X className="h-4 w-4" />
+    <span className="sr-only">Close</span>
   </ToastPrimitives.Close>
kits/automation/meeting-action-agent/components/ui/context-menu.tsx-114-135 (1)

114-135: ⚠️ Potential issue | 🟡 Minor

Fix malformed Tailwind selector syntax for destructive variant SVG styling.

Line 129 contains data-[variant=destructive]:*:[svg]:!text-destructive which is invalid Tailwind syntax. The *:[svg] portion doesn't match documented patterns for targeting SVG elements, and SVG elements don't have an svg attribute. Use the established pattern already throughout this file:

Suggested fix
-        "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
+        "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:[&_svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
🧹 Nitpick comments (26)
kits/automation/meeting-action-agent/hooks/use-mobile.ts (1)

10-11: Prefer mql.matches over window.innerWidth for consistency.

The media query listener is set up on mql, but the onChange handler checks window.innerWidth directly instead of using mql.matches. Using mql.matches is more idiomatic and ensures consistency with the media query definition.

♻️ Suggested improvement
   const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
-  const onChange = () => {
-    setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
-  }
+  const onChange = (e: MediaQueryListEvent | MediaQueryList) => {
+    setIsMobile(e.matches)
+  }
   mql.addEventListener('change', onChange)
-  setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
+  onChange(mql)
kits/automation/meeting-action-agent/components/ui/menubar.tsx (1)

91-162: Reduce repeated item utility classes to avoid style drift.

MenubarItem, MenubarCheckboxItem, and MenubarRadioItem repeat a lot of shared item styling. Extracting a shared base class would make future updates safer.

kits/automation/meeting-action-agent/components/ui/slider.tsx (2)

8-15: Forward ref to SliderPrimitive.Root for composability with parent consumers.

The component currently cannot be focused or measured by ref, limiting integration with parent components. Wrapping with React.forwardRef aligns with the official Radix UI composition patterns used in their documentation and third-party libraries like shadcn/ui.

Proposed ref-forwarding shape
-function Slider({
+const Slider = React.forwardRef<
+  React.ElementRef<typeof SliderPrimitive.Root>,
+  React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root>
+>(function Slider({
   className,
   defaultValue,
   value,
   min = 0,
   max = 100,
   ...props
-}: React.ComponentProps<typeof SliderPrimitive.Root>) {
+}, ref) {
...
     <SliderPrimitive.Root
+      ref={ref}
       data-slot="slider"
       defaultValue={defaultValue}
       value={value}
...
     </SliderPrimitive.Root>
   )
-}
+})
 
 export { Slider }

Also applies to: 27-38, 63-63


16-23: Default fallback forces 2 thumbs (range mode) instead of 1.

Line 22 defaults to [min, max] when neither value nor defaultValue is provided, and Line 52 renders one thumb per array element. This means the component renders two thumbs by default, which conflicts with @radix-ui/react-slider best practices—single-value sliders should default to a single-element array like [min] to render one thumb.

Proposed fix
   const _values = React.useMemo(
     () =>
       Array.isArray(value)
         ? value
         : Array.isArray(defaultValue)
           ? defaultValue
-          : [min, max],
+          : [min],
     [value, defaultValue, min, max],
   )
kits/automation/meeting-action-agent/flows/meeting-action-flow/meta.json (1)

1-9: Populate empty metadata fields before merging.

The description, tags, githubUrl, documentationUrl, and deployUrl fields are empty. Filling these in improves kit discoverability and provides users with relevant links and context.

kits/automation/meeting-action-agent/.gitignore (1)

19-20: Consider aligning .env pattern with root .gitignore.

The root .gitignore uses .env* to catch all environment file variants (.env.local, .env.development, etc.), while this uses .env (exact match only). Since the root already covers these, this is not a bug, but aligning patterns improves consistency.

Suggested change
 # env files
-.env
+.env*
kits/automation/meeting-action-agent/components/ui/input-otp.tsx (1)

69-73: Optional a11y polish: treat separator icon as decorative.

Consider marking the minus icon as non-announced so screen readers rely on the separator semantics only.

Suggested tweak
 function InputOTPSeparator({ ...props }: React.ComponentProps<'div'>) {
   return (
     <div data-slot="input-otp-separator" role="separator" {...props}>
-      <MinusIcon />
+      <MinusIcon aria-hidden="true" focusable="false" />
     </div>
   )
 }
kits/automation/meeting-action-agent/components/ui/toggle-group.tsx (1)

56-62: Optional: use ?? instead of || for fallback intent clarity.

Nullish coalescing better communicates that only null/undefined should fall back.

Suggested tweak
-      data-variant={context.variant || variant}
-      data-size={context.size || size}
+      data-variant={context.variant ?? variant}
+      data-size={context.size ?? size}
       className={cn(
         toggleVariants({
-          variant: context.variant || variant,
-          size: context.size || size,
+          variant: context.variant ?? variant,
+          size: context.size ?? size,
         }),
kits/automation/meeting-action-agent/components/ui/hover-card.tsx (1)

29-29: data-slot on Portal has no effect.

HoverCardPrimitive.Portal is a React utility component that creates a React portal; it doesn't render a DOM element itself. The data-slot="hover-card-portal" attribute will be silently ignored and won't appear in the DOM.

🧹 Proposed fix: remove the ineffective attribute
-    <HoverCardPrimitive.Portal data-slot="hover-card-portal">
+    <HoverCardPrimitive.Portal>
kits/automation/meeting-action-agent/components/ui/tooltip.tsx (1)

13-17: data-slot on Provider has no effect.

TooltipPrimitive.Provider is a React context provider, not a DOM element. The data-slot attribute won't appear in the rendered output.

🧹 Proposed fix: remove the ineffective attribute
-    <TooltipPrimitive.Provider
-      data-slot="tooltip-provider"
-      delayDuration={delayDuration}
+    <TooltipPrimitive.Provider delayDuration={delayDuration}
       {...props}
     />
kits/automation/meeting-action-agent/components/ui/calendar.tsx (1)

175-211: Consider memoizing or hoisting getDefaultClassNames() call.

getDefaultClassNames() is called inside CalendarDayButton, which means it runs for every day cell rendered (typically 28-42 cells per calendar). While the performance impact is likely negligible, you could hoist this outside the component or memoize it for cleanliness.

♻️ Proposed optimization
+const defaultDayClassNames = getDefaultClassNames()
+
 function CalendarDayButton({
   className,
   day,
   modifiers,
   ...props
 }: React.ComponentProps<typeof DayButton>) {
-  const defaultClassNames = getDefaultClassNames()
 
   const ref = React.useRef<HTMLButtonElement>(null)
   React.useEffect(() => {
     if (modifiers.focused) ref.current?.focus()
   }, [modifiers.focused])
 
   return (
     <Button
       ref={ref}
       variant="ghost"
       size="icon"
       // ... other props
       className={cn(
         'data-[selected-single=true]:bg-primary ...',
-        defaultClassNames.day,
+        defaultDayClassNames.day,
         className,
       )}
       {...props}
     />
   )
 }
kits/automation/meeting-action-agent/components/ui/table.tsx (1)

1-1: 'use client' may be unnecessary.

These table components only render HTML elements with Tailwind classes — no hooks, event handlers, or browser APIs are used. Removing the directive would allow them to be server components, reducing client bundle size.

♻️ Proposed change
-'use client'
-
 import * as React from 'react'
kits/automation/meeting-action-agent/components/ui/pagination.tsx (1)

9-9: Remove unused Button import.

Button is imported but never used in this file; only buttonVariants is used for styling PaginationLink.

🧹 Proposed fix
-import { Button, buttonVariants } from '@/components/ui/button'
+import { buttonVariants } from '@/components/ui/button'
kits/automation/meeting-action-agent/lib/lamatic-client.ts (2)

3-7: Consider separating flow ID validation from client initialization.

MEETING_ACTION_FLOW_ID is not used in this module—it's consumed by orchestrate.ts. Validating it here creates tight coupling and may cause unnecessary startup failures if this module is imported in contexts that don't need the flow ID.


15-19: Remove redundant fallback values and fix type mismatch.

The environment variables are validated on lines 9-13, making the fallback values on lines 16-18 unreachable. Additionally, projectId: null violates the Lamatic constructor requirement that projectId be a string, not null.

♻️ Proposed fix: Use non-null assertions
 export const lamaticClient = new Lamatic({
-  endpoint: process.env.LAMATIC_API_URL ?? "",
-  projectId: process.env.LAMATIC_PROJECT_ID ?? null,
-  apiKey: process.env.LAMATIC_API_KEY ?? "",
+  endpoint: process.env.LAMATIC_API_URL!,
+  projectId: process.env.LAMATIC_PROJECT_ID!,
+  apiKey: process.env.LAMATIC_API_KEY!,
 })
kits/automation/meeting-action-agent/flows/meeting-action-flow/README.md (1)

56-58: Consider hyperlinking the documentation URL.

The reference to docs.lamatic.ai could be more accessible as a proper hyperlink.

📝 Suggested improvement
-- Check the Lamatic documentation at docs.lamatic.ai
+- Check the Lamatic documentation at [docs.lamatic.ai](https://docs.lamatic.ai)
kits/automation/meeting-action-agent/tsconfig.json (1)

7-7: Consider enabling strict mode for better type safety.

strict: false disables important TypeScript checks like strictNullChecks, noImplicitAny, and strictFunctionTypes. Enabling strict mode helps catch potential runtime errors at compile time.

kits/automation/meeting-action-agent/app/layout.tsx (1)

6-7: Initialized fonts are not applied to rendered elements.

_geist and _geistMono are configured but their CSS variable classes (e.g., _geist.variable) are not applied to the <html> or <body>. The body currently uses a hardcoded font-sans class. Either apply the font variables or remove the unused imports to avoid loading unnecessary font files.

♻️ Proposed fix to apply font variables
-const _geist = Geist({ subsets: ["latin"] });
-const _geistMono = Geist_Mono({ subsets: ["latin"] });
+const geist = Geist({ subsets: ["latin"], variable: "--font-geist-sans" });
+const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-geist-mono" });
-    <html lang="en" suppressHydrationWarning>
-      <body className={`font-sans antialiased`} suppressHydrationWarning>
+    <html lang="en" suppressHydrationWarning className={`${geist.variable} ${geistMono.variable}`}>
+      <body className={`font-sans antialiased`} suppressHydrationWarning>

Also applies to: 22-22

kits/automation/meeting-action-agent/README.md (1)

22-32: Add language specifiers to fenced code blocks.

Per static analysis (MD040), the architecture diagram (line 22) and project structure (line 105) code blocks should have a language specified. Use text or plaintext for these blocks.

📝 Proposed fix

Line 22:

-```
+```text
 User (pastes meeting notes)

Line 105:

-```
+```text
 kits/automation/meeting-action-agent/

Also applies to: 105-123

kits/automation/meeting-action-agent/config.json (1)

5-8: Consider using a real contact email.

The author email harish@example.com appears to be a placeholder. If this kit will be published, consider using an actual contact email or removing the email field if not required.

kits/automation/meeting-action-agent/app/page.tsx (2)

111-118: Duplicated priority normalization logic.

The priority normalization logic here duplicates normalizePriority() in orchestrate.ts. Since orchestrate.ts already normalizes priorities server-side, this client-side fallback handling for rawResult could import a shared utility or rely on the server's normalization.


91-91: Remove or reduce console.log in production.

This console.log will output full response data in production. Consider removing it or guarding it with a development-only check.

kits/automation/meeting-action-agent/flows/meeting-action-flow/config.json (1)

59-61: Hardcoded credential ID may not be portable.

The credentialId is environment-specific. Users importing this flow will need to update it with their own credential. Consider documenting this in the flow's README or using a placeholder value with clear instructions.

kits/automation/meeting-action-agent/components/ui/use-toast.ts (1)

174-182: useEffect dependency array should be empty.

The effect registers a listener on mount and cleans up on unmount. Including state as a dependency causes unnecessary re-registration on every state update. While the cleanup prevents duplicates, this is inefficient.

♻️ Proposed fix
   React.useEffect(() => {
     listeners.push(setState)
     return () => {
       const index = listeners.indexOf(setState)
       if (index > -1) {
         listeners.splice(index, 1)
       }
     }
-  }, [state])
+  }, [])
kits/automation/meeting-action-agent/actions/orchestrate.ts (1)

54-57: Consider removing or gating debug logs for production.

These console.log statements will output full SDK responses and parsed data in production. Consider removing them or using a debug flag.

kits/automation/meeting-action-agent/components/ui/field.tsx (1)

128-139: Duplicate data-slot value may cause selector ambiguity.

FieldTitle uses data-slot="field-label" (Line 131), which is the same value used by FieldLabel (Line 116). This could cause unintended style matches or confusing behavior when CSS selectors target [data-slot=field-label].

Consider using a distinct slot name like data-slot="field-title" for clarity.

💡 Suggested fix
 function FieldTitle({ className, ...props }: React.ComponentProps<'div'>) {
   return (
     <div
-      data-slot="field-label"
+      data-slot="field-title"
       className={cn(

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d65d144b-424d-4b09-ad47-945b4e97f480

📥 Commits

Reviewing files that changed from the base of the PR and between e1ceb47 and d9e7781.

⛔ Files ignored due to path filters (1)
  • kits/automation/meeting-action-agent/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (80)
  • .gitignore
  • kits/automation/meeting-action-agent/.gitignore
  • kits/automation/meeting-action-agent/README.md
  • kits/automation/meeting-action-agent/actions/orchestrate.ts
  • kits/automation/meeting-action-agent/app/globals.css
  • kits/automation/meeting-action-agent/app/layout.tsx
  • kits/automation/meeting-action-agent/app/page.tsx
  • kits/automation/meeting-action-agent/components.json
  • kits/automation/meeting-action-agent/components/header.tsx
  • kits/automation/meeting-action-agent/components/theme-provider.tsx
  • kits/automation/meeting-action-agent/components/ui/accordion.tsx
  • kits/automation/meeting-action-agent/components/ui/alert-dialog.tsx
  • kits/automation/meeting-action-agent/components/ui/alert.tsx
  • kits/automation/meeting-action-agent/components/ui/aspect-ratio.tsx
  • kits/automation/meeting-action-agent/components/ui/avatar.tsx
  • kits/automation/meeting-action-agent/components/ui/badge.tsx
  • kits/automation/meeting-action-agent/components/ui/breadcrumb.tsx
  • kits/automation/meeting-action-agent/components/ui/button-group.tsx
  • kits/automation/meeting-action-agent/components/ui/button.tsx
  • kits/automation/meeting-action-agent/components/ui/calendar.tsx
  • kits/automation/meeting-action-agent/components/ui/card.tsx
  • kits/automation/meeting-action-agent/components/ui/carousel.tsx
  • kits/automation/meeting-action-agent/components/ui/chart.tsx
  • kits/automation/meeting-action-agent/components/ui/checkbox.tsx
  • kits/automation/meeting-action-agent/components/ui/collapsible.tsx
  • kits/automation/meeting-action-agent/components/ui/command.tsx
  • kits/automation/meeting-action-agent/components/ui/context-menu.tsx
  • kits/automation/meeting-action-agent/components/ui/dialog.tsx
  • kits/automation/meeting-action-agent/components/ui/drawer.tsx
  • kits/automation/meeting-action-agent/components/ui/dropdown-menu.tsx
  • kits/automation/meeting-action-agent/components/ui/empty.tsx
  • kits/automation/meeting-action-agent/components/ui/field.tsx
  • kits/automation/meeting-action-agent/components/ui/form.tsx
  • kits/automation/meeting-action-agent/components/ui/hover-card.tsx
  • kits/automation/meeting-action-agent/components/ui/input-group.tsx
  • kits/automation/meeting-action-agent/components/ui/input-otp.tsx
  • kits/automation/meeting-action-agent/components/ui/input.tsx
  • kits/automation/meeting-action-agent/components/ui/item.tsx
  • kits/automation/meeting-action-agent/components/ui/kbd.tsx
  • kits/automation/meeting-action-agent/components/ui/label.tsx
  • kits/automation/meeting-action-agent/components/ui/menubar.tsx
  • kits/automation/meeting-action-agent/components/ui/navigation-menu.tsx
  • kits/automation/meeting-action-agent/components/ui/pagination.tsx
  • kits/automation/meeting-action-agent/components/ui/popover.tsx
  • kits/automation/meeting-action-agent/components/ui/progress.tsx
  • kits/automation/meeting-action-agent/components/ui/radio-group.tsx
  • kits/automation/meeting-action-agent/components/ui/resizable.tsx
  • kits/automation/meeting-action-agent/components/ui/scroll-area.tsx
  • kits/automation/meeting-action-agent/components/ui/select.tsx
  • kits/automation/meeting-action-agent/components/ui/separator.tsx
  • kits/automation/meeting-action-agent/components/ui/sheet.tsx
  • kits/automation/meeting-action-agent/components/ui/sidebar.tsx
  • kits/automation/meeting-action-agent/components/ui/skeleton.tsx
  • kits/automation/meeting-action-agent/components/ui/slider.tsx
  • kits/automation/meeting-action-agent/components/ui/sonner.tsx
  • kits/automation/meeting-action-agent/components/ui/spinner.tsx
  • kits/automation/meeting-action-agent/components/ui/switch.tsx
  • kits/automation/meeting-action-agent/components/ui/table.tsx
  • kits/automation/meeting-action-agent/components/ui/tabs.tsx
  • kits/automation/meeting-action-agent/components/ui/textarea.tsx
  • kits/automation/meeting-action-agent/components/ui/toast.tsx
  • kits/automation/meeting-action-agent/components/ui/toaster.tsx
  • kits/automation/meeting-action-agent/components/ui/toggle-group.tsx
  • kits/automation/meeting-action-agent/components/ui/toggle.tsx
  • kits/automation/meeting-action-agent/components/ui/tooltip.tsx
  • kits/automation/meeting-action-agent/components/ui/use-mobile.tsx
  • kits/automation/meeting-action-agent/components/ui/use-toast.ts
  • kits/automation/meeting-action-agent/config.json
  • kits/automation/meeting-action-agent/flows/meeting-action-flow/README.md
  • kits/automation/meeting-action-agent/flows/meeting-action-flow/config.json
  • kits/automation/meeting-action-agent/flows/meeting-action-flow/inputs.json
  • kits/automation/meeting-action-agent/flows/meeting-action-flow/meta.json
  • kits/automation/meeting-action-agent/hooks/use-mobile.ts
  • kits/automation/meeting-action-agent/hooks/use-toast.ts
  • kits/automation/meeting-action-agent/lib/lamatic-client.ts
  • kits/automation/meeting-action-agent/lib/utils.ts
  • kits/automation/meeting-action-agent/next.config.mjs
  • kits/automation/meeting-action-agent/package.json
  • kits/automation/meeting-action-agent/postcss.config.mjs
  • kits/automation/meeting-action-agent/tsconfig.json

Comment on lines +39 to +56
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<'button'> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'button'

return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Set a safe default button type to avoid accidental form submits.

When asChild is false, this renders a native <button> without type; default behavior is submit, which can trigger unintended submissions in forms.

🔧 Proposed fix
 function Button({
   className,
   variant,
   size,
   asChild = false,
+  type,
   ...props
 }: React.ComponentProps<'button'> &
   VariantProps<typeof buttonVariants> & {
     asChild?: boolean
   }) {
   const Comp = asChild ? Slot : 'button'
 
   return (
     <Comp
       data-slot="button"
       className={cn(buttonVariants({ variant, size, className }))}
+      {...(!asChild ? { type: type ?? 'button' } : {})}
       {...props}
     />
   )
 }
📝 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
function Button({
className,
variant,
size,
asChild = false,
...props
}: React.ComponentProps<'button'> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'button'
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
function Button({
className,
variant,
size,
asChild = false,
type,
...props
}: React.ComponentProps<'button'> &
VariantProps<typeof buttonVariants> & {
asChild?: boolean
}) {
const Comp = asChild ? Slot : 'button'
return (
<Comp
data-slot="button"
className={cn(buttonVariants({ variant, size, className }))}
{...(!asChild ? { type: type ?? 'button' } : {})}
{...props}
/>
)
}

Comment on lines +82 to +100
<style
dangerouslySetInnerHTML={{
__html: Object.entries(THEMES)
.map(
([theme, prefix]) => `
${prefix} [data-chart=${id}] {
${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
itemConfig.color
return color ? ` --color-${key}: ${color};` : null
})
.join('\n')}
}
`,
)
.join('\n'),
}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n kits/automation/meeting-action-agent/components/ui/chart.tsx | head -150

Repository: Lamatic/AgentKit

Length of output: 5168


🏁 Script executed:

cat -n kits/automation/meeting-action-agent/components/ui/chart.tsx | sed -n '150,300p'

Repository: Lamatic/AgentKit

Length of output: 5740


🏁 Script executed:

cat -n kits/automation/meeting-action-agent/components/ui/chart.tsx | tail -50

Repository: Lamatic/AgentKit

Length of output: 1487


🏁 Script executed:

# Search for ChartContainer usage to understand how id prop is used
rg -A 3 'ChartContainer' kits/automation/meeting-action-agent --type tsx --type ts

Repository: Lamatic/AgentKit

Length of output: 87


🏁 Script executed:

rg -A 3 'ChartContainer' kits/automation/meeting-action-agent

Repository: Lamatic/AgentKit

Length of output: 1021


🏁 Script executed:

# Find usage of ChartContainer in the codebase
find kits/automation/meeting-action-agent -type f -name '*.jsx' -o -name '*.js' -o -name '*.ts' -o -name '*.tsx' | xargs grep -l 'ChartContainer' | head -5

Repository: Lamatic/AgentKit

Length of output: 120


🏁 Script executed:

# Search for ChartContainer imports/usage in the entire repo
rg 'ChartContainer' --max-count 20

Repository: Lamatic/AgentKit

Length of output: 2432


🏁 Script executed:

# Search for actual usage/instantiation of ChartContainer with id prop
rg -B 2 -A 5 '<ChartContainer' kits/automation/meeting-action-agent | head -40

Repository: Lamatic/AgentKit

Length of output: 664


🏁 Script executed:

# Search for ChartContainer usage in pages or demo components
rg -B 2 -A 5 'ChartContainer\s*[<{]' kits/automation/meeting-action-agent

Repository: Lamatic/AgentKit

Length of output: 42


🏁 Script executed:

# Look for imports of ChartContainer in actual component files
rg 'import.*ChartContainer' kits/automation/meeting-action-agent

Repository: Lamatic/AgentKit

Length of output: 42


🏁 Script executed:

# Check if there are any actual component files using ChartContainer
find kits -type f -name '*.jsx' -o -name '*.tsx' | xargs grep -l 'from.*chart' | head -10

Repository: Lamatic/AgentKit

Length of output: 499


🏁 Script executed:

# Search for JSX usage of ChartContainer across entire repo
rg '<ChartContainer' kits/

Repository: Lamatic/AgentKit

Length of output: 1156


🏁 Script executed:

# Search across all kit directories for actual ChartContainer instantiations
find kits -type f \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) -exec grep -l 'ChartContainer' {} \; | xargs grep -B 3 -A 8 'id=' | head -60

Repository: Lamatic/AgentKit

Length of output: 4208


🏁 Script executed:

# Verify the complete flow: check line 50 to see how id is constructed
sed -n '37,70p' kits/automation/meeting-action-agent/components/ui/chart.tsx

Repository: Lamatic/AgentKit

Length of output: 1499


🏁 Script executed:

# Check how ChartConfig is actually used in practice
find kits/automation/meeting-action-agent -type f \( -name '*.js' -o -name '*.jsx' -o -name '*.ts' -o -name '*.tsx' \) ! -name 'chart.tsx' | xargs grep -l 'ChartConfig\|chartConfig' | head -5

Repository: Lamatic/AgentKit

Length of output: 42


Sanitize or validate chart CSS generation to prevent style-tag injection.

The id, config keys, and color values are interpolated directly into a <style> tag via dangerouslySetInnerHTML without escaping (lines 82–100). If id (passed as a prop at line 50) or config keys/colors ever become user-controlled, a crafted value like test"]; } * { background: red; would break the CSS selector and inject arbitrary rules. Either sanitize these values using CSS property escaping, escape the id for use in an attribute selector, or document and enforce that id and config must only come from internal/trusted sources.

🧰 Tools
🪛 ast-grep (0.41.1)

[warning] 82-82: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

Comment on lines +14 to +26
<ProgressPrimitive.Root
data-slot="progress"
className={cn(
'bg-primary/20 relative h-2 w-full overflow-hidden rounded-full',
className,
)}
{...props}
>
<ProgressPrimitive.Indicator
data-slot="progress-indicator"
className="bg-primary h-full w-full flex-1 transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In @radix-ui/react-progress, does <Progress.Root value={...}> control aria-valuenow/data-state, and is value expected to be clamped within [0, max]?

💡 Result:

Yes, the <Progress.Root value={...}> prop controls both aria-valuenow and data-state attributes. The value prop sets aria-valuenow to the clamped value (bounded within [0, max]) and determines data-state ("complete" if value >= max, "loading" otherwise when value is defined). aria-valuemax is set to the max prop (default 100). Value is expected to be clamped: the component internally clamps it with Math.min(Math.max(value || 0, 0), max).

Citations:


🏁 Script executed:

cd kits/automation/meeting-action-agent && find . -name "progress.tsx" -type f

Repository: Lamatic/AgentKit

Length of output: 88


🏁 Script executed:

cat -n kits/automation/meeting-action-agent/components/ui/progress.tsx

Repository: Lamatic/AgentKit

Length of output: 1017


Pass value into ProgressPrimitive.Root (currently omitted).

value is destructured and used for visual transform (line 25) but never forwarded to ProgressPrimitive.Root (lines 14–20). This desynchronizes visual progress from Radix's ARIA metadata (aria-valuenow, data-state) and prevents Radix from properly clamping the value.

🔧 Proposed fix
 function Progress({
   className,
   value,
   ...props
 }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
+  const normalizedValue =
+    typeof value === 'number' ? Math.min(100, Math.max(0, value)) : undefined
+
   return (
     <ProgressPrimitive.Root
       data-slot="progress"
+      value={normalizedValue}
       className={cn(
         'bg-primary/20 relative h-2 w-full overflow-hidden rounded-full',
         className,
       )}
       {...props}
     >
       <ProgressPrimitive.Indicator
         data-slot="progress-indicator"
         className="bg-primary h-full w-full flex-1 transition-all"
-        style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
+        style={{ transform: `translateX(-${100 - (normalizedValue ?? 0)}%)` }}
       />
     </ProgressPrimitive.Root>
   )
 }

Comment on lines +1 to +19
import * as React from 'react'

const MOBILE_BREAKPOINT = 768

export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)

React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener('change', onChange)
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
return () => mql.removeEventListener('change', onChange)
}, [])

return !!isMobile
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify the duplicate files and check for usages of each

echo "=== Comparing the two files ==="
diff kits/automation/meeting-action-agent/hooks/use-mobile.ts kits/automation/meeting-action-agent/components/ui/use-mobile.tsx

echo ""
echo "=== Finding imports of hooks/use-mobile ==="
rg -n "from.*hooks/use-mobile" kits/automation/meeting-action-agent/

echo ""
echo "=== Finding imports of components/ui/use-mobile ==="
rg -n "from.*components/ui/use-mobile" kits/automation/meeting-action-agent/

Repository: Lamatic/AgentKit

Length of output: 303


🏁 Script executed:

#!/bin/bash
# Verify if the files actually exist
echo "=== Checking if hooks/use-mobile.ts exists ==="
ls -la kits/automation/meeting-action-agent/hooks/use-mobile.ts 2>&1

echo ""
echo "=== Checking if components/ui/use-mobile.tsx exists ==="
ls -la kits/automation/meeting-action-agent/components/ui/use-mobile.tsx 2>&1

echo ""
echo "=== Listing all use-mobile files in the codebase ==="
find . -name "*use-mobile*" -type f 2>/dev/null

echo ""
echo "=== Checking hooks directory ==="
ls -la kits/automation/meeting-action-agent/hooks/ 2>&1

echo ""
echo "=== Checking components/ui directory ==="
ls -la kits/automation/meeting-action-agent/components/ui/ 2>&1

Repository: Lamatic/AgentKit

Length of output: 5296


🏁 Script executed:

#!/bin/bash
# Compare the actual content of both files
echo "=== Content of hooks/use-mobile.ts ==="
cat kits/automation/meeting-action-agent/hooks/use-mobile.ts

echo ""
echo "=== Content of components/ui/use-mobile.tsx ==="
cat kits/automation/meeting-action-agent/components/ui/use-mobile.tsx

echo ""
echo "=== Checking if components/ui/use-mobile is imported anywhere in the entire codebase ==="
rg -n "use-mobile" --type ts --type tsx | grep -E "(from|import)" | head -20

Repository: Lamatic/AgentKit

Length of output: 1412


🏁 Script executed:

#!/bin/bash
# Search for all imports of use-mobile more broadly
echo "=== All imports mentioning use-mobile ==="
rg "from.*use-mobile" --max-count=30

echo ""
echo "=== Specifically checking for components/ui/use-mobile imports ==="
rg "components/ui/use-mobile" --max-count=20

Repository: Lamatic/AgentKit

Length of output: 1068


Consolidate duplicate useIsMobile hook—components/ui/use-mobile.tsx is unused.

Both hooks/use-mobile.ts and components/ui/use-mobile.tsx contain identical code. All imports across the codebase use @/hooks/use-mobile, making the copy in components/ui/ dead code. Remove the duplicate from components/ui/ to maintain a single source of truth.

Comment on lines +174 to +182
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [state])
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Incorrect useEffect dependency causes unnecessary re-registrations.

The dependency array [state] causes the listener to be unregistered and re-registered on every state change. Since setState is a stable reference and the effect is purely for subscription setup/teardown, the dependency array should be empty.

🐛 Proposed fix
   React.useEffect(() => {
     listeners.push(setState)
     return () => {
       const index = listeners.indexOf(setState)
       if (index > -1) {
         listeners.splice(index, 1)
       }
     }
-  }, [state])
+  }, [])
📝 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
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [state])
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [])

Comment on lines +34 to +39
"@vercel/analytics": "latest",
"autoprefixer": "^10.4.20",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"geist": "latest",
"lamatic": "latest",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check current latest versions for these packages

curl -s https://registry.npmjs.org/@vercel/analytics/latest | jq '.version'
curl -s https://registry.npmjs.org/geist/latest | jq '.version'
curl -s https://registry.npmjs.org/lamatic/latest | jq '.version'

Repository: Lamatic/AgentKit

Length of output: 83


🏁 Script executed:

cat -n kits/automation/meeting-action-agent/package.json | head -50

Repository: Lamatic/AgentKit

Length of output: 1969


Avoid using latest tag for production dependencies.

Using latest for @vercel/analytics, geist, and lamatic prevents reproducible builds and risks unexpected breaking changes when versions update. Pin these to specific versions instead: @vercel/analytics@2.0.1, geist@1.7.0, and lamatic@0.3.2.

"@radix-ui/react-toast": "1.2.4",
"@radix-ui/react-tooltip": "1.1.6",
"@vercel/analytics": "latest",
"autoprefixer": "^10.4.20",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Move autoprefixer to devDependencies.

autoprefixer is a PostCSS plugin used only during the build process and should not be a runtime dependency.

♻️ Proposed fix
   "dependencies": {
     "@hookform/resolvers": "^3.10.0",
     ...
-    "autoprefixer": "^10.4.20",
     ...
   },
   "devDependencies": {
+    "autoprefixer": "^10.4.20",
     "@tailwindcss/postcss": "^4.1.9",

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
kits/automation/meeting-action-agent/.env.example (2)

1-4: Consider removing quotes from .env values.

The double quotes around the placeholder values are unnecessary in .env files and can potentially cause confusion. Most .env parsers handle unquoted values correctly, and quotes are only needed when values contain spaces or special characters.

♻️ Proposed refactor to remove quotes
-MEETING_ACTION_FLOW_ID="your-flow-id-here"
-LAMATIC_API_URL="https://your-org.lamatic.dev/graphql"
-LAMATIC_PROJECT_ID="your-project-id-here"
-LAMATIC_API_KEY="your-api-key-here"
+MEETING_ACTION_FLOW_ID=your-flow-id-here
+LAMATIC_API_URL=https://your-org.lamatic.dev/graphql
+LAMATIC_PROJECT_ID=your-project-id-here
+LAMATIC_API_KEY=your-api-key-here

4-4: Add trailing newline at end of file.

It's a common convention to end files with a blank line, which can help with version control diffs and text processing tools.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c65b33d-320f-4676-91b0-8a53a29ab737

📥 Commits

Reviewing files that changed from the base of the PR and between d9e7781 and 60510ff.

📒 Files selected for processing (1)
  • kits/automation/meeting-action-agent/.env.example

@harishghasolia07 harishghasolia07 marked this pull request as draft March 22, 2026 18:54
@harishghasolia07 harishghasolia07 deleted the meeting-action-agent branch March 22, 2026 18:57
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