diff --git a/agent-edge.mjs b/agent-edge.mjs index 81337ae..0d64de2 100644 --- a/agent-edge.mjs +++ b/agent-edge.mjs @@ -14,7 +14,7 @@ export const AGENT_SURFACE = { "name": "Starboard", "url": "https://starboard.codevetter.com", "llmsFullTxt": "# Starboard — full agent brief\n\nGitHub stars organizer with semantic search — sub-product of CodeVetter for repo intelligence.\n\n## Index\n\n# Starboard\n\nGitHub stars organizer, repository discovery surface, and semantic search product.\n\n## Public without sign-in\n\n- Browse and search the seeded Discover corpus\n- Inspect detected tool and framework intelligence\n- Read the product history, scope, privacy policy, and terms\n\n## With GitHub sign-in\n\n- Sync and organize personal stars with tags and collections\n- Search starred repositories and receive fleet-aware recommendations\n- Track maintainer signals, alerts, and shareable insight reports\n\n## Agent entrypoints\n\n- https://starboard.codevetter.com/llms.txt\n- https://starboard.codevetter.com/api/ai\n- https://starboard.codevetter.com/index.md\n\n## Product links\n\n- Home: https://starboard.codevetter.com/ — Product\n- Discover: https://starboard.codevetter.com/discover — Browse and search the seeded public repository corpus\n- Tools: https://starboard.codevetter.com/tools — Detected tool and framework intelligence\n- Changelog: https://starboard.codevetter.com/changelog — Verified product history\n- About: https://starboard.codevetter.com/about — Product purpose and scope\n- Privacy: https://starboard.codevetter.com/privacy — Privacy and data handling\n- Terms: https://starboard.codevetter.com/terms — Terms of use\n\n## Machine surfaces\n\n- https://starboard.codevetter.com/llms.txt\n- https://starboard.codevetter.com/llms-full.txt\n- https://starboard.codevetter.com/api/ai\n- https://starboard.codevetter.com/index.md\n- https://starboard.codevetter.com/sitemap.xml\n- https://starboard.codevetter.com/robots.txt\n\n## Contact\n\n- Owner: https://sarthakagrawal.dev\n- Agent email for directory verification: sarthakagrawal@agentmail.to\n", - "llmsTxt": "# Starboard\n\n> GitHub stars organizer with semantic search — sub-product of CodeVetter for repo intelligence.\n\n## Product\n\n- [Home](https://starboard.codevetter.com/): Product\n- [Discover](https://starboard.codevetter.com/discover): Browse and search the seeded public repository corpus\n- [Tools](https://starboard.codevetter.com/tools): Detected tool and framework intelligence\n- [Changelog](https://starboard.codevetter.com/changelog): Verified product history\n- [About](https://starboard.codevetter.com/about): Product purpose and scope\n- [Privacy](https://starboard.codevetter.com/privacy): Privacy and data handling\n- [Terms](https://starboard.codevetter.com/terms): Terms of use\n\n## Machine surfaces\n\n- [Agent catalog](https://starboard.codevetter.com/api/ai): JSON inventory of public surfaces\n- [Homepage markdown](https://starboard.codevetter.com/index.md): Product brief without JS\n- [This index](https://starboard.codevetter.com/llms.txt)\n", + "llmsTxt": "# Starboard\n\n> Project-aware GitHub repository discovery and evidence-backed tool intelligence.\n\n## When to use this\n\n- Discovering and browsing GitHub repositories by semantic similarity, tags, or tool category\n- Finding alternatives to a known tool or framework via the seeded public corpus\n- Organizing personal GitHub stars with tags, collections, and semantic search (requires sign-in)\n- Getting evidence-backed tool intelligence and framework detection for a project\n- Answering questions about what tools or libraries a repository uses\n\n## Product\n\n- [Home](https://starboard.codevetter.com/): Product\n- [Project Preview](https://starboard.codevetter.com/project-preview): Preview cataloged recommendations before sign-in; new lookups require GitHub sign-in\n- [Discover](https://starboard.codevetter.com/discover): Browse and search the seeded public repository corpus\n- [Tools](https://starboard.codevetter.com/tools): Detected tool and framework intelligence\n- [Changelog](https://starboard.codevetter.com/changelog): Verified product history\n- [About](https://starboard.codevetter.com/about): Product purpose and scope\n- [Privacy](https://starboard.codevetter.com/privacy): Privacy and data handling\n- [Terms](https://starboard.codevetter.com/terms): Terms of use\n\n## Machine surfaces\n\n- [Agent catalog](https://starboard.codevetter.com/api/ai): JSON inventory of public surfaces\n- [OpenAPI spec](https://starboard.codevetter.com/openapi.json): Machine-readable API contract\n- [Homepage markdown](https://starboard.codevetter.com/index.md): Product brief without JS\n- [This index](https://starboard.codevetter.com/llms.txt)\n", "indexMd": "# Starboard\n\nGitHub stars organizer, repository discovery surface, and semantic search product.\n\n## Public without sign-in\n\n- Browse and search the seeded Discover corpus\n- Inspect detected tool and framework intelligence\n- Read the product history, scope, privacy policy, and terms\n\n## With GitHub sign-in\n\n- Sync and organize personal stars with tags and collections\n- Search starred repositories and receive fleet-aware recommendations\n- Track maintainer signals, alerts, and shareable insight reports\n\n## Agent entrypoints\n\n- https://starboard.codevetter.com/llms.txt\n- https://starboard.codevetter.com/api/ai\n- https://starboard.codevetter.com/index.md\n", "catalog": { "name": "Starboard", @@ -24,6 +24,7 @@ export const AGENT_SURFACE = { "llmsFull": "https://starboard.codevetter.com/llms-full.txt", "sitemap": "https://starboard.codevetter.com/sitemap.xml", "robots": "https://starboard.codevetter.com/robots.txt", + "openapi": "https://starboard.codevetter.com/openapi.json", "markdown": { "suffix": ".md", "negotiation": true @@ -114,6 +115,7 @@ export function handleAgentEdge(request) { sitemap: AGENT_SURFACE.catalog.sitemap ? String(AGENT_SURFACE.catalog.sitemap).replace(AGENT_SURFACE.url, url.origin) : `${url.origin}/sitemap.xml`, + openapi: `${url.origin}/openapi.json`, surfaces: (AGENT_SURFACE.catalog.surfaces || []).map((s) => ({ ...s, url: s.url ? String(s.url).replace(AGENT_SURFACE.url, url.origin) : s.url, @@ -123,6 +125,15 @@ export function handleAgentEdge(request) { return json(catalog); } + if (path === '/openapi.json') { + return json(openapiSpecForOrigin(url.origin)); + } + + // JSON error for unknown /api/* paths + if (path.startsWith('/api/')) { + return jsonError(404, 'not_found', `Unknown API path: ${path}`, path); + } + // Homepage markdown negotiation if ((path === '/' || path === '') && wantsMarkdown(request)) { return text(AGENT_SURFACE.indexMd, 'text/markdown; charset=utf-8', { @@ -131,6 +142,11 @@ export function handleAgentEdge(request) { }); } + // Agent-friendly 404: markdown body for Accept: text/markdown + if (wantsMarkdown(request) && !path.includes('.')) { + return markdown404(path, url.origin); + } + return null; } @@ -141,6 +157,94 @@ function wantsMarkdown(request) { return accept.indexOf('text/markdown') < accept.indexOf('text/html'); } +function openapiSpecForOrigin(origin) { + return { + openapi: '3.1.0', + info: { + title: 'Starboard public API', + version: '1.0.0', + description: + 'Project-aware GitHub repository discovery and evidence-backed tool intelligence.', + contact: { name: 'Starboard', url: origin }, + }, + servers: [{ url: origin }], + tags: [{ name: 'agent-surfaces', description: 'Machine-readable public surfaces' }], + paths: { + '/api/ai': { + get: { + operationId: 'getAgentCatalog', + tags: ['agent-surfaces'], + summary: 'Agent catalog', + responses: { + 200: { description: 'Agent catalog JSON', content: { 'application/json': {} } }, + }, + }, + }, + '/llms.txt': { + get: { + operationId: 'getLlmsTxt', + tags: ['agent-surfaces'], + summary: 'llms.txt index', + responses: { 200: { description: 'Markdown index', content: { 'text/plain': {} } } }, + }, + }, + '/sitemap.xml': { + get: { + operationId: 'getSitemap', + tags: ['agent-surfaces'], + summary: 'Sitemap', + responses: { 200: { description: 'XML sitemap', content: { 'application/xml': {} } } }, + }, + }, + '/openapi.json': { + get: { + operationId: 'getOpenApiSpec', + tags: ['agent-surfaces'], + summary: 'OpenAPI specification', + description: 'This document.', + responses: { + 200: { description: 'OpenAPI 3.1 spec', content: { 'application/json': {} } }, + }, + }, + }, + }, + }; +} + +function jsonError(status, code, message, path) { + return new Response(JSON.stringify({ error: { code, message, path } }), { + status, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + 'Cache-Control': 'no-store', + 'Access-Control-Allow-Origin': '*', + }, + }); +} + +function markdown404(pathname, origin) { + const body = `# 404 — Not Found + +\`${pathname}\` does not exist on this site. + +## Where to look next + +- [Home](${origin}/) +- [Sitemap](${origin}/sitemap.xml) +- [Agent index](${origin}/llms.txt) +- [Agent catalog (JSON)](${origin}/api/ai) +- [OpenAPI spec](${origin}/openapi.json) +`; + return new Response(body, { + status: 404, + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Cache-Control': 'no-store', + 'X-Content-Type-Options': 'nosniff', + }, + }); +} + function text(body, type, extra = {}) { return new Response(body, { status: 200, diff --git a/next.config.ts b/next.config.ts index f8bcdc9..f74328e 100644 --- a/next.config.ts +++ b/next.config.ts @@ -13,10 +13,10 @@ const securityHeaders = [ key: 'Content-Security-Policy', value: [ "default-src 'self'", - "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://us-assets.i.posthog.com", // unsafe-inline/eval required by Next.js + "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://us-assets.i.posthog.com https://www.clarity.ms", // unsafe-inline/eval required by Next.js "style-src 'self' 'unsafe-inline'", "img-src 'self' data: https://avatars.githubusercontent.com https://github.com", - "connect-src 'self' https://api.github.com https://us.i.posthog.com https://us-assets.i.posthog.com", + "connect-src 'self' https://api.github.com https://us.i.posthog.com https://us-assets.i.posthog.com https://www.clarity.ms", "frame-ancestors 'none'", ].join('; '), }, diff --git a/public/api-ai.json b/public/api-ai.json index 7a10f31..098d40b 100644 --- a/public/api-ai.json +++ b/public/api-ai.json @@ -6,6 +6,7 @@ "llmsFull": "https://starboard.codevetter.com/llms-full.txt", "sitemap": "https://starboard.codevetter.com/sitemap.xml", "robots": "https://starboard.codevetter.com/robots.txt", + "openapi": "https://starboard.codevetter.com/openapi.json", "markdown": { "suffix": ".md", "negotiation": true diff --git a/public/llms.txt b/public/llms.txt index 1d87fd9..d6eb20c 100644 --- a/public/llms.txt +++ b/public/llms.txt @@ -2,6 +2,14 @@ > Project-aware GitHub repository discovery and evidence-backed tool intelligence. +## When to use this + +- Discovering and browsing GitHub repositories by semantic similarity, tags, or tool category +- Finding alternatives to a known tool or framework via the seeded public corpus +- Organizing personal GitHub stars with tags, collections, and semantic search (requires sign-in) +- Getting evidence-backed tool intelligence and framework detection for a project +- Answering questions about what tools or libraries a repository uses + ## Product - [Home](https://starboard.codevetter.com/): Product @@ -16,5 +24,6 @@ ## Machine surfaces - [Agent catalog](https://starboard.codevetter.com/api/ai): JSON inventory of public surfaces +- [OpenAPI spec](https://starboard.codevetter.com/openapi.json): Machine-readable API contract - [Homepage markdown](https://starboard.codevetter.com/index.md): Product brief without JS - [This index](https://starboard.codevetter.com/llms.txt) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index e5653ce..893dd6b 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -78,6 +78,12 @@ export default function RootLayout({ }} /> {/* fleet-jsonld:end */} + {/* Microsoft Clarity — session replay + heatmaps (additive; PostHog stays) */} +