mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
The "Hire an agent" and "monitor" wording oversold the feature: it is just a prompt you give an agent to check health, security, performance, or resources, optionally on a schedule. Rename the group to "Agent prompts", drop "monitor" from the four child pages (Health, Security, Performance, Resources), and use plainer framing across the landing page and observability hub. URL slugs are unchanged. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Renamed the Observability section to “Agent prompts” and updated its page titles and descriptions to describe project checks. * Clarified that prompts read project data without changing it, and that findings can be sent through existing harness connections. * Updated setup guidance to refer to running prompts and using “checks” in task names. * Renamed the Health, Security, Performance, and Resources entries. The related links, schedules, and reporting details remain unchanged. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
142 lines
4.9 KiB
TypeScript
142 lines
4.9 KiB
TypeScript
import { aiPrompts } from './ai-prompts.data'
|
|
import {
|
|
monitoringAgents,
|
|
type MonitoringAgent,
|
|
type MonitoringAgentId,
|
|
} from './monitoring-agents.data'
|
|
|
|
export type MonitoringAgentHarnessKey = 'claude' | 'codex' | 'cursor'
|
|
|
|
export type ScheduleMark = {
|
|
key: string
|
|
label?: string
|
|
}
|
|
|
|
export type MonitoringAgentHarnessSetup = {
|
|
key: MonitoringAgentHarnessKey
|
|
label: string
|
|
icon: 'claude' | 'openai' | 'cursor'
|
|
hasDistinctDarkIcon?: boolean
|
|
docsUrl: string
|
|
intro: string
|
|
steps: string[]
|
|
note?: string
|
|
}
|
|
|
|
const WEEKDAY_LABELS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] as const
|
|
const DAY_LABELS = ['12am', '6am', '12pm', '6pm'] as const
|
|
|
|
export const AGENT_PROMPT_ANCHOR = 'agent-prompt'
|
|
|
|
const MCP_STEP =
|
|
'Connect the [Supabase MCP server](/docs/guides/ai-tools/mcp) with `project_ref` and `read_only=true`.'
|
|
|
|
export function getMonitoringAgent(id: string): MonitoringAgent {
|
|
const agent = monitoringAgents[id as MonitoringAgentId]
|
|
if (!agent) {
|
|
throw new Error(`Unknown monitoring agent id: ${id}`)
|
|
}
|
|
return agent
|
|
}
|
|
|
|
export function getMonitoringAgentPrompt(agent: MonitoringAgent): string {
|
|
const prompt = aiPrompts[agent.promptId]
|
|
if (!prompt) {
|
|
throw new Error(`Unknown AiPrompt id: ${agent.promptId}`)
|
|
}
|
|
return prompt
|
|
}
|
|
|
|
export function getCronExpression(intervalMinutes: number): string {
|
|
if (intervalMinutes === 15) return '*/15 * * * *'
|
|
if (intervalMinutes === 60) return '0 * * * *'
|
|
if (intervalMinutes === 1440) return '0 9 * * *'
|
|
throw new Error(`Unsupported monitoring agent interval: ${intervalMinutes}`)
|
|
}
|
|
|
|
export function getScheduleMarks(intervalMinutes: number): {
|
|
window: 'day' | 'week'
|
|
marks: ScheduleMark[]
|
|
} {
|
|
if (intervalMinutes >= 24 * 60) {
|
|
return {
|
|
window: 'week',
|
|
marks: WEEKDAY_LABELS.map((label) => ({ key: label, label })),
|
|
}
|
|
}
|
|
|
|
const marksPerDay = (24 * 60) / intervalMinutes
|
|
if (!Number.isInteger(marksPerDay)) {
|
|
throw new Error(`intervalMinutes must divide 1440 evenly. Received: ${intervalMinutes}`)
|
|
}
|
|
|
|
const labelEvery = marksPerDay / 4
|
|
const marks = Array.from({ length: marksPerDay }, (_, index) => ({
|
|
key: String(index),
|
|
label: index % labelEvery === 0 ? DAY_LABELS[index / labelEvery] : undefined,
|
|
}))
|
|
|
|
return { window: 'day', marks }
|
|
}
|
|
|
|
export function getScheduleLabel(agent: MonitoringAgent): string {
|
|
const cadence = agent.schedule.cadence
|
|
return cadence.charAt(0).toUpperCase() + cadence.slice(1)
|
|
}
|
|
|
|
export function getMonitoringAgentHarnesses(agent: MonitoringAgent): MonitoringAgentHarnessSetup[] {
|
|
const cron = getCronExpression(agent.schedule.intervalMinutes)
|
|
const cadence = agent.schedule.cadence
|
|
const isSubHourly = agent.schedule.intervalMinutes < 60
|
|
|
|
return [
|
|
{
|
|
key: 'claude',
|
|
label: 'Claude',
|
|
icon: 'claude',
|
|
docsUrl: isSubHourly
|
|
? 'https://code.claude.com/docs/en/desktop-scheduled-tasks'
|
|
: 'https://code.claude.com/docs/en/routines',
|
|
intro: isSubHourly
|
|
? `Create a Claude Desktop scheduled task that runs the ${agent.name} prompt ${cadence}.`
|
|
: `Create a Claude routine that runs the ${agent.name} prompt ${cadence}.`,
|
|
steps: [
|
|
MCP_STEP,
|
|
isSubHourly
|
|
? 'In the Claude Code Desktop app, open **Routines**, click **New routine**, and choose **Local**.'
|
|
: 'Open [Claude routines](https://claude.ai/code/routines) or run `/schedule` in Claude Code.',
|
|
`Name it ${agent.name} checks. Paste the [prompt](#${AGENT_PROMPT_ANCHOR}). Set the schedule to ${cadence}.`,
|
|
],
|
|
note: isSubHourly
|
|
? 'Cloud routines have a 1-hour minimum. Use a [Desktop scheduled task](https://code.claude.com/docs/en/desktop-scheduled-tasks) for this cadence.'
|
|
: undefined,
|
|
},
|
|
{
|
|
key: 'codex',
|
|
label: 'Codex',
|
|
icon: 'openai',
|
|
hasDistinctDarkIcon: true,
|
|
docsUrl: 'https://developers.openai.com/codex/app/automations',
|
|
intro: `Create a Codex scheduled task that runs the ${agent.name} prompt ${cadence}.`,
|
|
steps: [
|
|
MCP_STEP,
|
|
'Open **Scheduled** in the ChatGPT desktop app, or ask Codex to create a standalone scheduled task.',
|
|
`Name it ${agent.name} checks. Paste the [prompt](#${AGENT_PROMPT_ANCHOR}). Set the schedule to ${cadence}. Each run should start a new chat.`,
|
|
],
|
|
},
|
|
{
|
|
key: 'cursor',
|
|
label: 'Cursor',
|
|
icon: 'cursor',
|
|
hasDistinctDarkIcon: true,
|
|
docsUrl: 'https://cursor.com/docs/cloud-agent/automations',
|
|
intro: `Create a Cursor automation that runs the ${agent.name} prompt ${cadence}.`,
|
|
steps: [
|
|
MCP_STEP,
|
|
'Create an automation in the Agents Window, at [cursor.com/automations](https://cursor.com/automations), or with the `/automate` skill.',
|
|
`Name it ${agent.name} checks. Use a scheduled trigger (${cadence}, cron \`${cron}\`). Paste the [prompt](#${AGENT_PROMPT_ANCHOR}). Keep the agent read-only, with no repository.`,
|
|
],
|
|
},
|
|
]
|
|
}
|