-
Notifications
You must be signed in to change notification settings - Fork 0
agent: @U0AJM7X8FBR Admin + Docs + API - we want a new admin page to view analy #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0b24941
f3622d2
b59e000
75c80cd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| import type { Metadata } from "next"; | ||
| import CodingAgentSlackTagsPage from "@/components/CodingAgentSlackTags/CodingAgentSlackTagsPage"; | ||
|
|
||
| export const metadata: Metadata = { | ||
| title: "Coding Agent Slack Tags — Recoup Admin", | ||
| }; | ||
|
|
||
| export default function Page() { | ||
| return <CodingAgentSlackTagsPage />; | ||
| } | ||
|
Comment on lines
+8
to
+10
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate admin-guard patterns used by this route/component stack.
rg -n -C3 'useIsAdmin|isAdmin|admins/check|redirect\(|notFound\(' --type=ts --type=tsx
rg -n -C3 'CodingAgentSlackTagsPage' --type=ts --type=tsxRepository: recoupable/admin Length of output: 87 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Fix: remove unsupported file type, search all files with TS/TSX extensions
echo "=== Searching for admin/auth guard patterns ==="
rg -n -C3 'useIsAdmin|isAdmin|admins/check|redirect\(|notFound\(' \
--glob='*.ts' --glob='*.tsx'
echo ""
echo "=== Searching for CodingAgentSlackTagsPage ==="
rg -n 'CodingAgentSlackTagsPage' --glob='*.ts' --glob='*.tsx'
echo ""
echo "=== Checking the target file ==="
if [ -f "app/coding-agent/page.tsx" ]; then
cat -n "app/coding-agent/page.tsx"
else
echo "File not found, searching for similar files..."
find . -name "*coding-agent*" -type f 2>/dev/null | head -20
fiRepository: recoupable/admin Length of output: 3787 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Read the CodingAgentSlackTagsPage component
echo "=== CodingAgentSlackTagsPage component ==="
cat -n "components/CodingAgentSlackTags/CodingAgentSlackTagsPage.tsx"
echo ""
echo "=== Check for middleware in app directory ==="
find app -name "middleware*" -type f 2>/dev/null || echo "No middleware files found in app"
echo ""
echo "=== Check for route.ts or layout.tsx in coding-agent ==="
ls -la app/coding-agent/ 2>/dev/null || echo "Directory listing failed"Repository: recoupable/admin Length of output: 3657 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check for middleware at root level
echo "=== Looking for middleware.ts at repository root ==="
find . -maxdepth 1 -name "middleware.ts" -o -name "middleware.js" 2>/dev/null || echo "No root middleware found"
echo ""
echo "=== Check for app directory layout.tsx ==="
if [ -f "app/layout.tsx" ]; then
head -50 app/layout.tsx
else
echo "No app/layout.tsx found"
fi
echo ""
echo "=== Compare with HomeContent pattern (which has proper admin check) ==="
grep -A 15 "const { data: isAdmin" components/Home/HomeContent.tsxRepository: recoupable/admin Length of output: 1853 Add admin authorization check to this component.
Currently the page renders without any authorization verification, allowing non-admin authenticated users to access admin-only data. 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| "use client"; | ||
|
|
||
| import { useState } from "react"; | ||
| import PageBreadcrumb from "@/components/Sandboxes/PageBreadcrumb"; | ||
| import ApiDocsLink from "@/components/ApiDocs/ApiDocsLink"; | ||
| import { useSlackTags } from "@/hooks/useSlackTags"; | ||
| import SlackTagsTable from "./SlackTagsTable"; | ||
| import AdminLineChart from "@/components/Admin/AdminLineChart"; | ||
| import { getTagsByDate } from "@/lib/coding-agent/getTagsByDate"; | ||
| import PeriodSelector from "@/components/Admin/PeriodSelector"; | ||
| import TableSkeleton from "@/components/Sandboxes/TableSkeleton"; | ||
| import ChartSkeleton from "@/components/PrivyLogins/ChartSkeleton"; | ||
| import type { AdminPeriod } from "@/types/admin"; | ||
|
|
||
| export default function CodingAgentSlackTagsPage() { | ||
| const [period, setPeriod] = useState<AdminPeriod>("all"); | ||
| const { data, isLoading, error } = useSlackTags(period); | ||
|
|
||
| return ( | ||
| <main className="mx-auto max-w-6xl px-4 py-10"> | ||
| <div className="mb-6 flex items-start justify-between"> | ||
| <div> | ||
| <PageBreadcrumb current="Coding Agent Tags" /> | ||
| <h1 className="text-2xl font-bold tracking-tight text-gray-900 dark:text-gray-100"> | ||
| Coding Agent Slack Tags | ||
| </h1> | ||
| <p className="mt-1 text-sm text-gray-500 dark:text-gray-400"> | ||
| Slack mentions of the Recoup Coding Agent, pulled directly from the Slack API. | ||
| </p> | ||
| </div> | ||
| <ApiDocsLink path="admins/coding-agent-slack-tags" /> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "1) ApiDocsLink implementation:"
fd 'ApiDocsLink.tsx' --exec sed -n '1,220p' {}
echo
echo "2) All ApiDocsLink path usages:"
rg -nP --type=tsx -C1 'ApiDocsLink\s+path='
echo
echo "3) Coding Slack-related route/path strings:"
rg -n -C2 'coding-agent-slack-tags|admins/coding/slack|/api/admins/coding/slack|/api/admins/coding'Repository: recoupable/admin Length of output: 539 🏁 Script executed: rg 'ApiDocsLink.*path=' --type-listRepository: recoupable/admin Length of output: 449 🏁 Script executed: rg 'ApiDocsLink.*path=' -A1 -B1Repository: recoupable/admin Length of output: 1197 🏁 Script executed: rg 'coding-agent-slack-tags|coding.*slack|admins/coding' -iRepository: recoupable/admin Length of output: 1101 🏁 Script executed: fd -e tsx -e ts | head -20Repository: recoupable/admin Length of output: 817 Update On Line 30, the path 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not applicable — ApiDocsLink path references the Mintlify docs page filename (admins/coding-agent-slack-tags.mdx), not the API endpoint path. The docs page is correctly named coding-agent-slack-tags.mdx. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
✏️ Learnings added
|
||
| </div> | ||
|
|
||
| <div className="mb-6 flex items-center gap-4"> | ||
| <PeriodSelector period={period} onPeriodChange={setPeriod} /> | ||
| {data && ( | ||
| <div className="text-sm text-gray-600 dark:text-gray-400"> | ||
| <span className="font-semibold text-gray-900 dark:text-gray-100">{data.total}</span>{" "} | ||
| {data.total === 1 ? "tag" : "tags"} found | ||
| </div> | ||
| )} | ||
| </div> | ||
|
|
||
| {isLoading && ( | ||
| <> | ||
| <ChartSkeleton /> | ||
| <TableSkeleton columns={["Tagged By", "Prompt", "Channel", "Timestamp"]} /> | ||
| </> | ||
| )} | ||
|
|
||
| {error && ( | ||
| <div className="rounded-md bg-red-50 p-4 text-sm text-red-700 dark:bg-red-900/20 dark:text-red-400"> | ||
| {error instanceof Error ? error.message : "Failed to load Slack tags"} | ||
| </div> | ||
| )} | ||
|
|
||
| {!isLoading && !error && data && data.tags.length === 0 && ( | ||
| <div className="flex items-center justify-center py-12 text-sm text-gray-400"> | ||
| No tags found for this period. | ||
| </div> | ||
| )} | ||
|
|
||
| {!isLoading && !error && data && data.tags.length > 0 && ( | ||
| <> | ||
| <AdminLineChart title="Tags Over Time" data={getTagsByDate(data.tags)} label="Tags" /> | ||
| <SlackTagsTable tags={data.tags} /> | ||
| </> | ||
| )} | ||
| </main> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { type ColumnDef } from "@tanstack/react-table"; | ||
| import { SortableHeader } from "@/components/SandboxOrgs/SortableHeader"; | ||
| import type { SlackTag } from "@/types/coding-agent"; | ||
|
|
||
| export const slackTagsColumns: ColumnDef<SlackTag>[] = [ | ||
| { | ||
| id: "user_name", | ||
| accessorKey: "user_name", | ||
| header: "Tagged By", | ||
| cell: ({ row }) => { | ||
| const tag = row.original; | ||
| return ( | ||
| <div className="flex items-center gap-2"> | ||
| {tag.user_avatar && ( | ||
| <img | ||
|
Check warning on line 15 in components/CodingAgentSlackTags/SlackTagsColumns.tsx
|
||
| src={tag.user_avatar} | ||
| alt={tag.user_name} | ||
| className="h-6 w-6 rounded-full" | ||
| /> | ||
|
Comment on lines
+15
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify image configuration for external avatar hosts before switching to next/image.
for f in $(fd 'next.config.*'); do
echo "== $f =="
sed -n '1,240p' "$f"
doneRepository: recoupable/admin Length of output: 184 🏁 Script executed: cat -n components/CodingAgentSlackTags/SlackTagsColumns.tsx | head -50Repository: recoupable/admin Length of output: 1853 🏁 Script executed: fd '.eslintrc*' -o 'eslint.config.*'Repository: recoupable/admin Length of output: 209 🏁 Script executed: rg 'user_avatar' --type tsx --type ts -B 3 -A 3Repository: recoupable/admin Length of output: 87 🏁 Script executed: fd -t f '\.(eslintrc|eslintrc\.js|eslintrc\.json|eslintrc\.yml|eslintrc\.yaml)$'Repository: recoupable/admin Length of output: 42 🏁 Script executed: fd 'coding-agent' -t fRepository: recoupable/admin Length of output: 81 🏁 Script executed: rg 'interface SlackTag|type SlackTag' -A 5Repository: recoupable/admin Length of output: 1618 🏁 Script executed: cat package.json | head -80Repository: recoupable/admin Length of output: 879 🏁 Script executed: rg '@next/next' -A 2 -B 2Repository: recoupable/admin Length of output: 42 🏁 Script executed: rg 'no-img-element' -rRepository: recoupable/admin Length of output: 473 🏁 Script executed: fd -H '\.eslintrc' -o 'eslint\.config\.'Repository: recoupable/admin Length of output: 211 🏁 Script executed: rg 'no-img-element'Repository: recoupable/admin Length of output: 42 🏁 Script executed: ls -la | grep eslintRepository: recoupable/admin Length of output: 126 🏁 Script executed: cat .eslintrc.jsonRepository: recoupable/admin Length of output: 120 🏁 Script executed: rg 'remotePatterns|domains' types/ components/ -A 3 -B 3Repository: recoupable/admin Length of output: 42 Using While the The refactor must include: Required next.config.ts changes-const nextConfig: NextConfig = {};
+const nextConfig: NextConfig = {
+ images: {
+ remotePatterns: [
+ {
+ protocol: 'https',
+ hostname: '*.slack-edge.com',
+ },
+ {
+ protocol: 'https',
+ hostname: '*.slack.com',
+ },
+ ],
+ },
+};Then apply the component refactor: Component changes+import Image from "next/image";
...
- {tag.user_avatar && (
- <img
- src={tag.user_avatar}
- alt={tag.user_name}
- className="h-6 w-6 rounded-full"
- />
- )}
+ {tag.user_avatar && (
+ <Image
+ src={tag.user_avatar}
+ alt={tag.user_name}
+ width={24}
+ height={24}
+ className="h-6 w-6 rounded-full"
+ />
+ )}🧰 Tools🪛 GitHub Check: ESLint[warning] 15-15: 🤖 Prompt for AI Agents |
||
| )} | ||
| <span className="font-medium">{tag.user_name}</span> | ||
| </div> | ||
| ); | ||
| }, | ||
| }, | ||
| { | ||
| id: "prompt", | ||
| accessorKey: "prompt", | ||
| header: "Prompt", | ||
| cell: ({ getValue }) => ( | ||
| <span className="max-w-md truncate block text-sm text-gray-700 dark:text-gray-300"> | ||
| {getValue<string>()} | ||
| </span> | ||
| ), | ||
| }, | ||
| { | ||
| id: "channel_name", | ||
| accessorKey: "channel_name", | ||
| header: "Channel", | ||
| cell: ({ getValue }) => ( | ||
| <span className="text-sm text-gray-500 dark:text-gray-400">#{getValue<string>()}</span> | ||
| ), | ||
| }, | ||
| { | ||
| id: "timestamp", | ||
| accessorKey: "timestamp", | ||
| header: ({ column }) => <SortableHeader column={column} label="Timestamp" />, | ||
| cell: ({ getValue }) => new Date(getValue<string>()).toLocaleString(), | ||
| sortingFn: "basic", | ||
| }, | ||
| ]; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| "use client"; | ||
|
|
||
| import { | ||
| flexRender, | ||
| getCoreRowModel, | ||
| getSortedRowModel, | ||
| useReactTable, | ||
| type SortingState, | ||
| } from "@tanstack/react-table"; | ||
| import { useState } from "react"; | ||
| import { | ||
| Table, | ||
| TableBody, | ||
| TableCell, | ||
| TableHead, | ||
| TableHeader, | ||
| TableRow, | ||
| } from "@/components/ui/table"; | ||
| import { slackTagsColumns } from "./SlackTagsColumns"; | ||
| import type { SlackTag } from "@/types/coding-agent"; | ||
|
|
||
| interface SlackTagsTableProps { | ||
| tags: SlackTag[]; | ||
| } | ||
|
|
||
| export default function SlackTagsTable({ tags }: SlackTagsTableProps) { | ||
| const [sorting, setSorting] = useState<SortingState>([ | ||
| { id: "timestamp", desc: true }, | ||
| ]); | ||
|
|
||
| const table = useReactTable({ | ||
| data: tags, | ||
| columns: slackTagsColumns, | ||
| state: { sorting }, | ||
| onSortingChange: setSorting, | ||
| getCoreRowModel: getCoreRowModel(), | ||
| getSortedRowModel: getSortedRowModel(), | ||
| }); | ||
|
|
||
| return ( | ||
| <div className="rounded-lg border"> | ||
| <Table> | ||
| <TableHeader> | ||
| {table.getHeaderGroups().map((headerGroup) => ( | ||
| <TableRow key={headerGroup.id}> | ||
| {headerGroup.headers.map((header) => ( | ||
| <TableHead key={header.id}> | ||
| {header.isPlaceholder | ||
| ? null | ||
| : flexRender(header.column.columnDef.header, header.getContext())} | ||
| </TableHead> | ||
| ))} | ||
| </TableRow> | ||
| ))} | ||
| </TableHeader> | ||
| <TableBody> | ||
| {table.getRowModel().rows.length ? ( | ||
| table.getRowModel().rows.map((row) => ( | ||
| <TableRow key={row.id}> | ||
| {row.getVisibleCells().map((cell) => ( | ||
| <TableCell key={cell.id}> | ||
| {flexRender(cell.column.columnDef.cell, cell.getContext())} | ||
| </TableCell> | ||
| ))} | ||
| </TableRow> | ||
| )) | ||
| ) : ( | ||
| <TableRow> | ||
| <TableCell colSpan={slackTagsColumns.length} className="h-24 text-center"> | ||
| No results. | ||
| </TableCell> | ||
| </TableRow> | ||
| )} | ||
| </TableBody> | ||
| </Table> | ||
| </div> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| "use client"; | ||
|
|
||
| import { useQuery } from "@tanstack/react-query"; | ||
| import { usePrivy } from "@privy-io/react-auth"; | ||
| import { fetchSlackTags } from "@/lib/recoup/fetchSlackTags"; | ||
| import type { SlackTagsPeriod } from "@/types/coding-agent"; | ||
|
|
||
| /** | ||
| * Fetches Slack tagging analytics for the Recoup Coding Agent for the given period. | ||
| * Authenticates with the Privy access token (admin Bearer auth). | ||
| */ | ||
| export function useSlackTags(period: SlackTagsPeriod) { | ||
| const { ready, authenticated, getAccessToken } = usePrivy(); | ||
|
|
||
| return useQuery({ | ||
| queryKey: ["admin", "coding-agent", "slack-tags", period], | ||
| queryFn: async () => { | ||
| const token = await getAccessToken(); | ||
| if (!token) throw new Error("Not authenticated"); | ||
| return fetchSlackTags(token, period); | ||
| }, | ||
| enabled: ready && authenticated, | ||
| }); | ||
|
Comment on lines
+15
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check whether auth transitions clear/invalidate React Query cache.
rg -n -C3 'queryClient\.(clear|removeQueries|resetQueries|invalidateQueries)|logout|onLogout' --type=ts --type=tsx
# Inspect current query keys for admin datasets.
rg -n -C2 'queryKey:\s*\[' --type=ts --type=tsxRepository: recoupable/admin Length of output: 87 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Searching for cache invalidation on auth transitions ==="
rg -n -C3 'queryClient\.(clear|removeQueries|resetQueries|invalidateQueries)|logout|onLogout' --type=ts
echo ""
echo "=== Checking usePrivy usage in the codebase ==="
rg -n 'usePrivy' --type=ts -A2
echo ""
echo "=== Examining the specific file: hooks/useSlackTags.ts ==="
fd 'useSlackTags.ts' -type f -exec cat {} \;
echo ""
echo "=== Checking other query keys in admin context ==="
rg -n 'queryKey.*admin' --type=ts -B1 -A1
echo ""
echo "=== Looking for Privy logout handlers ==="
rg -n 'logout' --type=ts -C3Repository: recoupable/admin Length of output: 5722 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Reading useSlackTags.ts ==="
cat hooks/useSlackTags.ts
echo ""
echo "=== Searching for queryClient initialization and setup ==="
rg -n 'queryClient\s*=' --type=ts
echo ""
echo "=== Searching for Privy provider setup ==="
rg -n 'PrivyProvider\|QueryClientProvider' --type=ts
echo ""
echo "=== Checking root app files for initialization ==="
fd -e ts -e js 'app\.|main\.|_app\.' | head -20
echo ""
echo "=== Checking _app.tsx or similar ==="
fd '_app' -type f | head -5Repository: recoupable/admin Length of output: 1083 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Reading providers/Providers.tsx ==="
cat providers/Providers.tsx
echo ""
echo "=== Checking for logout or auth change handlers ==="
rg -n 'onLogout\|logout\|onAuthStateChange' --type=ts -B2 -A3
echo ""
echo "=== Checking if other admin queries also lack user scope ==="
rg -n 'queryKey.*\["admin' --type=ts -A1
echo ""
echo "=== Looking for Privy docs or integration patterns ==="
rg -n 'PrivyProvider' --type=ts -B2 -A5Repository: recoupable/admin Length of output: 659 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== Reading providers/PrivyProvider.tsx ==="
cat providers/PrivyProvider.tsx
echo ""
echo "=== All admin query keys in codebase ==="
rg -n 'queryKey.*\["admin' --type=ts -B1 -A2
echo ""
echo "=== Check if any hook includes user?.id in queryKey ==="
rg -n 'queryKey.*user' --type=ts -B2 -A1
echo ""
echo "=== Looking for useEffect with logout dependency ==="
rg -n 'useEffect.*logout\|logout.*useEffect' --type=ts -B2 -A5Repository: recoupable/admin Length of output: 2662 Cache leakage vulnerability across all admin queries—not just useSlackTags. This is a systemic security issue. All admin hooks ( Required fixes:
The PrivyProvider has no logout callbacks configured, and no cache-clearing logic exists elsewhere in the application. 🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,25 @@ | ||||||||||||||||||
| import type { SlackTag } from "@/types/coding-agent"; | ||||||||||||||||||
|
|
||||||||||||||||||
| interface TagsByDateEntry { | ||||||||||||||||||
| date: string; | ||||||||||||||||||
| count: number; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * Aggregates Slack tags by UTC date (YYYY-MM-DD) for charting. | ||||||||||||||||||
| * | ||||||||||||||||||
| * @param tags - Array of SlackTag objects | ||||||||||||||||||
| * @returns Array of { date, count } sorted ascending by date | ||||||||||||||||||
| */ | ||||||||||||||||||
| export function getTagsByDate(tags: SlackTag[]): TagsByDateEntry[] { | ||||||||||||||||||
| const counts: Record<string, number> = {}; | ||||||||||||||||||
|
|
||||||||||||||||||
| for (const tag of tags) { | ||||||||||||||||||
| const date = tag.timestamp.slice(0, 10); // "YYYY-MM-DD" | ||||||||||||||||||
| counts[date] = (counts[date] ?? 0) + 1; | ||||||||||||||||||
|
Comment on lines
+18
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# Verify what timestamp formats are documented/produced for slack-tags payloads.
rg -n -C2 'slack-tags|timestamp|coding-agent' --type=ts --type=tsx --type=md --type=jsonRepository: recoupable/admin Length of output: 87 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check file structure and find relevant files
find . -type f -name "*.ts" -o -name "*.js" | grep -E "(getTagsByDate|slack|tag)" | head -20Repository: recoupable/admin Length of output: 2133 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Search for timestamp/date-related patterns without problematic file types
rg -n 'slack|timestamp|getTagsByDate' --type=ts --max-count=50Repository: recoupable/admin Length of output: 1684 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Look at the actual file in question
cat -n lib/coding-agent/getTagsByDate.tsRepository: recoupable/admin Length of output: 918 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Search for where this function is called or how timestamps are generated
rg -n 'getTagsByDate|tag\.timestamp' --type=js --type=ts --max-count=100Repository: recoupable/admin Length of output: 473 🏁 Script executed: #!/bin/bash
cat -n types/coding-agent.tsRepository: recoupable/admin Length of output: 532 🏁 Script executed: #!/bin/bash
cat -n lib/recoup/fetchSlackTags.tsRepository: recoupable/admin Length of output: 1309 🏁 Script executed: #!/bin/bash
rg -n 'timestamp.*:' --type=ts --max-count=50 -A 2 -B 2 | head -100Repository: recoupable/admin Length of output: 740 🏁 Script executed: #!/bin/bash
# Look for test files related to getTagsByDate or SlackTags
find . -path ./node_modules -prune -o -type f \( -name "*.test.ts" -o -name "*.spec.ts" -o -name "__tests__" \) -print | xargs grep -l "getTagsByDate\|SlackTag" 2>/dev/null || echo "No tests found"Repository: recoupable/admin Length of output: 74 🏁 Script executed: #!/bin/bash
# Check for mock data or fixtures
rg -n 'SlackTag\|timestamp' --type=ts -B 2 -A 2 | grep -E "(2026|2025|timestamp.*[0-9]{4})" | head -20Repository: recoupable/admin Length of output: 42 UTC bucketing logic is broken for timezone-aware timestamps. The function's JSDoc (line 9) explicitly declares it should aggregate by UTC date, but the implementation simply slices the timestamp string without normalizing to UTC. For a timestamp like Fix by normalizing to UTC before slicing: Diff for (const tag of tags) {
- const date = tag.timestamp.slice(0, 10); // "YYYY-MM-DD"
+ const parsed = new Date(tag.timestamp);
+ if (Number.isNaN(parsed.getTime())) continue;
+ const date = parsed.toISOString().slice(0, 10); // UTC "YYYY-MM-DD"
counts[date] = (counts[date] ?? 0) + 1;
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| return Object.entries(counts) | ||||||||||||||||||
| .map(([date, count]) => ({ date, count })) | ||||||||||||||||||
| .sort((a, b) => a.date.localeCompare(b.date)); | ||||||||||||||||||
| } | ||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.