@tstax/coding-tab 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -0
- package/dist/browser.js +60 -0
- package/dist/browser.js.map +1 -0
- package/dist/server.cjs +709 -0
- package/dist/server.cjs.map +1 -0
- package/dist/server.d.cts +111 -0
- package/dist/server.d.ts +111 -0
- package/dist/server.js +668 -0
- package/dist/server.js.map +1 -0
- package/dist/style.css +244 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server/index.ts","../node_modules/tsup/assets/cjs_shims.js","../src/server/authRoutes.ts","../src/server/authMiddleware.ts","../src/server/session.ts","../src/server/agentRoutes.ts","../src/server/models.ts","../src/server/sessions.ts","../src/server/githubRoutes.ts","../src/server/staticAssets.ts"],"sourcesContent":["import express, { type Express, type Router } from \"express\";\nimport { makeAuthRouter, type GitHubOAuthOptions } from \"./authRoutes.js\";\nimport { makeAgentRouter } from \"./agentRoutes.js\";\nimport { makeGitHubRouter } from \"./githubRoutes.js\";\nimport { makeRequireAuth } from \"./authMiddleware.js\";\nimport { makeAssetRouter } from \"./staticAssets.js\";\n\nexport interface MountCodingTabOptions {\n cursorApiKey: string;\n githubOAuth: GitHubOAuthOptions;\n sessionPassword: string;\n defaultRepo: { url: string; ref?: string };\n basePath?: string;\n secure?: boolean;\n envName?: string;\n skipReviewerRequest?: boolean;\n}\n\nexport function mountCodingTab(app: Express, options: MountCodingTabOptions): Router {\n const basePath = (options.basePath ?? \"/coding-tab\").replace(/\\/$/, \"\");\n const secure = options.secure ?? process.env.NODE_ENV === \"production\";\n\n if (!options.cursorApiKey) throw new Error(\"[coding-tab] cursorApiKey is required\");\n if (!options.sessionPassword || options.sessionPassword.length < 32) {\n throw new Error(\"[coding-tab] sessionPassword must be at least 32 characters\");\n }\n if (!options.githubOAuth?.clientId || !options.githubOAuth?.clientSecret) {\n throw new Error(\"[coding-tab] githubOAuth.clientId and clientSecret are required\");\n }\n if (!options.githubOAuth.callbackUrl) {\n throw new Error(\"[coding-tab] githubOAuth.callbackUrl is required\");\n }\n if (!options.githubOAuth.allowedLogins || options.githubOAuth.allowedLogins.length === 0) {\n console.warn(\"[coding-tab] WARNING: allowedLogins is empty — anyone with a GitHub account can sign in.\");\n }\n\n const router = express.Router();\n router.use(express.json({ limit: \"1mb\" }));\n\n const assetRouter = makeAssetRouter(basePath);\n router.use(assetRouter);\n\n const authRouter = makeAuthRouter({\n oauth: options.githubOAuth,\n sessionPassword: options.sessionPassword,\n secure,\n basePath,\n });\n router.use(authRouter);\n\n const requireAuth = makeRequireAuth({\n sessionPassword: options.sessionPassword,\n secure,\n allowedLogins: options.githubOAuth.allowedLogins,\n });\n\n const agentRouter = makeAgentRouter({\n cursorApiKey: options.cursorApiKey,\n defaultRepo: options.defaultRepo,\n envName: options.envName,\n skipReviewerRequest: options.skipReviewerRequest,\n });\n router.use(requireAuth, agentRouter);\n\n const githubRouter = makeGitHubRouter();\n router.use(requireAuth, githubRouter);\n\n app.use(basePath, router);\n console.log(`[coding-tab] mounted at ${basePath}`);\n return router;\n}\n\nexport type { GitHubOAuthOptions } from \"./authRoutes.js\";\nexport type {\n ChatMode,\n ModelChoice,\n ModelOption,\n StreamEvent,\n PrInfo,\n StartAgentRequest,\n StartAgentResponse,\n SendMessageRequest,\n SendMessageResponse,\n ExecuteRequest,\n MergeRequest,\n MergeResponse,\n MeResponse,\n} from \"../shared/types.js\";\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import { Router, type Request, type Response } from \"express\";\nimport { randomBytes } from \"node:crypto\";\nimport { getSession } from \"./authMiddleware.js\";\n\nexport interface GitHubOAuthOptions {\n clientId: string;\n clientSecret: string;\n callbackUrl: string;\n allowedLogins: string[];\n scopes?: string[];\n}\n\nexport interface AuthRoutesOptions {\n oauth: GitHubOAuthOptions;\n sessionPassword: string;\n secure: boolean;\n basePath: string;\n}\n\nconst OAUTH_STATE_TTL_MS = 10 * 60 * 1000;\n\nexport function makeAuthRouter(opts: AuthRoutesOptions): Router {\n const router = Router();\n const allowed = new Set(opts.oauth.allowedLogins.map((l) => l.toLowerCase()));\n const scopes = opts.oauth.scopes ?? [\"repo\", \"read:user\"];\n\n router.get(\"/auth/login\", async (req: Request, res: Response) => {\n const session = await getSession(req, res, opts);\n const state = randomBytes(24).toString(\"hex\");\n session.oauthState = state;\n session.oauthStateCreatedAt = Date.now();\n await session.save();\n\n const url = new URL(\"https://github.com/login/oauth/authorize\");\n url.searchParams.set(\"client_id\", opts.oauth.clientId);\n url.searchParams.set(\"redirect_uri\", opts.oauth.callbackUrl);\n url.searchParams.set(\"scope\", scopes.join(\" \"));\n url.searchParams.set(\"state\", state);\n url.searchParams.set(\"allow_signup\", \"false\");\n res.redirect(302, url.toString());\n });\n\n router.get(\"/auth/callback\", async (req: Request, res: Response) => {\n const session = await getSession(req, res, opts);\n const code = typeof req.query.code === \"string\" ? req.query.code : null;\n const state = typeof req.query.state === \"string\" ? req.query.state : null;\n\n const expectedState = session.oauthState;\n const stateAge = session.oauthStateCreatedAt ? Date.now() - session.oauthStateCreatedAt : Number.POSITIVE_INFINITY;\n session.oauthState = undefined;\n session.oauthStateCreatedAt = undefined;\n\n if (!code || !state || !expectedState || state !== expectedState || stateAge > OAUTH_STATE_TTL_MS) {\n await session.save();\n res.status(400).send(\"OAuth state mismatch or expired. Try signing in again.\");\n return;\n }\n\n try {\n const tokenResp = await fetch(\"https://github.com/login/oauth/access_token\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n client_id: opts.oauth.clientId,\n client_secret: opts.oauth.clientSecret,\n code,\n redirect_uri: opts.oauth.callbackUrl,\n }),\n });\n const tokenJson = (await tokenResp.json()) as {\n access_token?: string;\n error?: string;\n error_description?: string;\n scope?: string;\n token_type?: string;\n };\n if (!tokenJson.access_token) {\n await session.save();\n res.status(401).send(`GitHub token exchange failed: ${tokenJson.error_description ?? tokenJson.error ?? \"unknown\"}`);\n return;\n }\n\n const userResp = await fetch(\"https://api.github.com/user\", {\n headers: {\n Authorization: `Bearer ${tokenJson.access_token}`,\n Accept: \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n },\n });\n if (!userResp.ok) {\n await session.save();\n res.status(401).send(`GitHub user lookup failed: ${userResp.status}`);\n return;\n }\n const user = (await userResp.json()) as { login: string; avatar_url?: string };\n\n if (allowed.size > 0 && !allowed.has(user.login.toLowerCase())) {\n await session.save();\n res.status(403).send(`@${user.login} is not on the allowlist for this app.`);\n return;\n }\n\n session.githubLogin = user.login;\n session.avatarUrl = user.avatar_url;\n session.accessToken = tokenJson.access_token;\n await session.save();\n\n res.redirect(302, opts.basePath + \"/\");\n } catch (err) {\n console.error(\"[coding-tab] OAuth callback failed\", err);\n res.status(500).send(\"OAuth callback failed. Check server logs.\");\n }\n });\n\n router.post(\"/auth/logout\", async (req: Request, res: Response) => {\n const session = await getSession(req, res, opts);\n session.destroy();\n res.json({ ok: true });\n });\n\n router.get(\"/auth/me\", async (req: Request, res: Response) => {\n const session = await getSession(req, res, opts);\n if (!session.githubLogin || !session.accessToken) {\n res.status(401).json({ error: \"unauthenticated\" });\n return;\n }\n if (allowed.size > 0 && !allowed.has(session.githubLogin.toLowerCase())) {\n res.status(403).json({ error: \"not_authorized\" });\n return;\n }\n res.json({ githubLogin: session.githubLogin, avatarUrl: session.avatarUrl });\n });\n\n return router;\n}\n","import type { NextFunction, Request, Response } from \"express\";\nimport { getIronSession } from \"iron-session\";\nimport { buildSessionOptions, SESSION_COOKIE_NAME, type CodingTabSession } from \"./session.js\";\n\nexport interface AuthenticatedRequest extends Request {\n user: {\n githubLogin: string;\n accessToken: string;\n avatarUrl?: string;\n };\n}\n\nexport interface AuthMiddlewareOptions {\n sessionPassword: string;\n secure: boolean;\n allowedLogins: string[];\n}\n\nexport function getSession(\n req: Request,\n res: Response,\n opts: { sessionPassword: string; secure: boolean },\n) {\n return getIronSession<CodingTabSession>(req, res, buildSessionOptions(opts.sessionPassword, opts.secure));\n}\n\nexport function makeRequireAuth(opts: AuthMiddlewareOptions) {\n const allowed = new Set(opts.allowedLogins.map((l) => l.toLowerCase()));\n return async function requireAuth(req: Request, res: Response, next: NextFunction) {\n try {\n const session = await getSession(req, res, opts);\n if (!session.githubLogin || !session.accessToken) {\n res.status(401).json({ error: \"unauthenticated\" });\n return;\n }\n if (allowed.size > 0 && !allowed.has(session.githubLogin.toLowerCase())) {\n res.status(403).json({ error: \"not_authorized\" });\n return;\n }\n (req as AuthenticatedRequest).user = {\n githubLogin: session.githubLogin,\n accessToken: session.accessToken,\n avatarUrl: session.avatarUrl,\n };\n next();\n } catch (err) {\n console.error(`[${SESSION_COOKIE_NAME}] requireAuth failed`, err);\n res.status(500).json({ error: \"session_error\" });\n }\n };\n}\n","import type { SessionOptions } from \"iron-session\";\n\nexport interface CodingTabSession {\n githubLogin?: string;\n avatarUrl?: string;\n accessToken?: string;\n oauthState?: string;\n oauthStateCreatedAt?: number;\n}\n\nexport const SESSION_COOKIE_NAME = \"coding_tab_session\";\n\nexport function buildSessionOptions(password: string, secure: boolean): SessionOptions {\n return {\n password,\n cookieName: SESSION_COOKIE_NAME,\n cookieOptions: {\n httpOnly: true,\n secure,\n sameSite: \"lax\",\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n },\n };\n}\n","import { Router, type Request, type Response } from \"express\";\nimport { Agent, CursorAgentError, type Run, type SDKMessage } from \"@cursor/sdk\";\nimport type { AuthenticatedRequest } from \"./authMiddleware.js\";\nimport { listAvailableModels, resolveModel } from \"./models.js\";\nimport {\n disposeSession,\n getSession,\n registerSession,\n} from \"./sessions.js\";\nimport type { ChatMode, PrInfo, StreamEvent } from \"../shared/types.js\";\n\nconst PLAN_INSTRUCTION = `You are operating in PLAN MODE.\n\nProduce a clear, concise markdown plan for the user's request. Do NOT modify any files. Do NOT call any file-editing or shell tools that mutate state. Read-only exploration tools (Read, Grep, Glob, semantic search) are encouraged.\n\nStructure the plan with:\n- Goal (1 line)\n- Approach (3-7 bullet points)\n- Files that will change (bulleted, with absolute or repo-relative paths)\n- Risks / things to verify after implementation\n\nWhen you are done, end your message with a single line: PLAN READY`;\n\nconst EXECUTE_INSTRUCTION = `You are now in AGENT MODE. Implement the plan you produced above. Make all required file changes, run any necessary commands, and prepare the changes for a pull request. When complete, summarize what changed in 3-5 bullets.`;\n\nexport interface AgentRoutesOptions {\n cursorApiKey: string;\n defaultRepo: { url: string; ref?: string };\n envName?: string;\n skipReviewerRequest?: boolean;\n}\n\nfunction sse(res: Response, event: StreamEvent) {\n res.write(`data: ${JSON.stringify(event)}\\n\\n`);\n}\n\nfunction parsePrUrl(url: string | undefined): PrInfo | undefined {\n if (!url) return undefined;\n const match = url.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/);\n if (!match) return undefined;\n return { url, owner: match[1]!, repo: match[2]!, number: Number(match[3]!) };\n}\n\nfunction modeInstructionPrefix(mode: ChatMode, prompt: string): string {\n return mode === \"plan\" ? `${PLAN_INSTRUCTION}\\n\\n---\\n\\nUser request:\\n${prompt}` : prompt;\n}\n\nfunction setupSseHeaders(res: Response) {\n res.set({\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache, no-transform\",\n Connection: \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n });\n res.flushHeaders?.();\n}\n\nasync function streamRun(res: Response, run: Run): Promise<void> {\n try {\n for await (const message of run.stream() as AsyncGenerator<SDKMessage, void>) {\n if (res.writableEnded) break;\n if (message.type === \"assistant\") {\n for (const block of message.message.content) {\n if (block.type === \"text\" && block.text) sse(res, { kind: \"text\", text: block.text });\n else if (block.type === \"tool_use\") sse(res, { kind: \"tool\", name: block.name, status: \"running\", callId: block.id, args: block.input });\n }\n } else if (message.type === \"thinking\") {\n sse(res, { kind: \"thinking\", text: message.text });\n } else if (message.type === \"tool_call\") {\n sse(res, { kind: \"tool\", name: message.name, status: message.status, callId: message.call_id, args: message.args, result: message.result });\n } else if (message.type === \"status\") {\n sse(res, { kind: \"status\", status: message.status, message: message.message });\n }\n }\n const result = await run.wait();\n const prUrl = result.git?.branches?.find((b) => b.prUrl)?.prUrl;\n sse(res, {\n kind: \"result\",\n status: result.status,\n pr: parsePrUrl(prUrl),\n durationMs: result.durationMs,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const retryable = err instanceof CursorAgentError ? Boolean((err as { isRetryable?: boolean }).isRetryable) : false;\n sse(res, { kind: \"error\", message, retryable });\n } finally {\n if (!res.writableEnded) res.end();\n }\n}\n\nexport function makeAgentRouter(opts: AgentRoutesOptions): Router {\n const router = Router();\n\n router.get(\"/models\", async (_req, res) => {\n try {\n const models = await listAvailableModels(opts.cursorApiKey);\n res.json({ models });\n } catch (err) {\n console.error(\"[coding-tab] /models failed\", err);\n res.status(500).json({ error: err instanceof Error ? err.message : \"models_failed\" });\n }\n });\n\n router.post(\"/agent/start\", async (req: Request, res: Response) => {\n const user = (req as AuthenticatedRequest).user;\n const { prompt, mode, model, repoUrl, startingRef } = (req.body ?? {}) as {\n prompt?: string;\n mode?: ChatMode;\n model?: \"sonnet\" | \"opus\";\n repoUrl?: string;\n startingRef?: string;\n };\n if (!prompt || (mode !== \"plan\" && mode !== \"agent\") || (model !== \"sonnet\" && model !== \"opus\")) {\n res.status(400).json({ error: \"invalid_request\" });\n return;\n }\n\n setupSseHeaders(res);\n\n let agent;\n try {\n const resolved = await resolveModel(opts.cursorApiKey, model);\n agent = await Agent.create({\n apiKey: opts.cursorApiKey,\n model: { id: resolved.cursorModelId },\n cloud: {\n repos: [\n {\n url: repoUrl ?? opts.defaultRepo.url,\n startingRef: startingRef ?? opts.defaultRepo.ref,\n },\n ],\n autoCreatePR: mode === \"agent\",\n skipReviewerRequest: opts.skipReviewerRequest ?? true,\n envVars: { GITHUB_TOKEN: user.accessToken },\n ...(opts.envName ? { env: { type: \"cloud\" as const, name: opts.envName } } : {}),\n },\n });\n const session = registerSession({\n githubLogin: user.githubLogin,\n agent,\n repoUrl: repoUrl ?? opts.defaultRepo.url,\n startingRef: startingRef ?? opts.defaultRepo.ref,\n });\n\n const run = await agent.send(modeInstructionPrefix(mode, prompt));\n sse(res, { kind: \"ready\", sessionId: session.id, agentId: agent.agentId, runId: run.id });\n console.log(`[coding-tab] start agent=${agent.agentId} run=${run.id} session=${session.id} login=${user.githubLogin}`);\n await streamRun(res, run);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const retryable = err instanceof CursorAgentError ? Boolean((err as { isRetryable?: boolean }).isRetryable) : false;\n console.error(\"[coding-tab] /agent/start failed\", err);\n sse(res, { kind: \"error\", message, retryable });\n if (!res.writableEnded) res.end();\n if (agent) await agent[Symbol.asyncDispose]().catch(() => {});\n }\n\n req.on(\"close\", () => {\n if (!res.writableEnded) res.end();\n });\n });\n\n router.post(\"/agent/send\", async (req: Request, res: Response) => {\n const { sessionId, prompt, mode } = (req.body ?? {}) as {\n sessionId?: string;\n prompt?: string;\n mode?: ChatMode;\n };\n if (!sessionId || !prompt || (mode !== \"plan\" && mode !== \"agent\")) {\n res.status(400).json({ error: \"invalid_request\" });\n return;\n }\n const session = getSession(sessionId);\n if (!session) {\n res.status(404).json({ error: \"session_not_found\" });\n return;\n }\n\n setupSseHeaders(res);\n\n try {\n const run = await session.agent.send(modeInstructionPrefix(mode, prompt));\n sse(res, { kind: \"ready\", sessionId: session.id, agentId: session.agent.agentId, runId: run.id });\n console.log(`[coding-tab] send agent=${session.agent.agentId} run=${run.id} session=${session.id}`);\n await streamRun(res, run);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(\"[coding-tab] /agent/send failed\", err);\n sse(res, { kind: \"error\", message });\n if (!res.writableEnded) res.end();\n }\n\n req.on(\"close\", () => {\n if (!res.writableEnded) res.end();\n });\n });\n\n router.post(\"/agent/execute\", async (req: Request, res: Response) => {\n const { sessionId } = (req.body ?? {}) as { sessionId?: string };\n if (!sessionId) {\n res.status(400).json({ error: \"invalid_request\" });\n return;\n }\n const session = getSession(sessionId);\n if (!session) {\n res.status(404).json({ error: \"session_not_found\" });\n return;\n }\n\n setupSseHeaders(res);\n\n try {\n const run = await session.agent.send(EXECUTE_INSTRUCTION);\n sse(res, { kind: \"ready\", sessionId: session.id, agentId: session.agent.agentId, runId: run.id });\n console.log(`[coding-tab] execute agent=${session.agent.agentId} run=${run.id} session=${session.id}`);\n await streamRun(res, run);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(\"[coding-tab] /agent/execute failed\", err);\n sse(res, { kind: \"error\", message });\n if (!res.writableEnded) res.end();\n }\n\n req.on(\"close\", () => {\n if (!res.writableEnded) res.end();\n });\n });\n\n router.post(\"/agent/cancel\", async (req: Request, res: Response) => {\n const { sessionId, runId } = (req.body ?? {}) as { sessionId?: string; runId?: string };\n if (!sessionId || !runId) {\n res.status(400).json({ error: \"invalid_request\" });\n return;\n }\n const session = getSession(sessionId);\n if (!session) {\n res.status(404).json({ error: \"session_not_found\" });\n return;\n }\n try {\n await Agent.cancelRun(runId, { runtime: \"cloud\", agentId: session.agent.agentId, apiKey: opts.cursorApiKey });\n res.json({ ok: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(\"[coding-tab] /agent/cancel failed\", err);\n res.status(500).json({ error: message });\n }\n });\n\n router.post(\"/agent/dispose\", async (req: Request, res: Response) => {\n const { sessionId } = (req.body ?? {}) as { sessionId?: string };\n if (!sessionId) {\n res.status(400).json({ error: \"invalid_request\" });\n return;\n }\n await disposeSession(sessionId);\n res.json({ ok: true });\n });\n\n return router;\n}\n","import { Cursor, type SDKModel } from \"@cursor/sdk\";\nimport type { ModelChoice, ModelOption } from \"../shared/types.js\";\n\nconst SONNET_PATTERN = /sonnet/i;\nconst OPUS_PATTERN = /opus/i;\n\ninterface ModelMapEntry {\n cursorModelId: string;\n displayName: string;\n}\n\nlet cache: { fetchedAt: number; models: SDKModel[] } | null = null;\nconst CACHE_TTL_MS = 5 * 60 * 1000;\n\nasync function getModelList(apiKey: string): Promise<SDKModel[]> {\n if (cache && Date.now() - cache.fetchedAt < CACHE_TTL_MS) return cache.models;\n const models = await Cursor.models.list({ apiKey });\n cache = { fetchedAt: Date.now(), models };\n return models;\n}\n\nfunction pickBest(models: SDKModel[], pattern: RegExp): SDKModel | undefined {\n const matches = models.filter((m) => pattern.test(m.id) || pattern.test(m.displayName) || (m.aliases ?? []).some((a) => pattern.test(a)));\n if (matches.length === 0) return undefined;\n matches.sort((a, b) => b.id.localeCompare(a.id));\n return matches[0];\n}\n\nexport async function listAvailableModels(apiKey: string): Promise<ModelOption[]> {\n const models = await getModelList(apiKey);\n const out: ModelOption[] = [];\n const sonnet = pickBest(models, SONNET_PATTERN);\n if (sonnet) out.push({ choice: \"sonnet\", cursorModelId: sonnet.id, displayName: sonnet.displayName ?? sonnet.id });\n const opus = pickBest(models, OPUS_PATTERN);\n if (opus) out.push({ choice: \"opus\", cursorModelId: opus.id, displayName: opus.displayName ?? opus.id });\n return out;\n}\n\nexport async function resolveModel(apiKey: string, choice: ModelChoice): Promise<ModelMapEntry> {\n const models = await getModelList(apiKey);\n const pattern = choice === \"sonnet\" ? SONNET_PATTERN : OPUS_PATTERN;\n const picked = pickBest(models, pattern);\n if (!picked) {\n const available = models.map((m) => `${m.displayName} (${m.id})`).join(\", \");\n throw new Error(`No Cursor-routed model matches \"${choice}\". Available: ${available}`);\n }\n return { cursorModelId: picked.id, displayName: picked.displayName ?? picked.id };\n}\n","import type { SDKAgent } from \"@cursor/sdk\";\nimport { randomUUID } from \"node:crypto\";\n\nexport interface AgentSession {\n id: string;\n githubLogin: string;\n agent: SDKAgent;\n repoUrl: string;\n startingRef?: string;\n createdAt: number;\n lastUsedAt: number;\n lastPlanText?: string;\n lastPrUrl?: string;\n}\n\nconst SESSION_IDLE_TTL_MS = 30 * 60 * 1000;\nconst sessions = new Map<string, AgentSession>();\n\nlet sweeperStarted = false;\nfunction startSweeper() {\n if (sweeperStarted) return;\n sweeperStarted = true;\n setInterval(() => {\n const now = Date.now();\n for (const [id, s] of sessions) {\n if (now - s.lastUsedAt > SESSION_IDLE_TTL_MS) {\n disposeSession(id).catch((e) => console.error(\"[coding-tab] session sweep dispose failed\", e));\n }\n }\n }, 5 * 60 * 1000).unref?.();\n}\n\nexport function registerSession(opts: { githubLogin: string; agent: SDKAgent; repoUrl: string; startingRef?: string }): AgentSession {\n startSweeper();\n const id = randomUUID();\n const session: AgentSession = {\n id,\n githubLogin: opts.githubLogin,\n agent: opts.agent,\n repoUrl: opts.repoUrl,\n startingRef: opts.startingRef,\n createdAt: Date.now(),\n lastUsedAt: Date.now(),\n };\n sessions.set(id, session);\n return session;\n}\n\nexport function getSession(id: string): AgentSession | undefined {\n const s = sessions.get(id);\n if (s) s.lastUsedAt = Date.now();\n return s;\n}\n\nexport function listSessions(login: string): AgentSession[] {\n return [...sessions.values()].filter((s) => s.githubLogin === login);\n}\n\nexport async function disposeSession(id: string): Promise<void> {\n const s = sessions.get(id);\n if (!s) return;\n sessions.delete(id);\n try {\n await s.agent[Symbol.asyncDispose]();\n } catch (err) {\n console.error(\"[coding-tab] dispose failed\", err);\n }\n}\n","import { Router, type Request, type Response } from \"express\";\nimport { Octokit } from \"@octokit/rest\";\nimport type { AuthenticatedRequest } from \"./authMiddleware.js\";\nimport type { MergeRequest, PrInfo } from \"../shared/types.js\";\n\nfunction parsePrUrl(prUrl: string): { owner: string; repo: string; number: number } | null {\n const match = prUrl.match(/github\\.com\\/([^/]+)\\/([^/]+)\\/pull\\/(\\d+)/);\n if (!match) return null;\n return { owner: match[1]!, repo: match[2]!, number: Number(match[3]!) };\n}\n\nexport function makeGitHubRouter(): Router {\n const router = Router();\n\n router.get(\"/pr/status\", async (req: Request, res: Response) => {\n const prUrl = typeof req.query.prUrl === \"string\" ? req.query.prUrl : null;\n if (!prUrl) {\n res.status(400).json({ error: \"missing_prUrl\" });\n return;\n }\n const parsed = parsePrUrl(prUrl);\n if (!parsed) {\n res.status(400).json({ error: \"invalid_prUrl\" });\n return;\n }\n const user = (req as AuthenticatedRequest).user;\n const octokit = new Octokit({ auth: user.accessToken });\n try {\n const pr = await octokit.pulls.get({ owner: parsed.owner, repo: parsed.repo, pull_number: parsed.number });\n const info: PrInfo = {\n url: pr.data.html_url,\n owner: parsed.owner,\n repo: parsed.repo,\n number: parsed.number,\n branch: pr.data.head?.ref,\n state: pr.data.merged ? \"merged\" : (pr.data.state as \"open\" | \"closed\"),\n title: pr.data.title,\n body: pr.data.body ?? undefined,\n };\n res.json({ pr: info, mergeable: pr.data.mergeable, mergeable_state: pr.data.mergeable_state });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n res.status(500).json({ error: message });\n }\n });\n\n router.post(\"/pr/merge\", async (req: Request, res: Response) => {\n const body = (req.body ?? {}) as MergeRequest;\n if (!body.prUrl) {\n res.status(400).json({ error: \"missing_prUrl\" });\n return;\n }\n const parsed = parsePrUrl(body.prUrl);\n if (!parsed) {\n res.status(400).json({ error: \"invalid_prUrl\" });\n return;\n }\n const user = (req as AuthenticatedRequest).user;\n const octokit = new Octokit({ auth: user.accessToken });\n try {\n const merge = await octokit.pulls.merge({\n owner: parsed.owner,\n repo: parsed.repo,\n pull_number: parsed.number,\n merge_method: body.mergeMethod ?? \"squash\",\n });\n res.json({ sha: merge.data.sha, merged: merge.data.merged });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(\"[coding-tab] /pr/merge failed\", err);\n res.status(500).json({ error: message });\n }\n });\n\n return router;\n}\n","import { Router, type Request, type Response } from \"express\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nconst here = dirname(fileURLToPath(import.meta.url));\n\nconst ASSET_CANDIDATES = [\n resolve(here, \"browser.js\"),\n resolve(here, \"..\", \"dist\", \"browser.js\"),\n resolve(here, \"..\", \"browser.js\"),\n];\nconst STYLE_CANDIDATES = [\n resolve(here, \"style.css\"),\n resolve(here, \"..\", \"dist\", \"style.css\"),\n resolve(here, \"..\", \"style.css\"),\n];\n\nasync function readFirst(paths: string[]): Promise<{ path: string; data: Buffer }> {\n let lastErr: unknown;\n for (const p of paths) {\n try {\n const data = await readFile(p);\n return { path: p, data };\n } catch (err) {\n lastErr = err;\n }\n }\n throw lastErr instanceof Error ? lastErr : new Error(\"asset not found\");\n}\n\nexport function makeAssetRouter(basePath: string): Router {\n const router = Router();\n\n router.get(\"/browser.js\", async (_req, res) => {\n try {\n const { data } = await readFirst(ASSET_CANDIDATES);\n res.set(\"Content-Type\", \"application/javascript; charset=utf-8\");\n res.set(\"Cache-Control\", \"public, max-age=300\");\n res.send(data);\n } catch (err) {\n res.status(500).send(\"// coding-tab browser bundle missing — did you run `npm run build`?\");\n }\n });\n\n router.get(\"/style.css\", async (_req, res) => {\n try {\n const { data } = await readFirst(STYLE_CANDIDATES);\n res.set(\"Content-Type\", \"text/css; charset=utf-8\");\n res.set(\"Cache-Control\", \"public, max-age=300\");\n res.send(data);\n } catch {\n res.status(404).send(\"/* style.css missing */\");\n }\n });\n\n router.get(\"/\", async (_req: Request, res: Response) => {\n const html = renderHostHtml(basePath);\n res.set(\"Content-Type\", \"text/html; charset=utf-8\");\n res.send(html);\n });\n\n return router;\n}\n\nfunction renderHostHtml(basePath: string): string {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\" />\n <title>Coding Tab</title>\n <link rel=\"stylesheet\" href=\"${basePath}/style.css\" />\n </head>\n <body>\n <div id=\"coding-tab-root\"></div>\n <script src=\"${basePath}/browser.js\"></script>\n <script>\n window.CodingTab.mountCodingTab(\n document.getElementById(\"coding-tab-root\"),\n { apiBase: ${JSON.stringify(basePath)} },\n );\n </script>\n </body>\n</html>`;\n}\n"],"mappings":"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","names":["import_express","import_express","import_sdk","import_node_crypto","getSession","getSession","import_express","parsePrUrl","import_express","express"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Express, Router } from 'express';
|
|
2
|
+
|
|
3
|
+
interface GitHubOAuthOptions {
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret: string;
|
|
6
|
+
callbackUrl: string;
|
|
7
|
+
allowedLogins: string[];
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type ChatMode = "plan" | "agent";
|
|
12
|
+
type ModelChoice = "sonnet" | "opus";
|
|
13
|
+
interface MeResponse {
|
|
14
|
+
githubLogin: string;
|
|
15
|
+
avatarUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
interface ModelOption {
|
|
18
|
+
choice: ModelChoice;
|
|
19
|
+
cursorModelId: string;
|
|
20
|
+
displayName: string;
|
|
21
|
+
}
|
|
22
|
+
interface StartAgentRequest {
|
|
23
|
+
prompt: string;
|
|
24
|
+
mode: ChatMode;
|
|
25
|
+
model: ModelChoice;
|
|
26
|
+
repoUrl?: string;
|
|
27
|
+
startingRef?: string;
|
|
28
|
+
}
|
|
29
|
+
interface StartAgentResponse {
|
|
30
|
+
sessionId: string;
|
|
31
|
+
agentId: string;
|
|
32
|
+
runId: string;
|
|
33
|
+
}
|
|
34
|
+
interface SendMessageRequest {
|
|
35
|
+
sessionId: string;
|
|
36
|
+
prompt: string;
|
|
37
|
+
mode: ChatMode;
|
|
38
|
+
}
|
|
39
|
+
interface SendMessageResponse {
|
|
40
|
+
runId: string;
|
|
41
|
+
}
|
|
42
|
+
interface ExecuteRequest {
|
|
43
|
+
sessionId: string;
|
|
44
|
+
}
|
|
45
|
+
interface PrInfo {
|
|
46
|
+
url: string;
|
|
47
|
+
number: number;
|
|
48
|
+
owner: string;
|
|
49
|
+
repo: string;
|
|
50
|
+
branch?: string;
|
|
51
|
+
state?: "open" | "closed" | "merged";
|
|
52
|
+
title?: string;
|
|
53
|
+
body?: string;
|
|
54
|
+
}
|
|
55
|
+
interface MergeRequest {
|
|
56
|
+
prUrl: string;
|
|
57
|
+
mergeMethod?: "merge" | "squash" | "rebase";
|
|
58
|
+
}
|
|
59
|
+
interface MergeResponse {
|
|
60
|
+
sha: string;
|
|
61
|
+
merged: boolean;
|
|
62
|
+
}
|
|
63
|
+
type StreamEvent = {
|
|
64
|
+
kind: "status";
|
|
65
|
+
status: string;
|
|
66
|
+
message?: string;
|
|
67
|
+
} | {
|
|
68
|
+
kind: "text";
|
|
69
|
+
text: string;
|
|
70
|
+
} | {
|
|
71
|
+
kind: "thinking";
|
|
72
|
+
text: string;
|
|
73
|
+
} | {
|
|
74
|
+
kind: "tool";
|
|
75
|
+
name: string;
|
|
76
|
+
status: "running" | "completed" | "error";
|
|
77
|
+
callId: string;
|
|
78
|
+
args?: unknown;
|
|
79
|
+
result?: unknown;
|
|
80
|
+
} | {
|
|
81
|
+
kind: "result";
|
|
82
|
+
status: "finished" | "error" | "cancelled";
|
|
83
|
+
pr?: PrInfo;
|
|
84
|
+
durationMs?: number;
|
|
85
|
+
} | {
|
|
86
|
+
kind: "error";
|
|
87
|
+
message: string;
|
|
88
|
+
retryable?: boolean;
|
|
89
|
+
} | {
|
|
90
|
+
kind: "ready";
|
|
91
|
+
sessionId: string;
|
|
92
|
+
agentId: string;
|
|
93
|
+
runId: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
interface MountCodingTabOptions {
|
|
97
|
+
cursorApiKey: string;
|
|
98
|
+
githubOAuth: GitHubOAuthOptions;
|
|
99
|
+
sessionPassword: string;
|
|
100
|
+
defaultRepo: {
|
|
101
|
+
url: string;
|
|
102
|
+
ref?: string;
|
|
103
|
+
};
|
|
104
|
+
basePath?: string;
|
|
105
|
+
secure?: boolean;
|
|
106
|
+
envName?: string;
|
|
107
|
+
skipReviewerRequest?: boolean;
|
|
108
|
+
}
|
|
109
|
+
declare function mountCodingTab(app: Express, options: MountCodingTabOptions): Router;
|
|
110
|
+
|
|
111
|
+
export { type ChatMode, type ExecuteRequest, type GitHubOAuthOptions, type MeResponse, type MergeRequest, type MergeResponse, type ModelChoice, type ModelOption, type MountCodingTabOptions, type PrInfo, type SendMessageRequest, type SendMessageResponse, type StartAgentRequest, type StartAgentResponse, type StreamEvent, mountCodingTab };
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Express, Router } from 'express';
|
|
2
|
+
|
|
3
|
+
interface GitHubOAuthOptions {
|
|
4
|
+
clientId: string;
|
|
5
|
+
clientSecret: string;
|
|
6
|
+
callbackUrl: string;
|
|
7
|
+
allowedLogins: string[];
|
|
8
|
+
scopes?: string[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type ChatMode = "plan" | "agent";
|
|
12
|
+
type ModelChoice = "sonnet" | "opus";
|
|
13
|
+
interface MeResponse {
|
|
14
|
+
githubLogin: string;
|
|
15
|
+
avatarUrl?: string;
|
|
16
|
+
}
|
|
17
|
+
interface ModelOption {
|
|
18
|
+
choice: ModelChoice;
|
|
19
|
+
cursorModelId: string;
|
|
20
|
+
displayName: string;
|
|
21
|
+
}
|
|
22
|
+
interface StartAgentRequest {
|
|
23
|
+
prompt: string;
|
|
24
|
+
mode: ChatMode;
|
|
25
|
+
model: ModelChoice;
|
|
26
|
+
repoUrl?: string;
|
|
27
|
+
startingRef?: string;
|
|
28
|
+
}
|
|
29
|
+
interface StartAgentResponse {
|
|
30
|
+
sessionId: string;
|
|
31
|
+
agentId: string;
|
|
32
|
+
runId: string;
|
|
33
|
+
}
|
|
34
|
+
interface SendMessageRequest {
|
|
35
|
+
sessionId: string;
|
|
36
|
+
prompt: string;
|
|
37
|
+
mode: ChatMode;
|
|
38
|
+
}
|
|
39
|
+
interface SendMessageResponse {
|
|
40
|
+
runId: string;
|
|
41
|
+
}
|
|
42
|
+
interface ExecuteRequest {
|
|
43
|
+
sessionId: string;
|
|
44
|
+
}
|
|
45
|
+
interface PrInfo {
|
|
46
|
+
url: string;
|
|
47
|
+
number: number;
|
|
48
|
+
owner: string;
|
|
49
|
+
repo: string;
|
|
50
|
+
branch?: string;
|
|
51
|
+
state?: "open" | "closed" | "merged";
|
|
52
|
+
title?: string;
|
|
53
|
+
body?: string;
|
|
54
|
+
}
|
|
55
|
+
interface MergeRequest {
|
|
56
|
+
prUrl: string;
|
|
57
|
+
mergeMethod?: "merge" | "squash" | "rebase";
|
|
58
|
+
}
|
|
59
|
+
interface MergeResponse {
|
|
60
|
+
sha: string;
|
|
61
|
+
merged: boolean;
|
|
62
|
+
}
|
|
63
|
+
type StreamEvent = {
|
|
64
|
+
kind: "status";
|
|
65
|
+
status: string;
|
|
66
|
+
message?: string;
|
|
67
|
+
} | {
|
|
68
|
+
kind: "text";
|
|
69
|
+
text: string;
|
|
70
|
+
} | {
|
|
71
|
+
kind: "thinking";
|
|
72
|
+
text: string;
|
|
73
|
+
} | {
|
|
74
|
+
kind: "tool";
|
|
75
|
+
name: string;
|
|
76
|
+
status: "running" | "completed" | "error";
|
|
77
|
+
callId: string;
|
|
78
|
+
args?: unknown;
|
|
79
|
+
result?: unknown;
|
|
80
|
+
} | {
|
|
81
|
+
kind: "result";
|
|
82
|
+
status: "finished" | "error" | "cancelled";
|
|
83
|
+
pr?: PrInfo;
|
|
84
|
+
durationMs?: number;
|
|
85
|
+
} | {
|
|
86
|
+
kind: "error";
|
|
87
|
+
message: string;
|
|
88
|
+
retryable?: boolean;
|
|
89
|
+
} | {
|
|
90
|
+
kind: "ready";
|
|
91
|
+
sessionId: string;
|
|
92
|
+
agentId: string;
|
|
93
|
+
runId: string;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
interface MountCodingTabOptions {
|
|
97
|
+
cursorApiKey: string;
|
|
98
|
+
githubOAuth: GitHubOAuthOptions;
|
|
99
|
+
sessionPassword: string;
|
|
100
|
+
defaultRepo: {
|
|
101
|
+
url: string;
|
|
102
|
+
ref?: string;
|
|
103
|
+
};
|
|
104
|
+
basePath?: string;
|
|
105
|
+
secure?: boolean;
|
|
106
|
+
envName?: string;
|
|
107
|
+
skipReviewerRequest?: boolean;
|
|
108
|
+
}
|
|
109
|
+
declare function mountCodingTab(app: Express, options: MountCodingTabOptions): Router;
|
|
110
|
+
|
|
111
|
+
export { type ChatMode, type ExecuteRequest, type GitHubOAuthOptions, type MeResponse, type MergeRequest, type MergeResponse, type ModelChoice, type ModelOption, type MountCodingTabOptions, type PrInfo, type SendMessageRequest, type SendMessageResponse, type StartAgentRequest, type StartAgentResponse, type StreamEvent, mountCodingTab };
|