Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

copilot.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

copilot.tsBlame73 lines · 1 contributor
3cbe3d6Claude1/**
2 * Block D9 — Copilot-style completion HTTP surface.
3 *
4 * POST /api/copilot/completions (authed — PAT / OAuth / session)
5 * Body: { prefix, suffix?, language?, repo? }
6 * Returns: { completion, model, cached }
7 *
8 * GET /api/copilot/ping (unauthed)
9 * Returns: { ok: true, aiAvailable: boolean }
10 *
11 * Keep per-user limits tight: IDE plugins call this on every keystroke, so a
12 * misbehaving client can otherwise exhaust the shared Anthropic quota fast.
13 */
14
0410f22Claude15// For proactive, context-aware suggestions see POST /api/pair/suggest (src/routes/pair-programmer.ts)
16
3cbe3d6Claude17import { Hono } from "hono";
18import { requireAuth } from "../middleware/auth";
19import type { AuthEnv } from "../middleware/auth";
20import { rateLimit } from "../middleware/rate-limit";
21import { completeCode } from "../lib/ai-completion";
22import { isAiAvailable } from "../lib/ai-client";
23
24const copilot = new Hono<AuthEnv>();
25
26// Tight per-caller limit: 60/min. NOTE: `rateLimit` keys by bearer-token
27// prefix when Authorization is present, otherwise by IP — so session-cookie
28// callers share a single IP bucket. That's acceptable for an IDE endpoint
29// where the expected caller is almost always a PAT/OAuth token.
0316dbbClaude30const completionLimit = rateLimit(60, 60_000, "copilot");
3cbe3d6Claude31
32copilot.get("/api/copilot/ping", (c) => {
33 return c.json({ ok: true, aiAvailable: isAiAvailable() });
34});
35
36copilot.post(
37 "/api/copilot/completions",
38 completionLimit,
39 requireAuth,
40 async (c) => {
41 let body: any;
42 try {
43 body = await c.req.json();
44 } catch {
45 return c.json({ error: "invalid JSON body" }, 400);
46 }
47 if (!body || typeof body !== "object") {
48 return c.json({ error: "body must be a JSON object" }, 400);
49 }
50
51 const { prefix, suffix, language, repo } = body as {
52 prefix?: unknown;
53 suffix?: unknown;
54 language?: unknown;
55 repo?: unknown;
56 };
57
58 if (typeof prefix !== "string" || prefix.length === 0) {
59 return c.json({ error: "prefix (non-empty string) is required" }, 400);
60 }
61
62 const result = await completeCode({
63 prefix,
64 suffix: typeof suffix === "string" ? suffix : undefined,
65 language: typeof language === "string" ? language : undefined,
66 repoHint: typeof repo === "string" ? repo : undefined,
67 });
68
69 return c.json(result);
70 }
71);
72
73export default copilot;