From 3e9e4a603be921aafc030ac1f7b6167e479055de Mon Sep 17 00:00:00 2001 From: iamjr15 Date: Mon, 27 Jul 2026 18:22:57 +0530 Subject: [PATCH 1/9] fix: repair proxy auth matcher, stale role guard, and duplicate scope schema --- .../src/durable-objects/agent-run-skill-runtime.ts | 4 ++-- apps/agent-worker/src/skill-runtime-auth.ts | 8 ++------ apps/web/src/proxy.ts | 2 +- knip.jsonc | 11 ++++------- packages/auth/src/index.ts | 2 -- packages/auth/src/skill-runtime-capability.ts | 9 --------- packages/db/src/skill-runtime-capabilities.ts | 8 +------- packages/types/README.md | 1 + packages/types/src/index.ts | 2 ++ packages/types/src/skill-runtime.ts | 10 ++++++++++ scripts/database-operation-safety.ts | 2 +- 11 files changed, 24 insertions(+), 35 deletions(-) create mode 100644 packages/types/src/skill-runtime.ts diff --git a/apps/agent-worker/src/durable-objects/agent-run-skill-runtime.ts b/apps/agent-worker/src/durable-objects/agent-run-skill-runtime.ts index 3946752c..57203205 100644 --- a/apps/agent-worker/src/durable-objects/agent-run-skill-runtime.ts +++ b/apps/agent-worker/src/durable-objects/agent-run-skill-runtime.ts @@ -1,4 +1,4 @@ -import { mintSkillRuntimeCapability, type SkillRuntimeScope } from "@cheatcode/auth"; +import { mintSkillRuntimeCapability } from "@cheatcode/auth"; import { createDb, rotateSkillRuntimeCapabilities, @@ -6,7 +6,7 @@ import { withUserContext, } from "@cheatcode/db"; import type { SandboxLike } from "@cheatcode/sandbox-contracts"; -import { AgentRunId, UserId } from "@cheatcode/types"; +import { AgentRunId, type SkillRuntimeScope, UserId } from "@cheatcode/types"; import type { AgentRunEnv } from "./agent-run-env"; import type { StartRunInput } from "./agent-run-schemas"; diff --git a/apps/agent-worker/src/skill-runtime-auth.ts b/apps/agent-worker/src/skill-runtime-auth.ts index a7e6edba..bd55d74a 100644 --- a/apps/agent-worker/src/skill-runtime-auth.ts +++ b/apps/agent-worker/src/skill-runtime-auth.ts @@ -1,11 +1,7 @@ -import { - parseSkillRuntimeCapability, - type SkillRuntimeScope, - verifySkillRuntimeCapabilityDigest, -} from "@cheatcode/auth"; +import { parseSkillRuntimeCapability, verifySkillRuntimeCapabilityDigest } from "@cheatcode/auth"; import { authorizeSkillRuntimeCapability, createDb, withUserContext } from "@cheatcode/db"; import { APIError } from "@cheatcode/observability"; -import { AgentRunId, UserId } from "@cheatcode/types"; +import { AgentRunId, type SkillRuntimeScope, UserId } from "@cheatcode/types"; import type { AgentEnv } from "./agent-env"; export interface SkillRuntimePrincipal { diff --git a/apps/web/src/proxy.ts b/apps/web/src/proxy.ts index 7701cebf..f341bc8d 100644 --- a/apps/web/src/proxy.ts +++ b/apps/web/src/proxy.ts @@ -7,7 +7,7 @@ const PRODUCTION_WEB_ORIGIN = "https://trycheatcode.com"; const REJECTED_AUTHORIZED_PARTY = "https://invalid.invalid"; const AUTH_PATH_PATTERN = /^\/sign-(?:in|up)(?:\/|$)/u; const PROTECTED_PATH_PATTERN = - /^\/(?:101|billing|chats|models|onboarding|personalization|projects|skills)(?:\/|$)/u; + /^\/(?:101|chats|models|onboarding|personalization|pricing|skills|usage)(?:\/|$)/u; const ONBOARDING_PATH_PATTERN = /^\/onboarding(?:\/|$)/u; const proxy = clerkMiddleware(async (auth, request) => { diff --git a/knip.jsonc b/knip.jsonc index 292f42f7..ea927d81 100644 --- a/knip.jsonc +++ b/knip.jsonc @@ -17,16 +17,13 @@ "entry": ["drizzle.config.ts", "src/schema/drizzle.ts"] }, "infra/containers/sandbox/browser-driver": { - // Stagehand resolves these declared peers only inside the separately - // installed sandbox image, so there is no source import for Knip to trace. - "ignoreDependencies": ["playwright-core", "zod"] + // Must stay declared as a workspace so its package.json `main` (server.js, + // launched by scripts/start-browser-driver.sh) anchors the module graph. }, "infra/containers/sandbox/skill-runtime": { "entry": ["bin/*.mjs"], - // Snapshot launchers resolve these executables by installed binary name; - // Knip cannot infer that runtime edge from spawnSync or the shebang. - "ignoreDependencies": ["agent-browser", "tsx"], - "ignoreBinaries": ["agent-browser"] + // The launcher resolves tsx through a hard-coded installed binary path. + "ignoreDependencies": ["tsx"] } } } diff --git a/packages/auth/src/index.ts b/packages/auth/src/index.ts index b17e8e05..ff38099b 100644 --- a/packages/auth/src/index.ts +++ b/packages/auth/src/index.ts @@ -32,13 +32,11 @@ export { export type { MintedSkillRuntimeCapability, ParsedSkillRuntimeCapability, - SkillRuntimeScope, } from "./skill-runtime-capability"; export { mintSkillRuntimeCapability, parseSkillRuntimeCapability, SKILL_RUNTIME_CAPABILITY_TTL_MS, - SkillRuntimeScopeSchema, verifySkillRuntimeCapabilityDigest, } from "./skill-runtime-capability"; diff --git a/packages/auth/src/skill-runtime-capability.ts b/packages/auth/src/skill-runtime-capability.ts index ce55c68b..e0901ef7 100644 --- a/packages/auth/src/skill-runtime-capability.ts +++ b/packages/auth/src/skill-runtime-capability.ts @@ -12,15 +12,6 @@ const CAPABILITY_DIGEST_LENGTH = 43; const BASE64_URL_PATTERN = /^[A-Za-z0-9_-]+$/u; const TEXT_ENCODER = new TextEncoder(); -export const SkillRuntimeScopeSchema = z.enum([ - "events:write", - "integrations:execute", - "skills:read", - "skills:write", -]); - -export type SkillRuntimeScope = z.infer; - export interface MintedSkillRuntimeCapability { digest: string; expiresAt: number; diff --git a/packages/db/src/skill-runtime-capabilities.ts b/packages/db/src/skill-runtime-capabilities.ts index d5a52cfb..671b8269 100644 --- a/packages/db/src/skill-runtime-capabilities.ts +++ b/packages/db/src/skill-runtime-capabilities.ts @@ -1,16 +1,10 @@ -import type { AgentRunId, UserId } from "@cheatcode/types"; +import { type AgentRunId, SkillRuntimeScopeSchema, type UserId } from "@cheatcode/types"; import { and, eq, inArray, isNull } from "drizzle-orm"; import { z } from "zod"; import type { Database } from "./client"; import { agentRuns, projects, type StoredSkillRuntimeCapability, threads } from "./schema"; const MAX_STORED_CAPABILITIES_PER_RUN = 12; -const SkillRuntimeScopeSchema = z.enum([ - "events:write", - "integrations:execute", - "skills:read", - "skills:write", -]); const StoredSkillRuntimeCapabilitySchema = z .object({ digest: z.string().regex(/^[A-Za-z0-9_-]{43}$/u), diff --git a/packages/types/README.md b/packages/types/README.md index b85ee690..9c8a80d4 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -21,6 +21,7 @@ capability discovery contracts, error codes, and UI message types. - `models.ts`: catalog IDs plus the open provider-prefixed logical-model schema - `@cheatcode/types/quota`: strict cross-Worker QuotaTracker request/response contracts and canonical quota feature identifiers +- `skill-runtime.ts`: canonical skill-runtime capability scopes and schema - `ui-message.ts`: the exact AI SDK UI message data-part contract persisted in Postgres and replayed to the web client diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 2cfca294..8e709c18 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -205,6 +205,8 @@ export { UserProfileSchema, } from "./profile"; export { RunStatusSnapshotSchema } from "./run-control"; +export type { SkillRuntimeScope } from "./skill-runtime"; +export { SkillRuntimeScopeSchema } from "./skill-runtime"; export { ClientErrorBodySchema, ClientUserEventBodySchema, diff --git a/packages/types/src/skill-runtime.ts b/packages/types/src/skill-runtime.ts new file mode 100644 index 00000000..cdb42f0d --- /dev/null +++ b/packages/types/src/skill-runtime.ts @@ -0,0 +1,10 @@ +import { z } from "zod"; + +export const SkillRuntimeScopeSchema = z.enum([ + "events:write", + "integrations:execute", + "skills:read", + "skills:write", +]); + +export type SkillRuntimeScope = z.infer; diff --git a/scripts/database-operation-safety.ts b/scripts/database-operation-safety.ts index 8cd44c5d..490d4e91 100644 --- a/scripts/database-operation-safety.ts +++ b/scripts/database-operation-safety.ts @@ -15,7 +15,7 @@ interface SessionOptions { } const MAINTENANCE_LOCK_NAME = "cheatcode:database-maintenance:v1"; -const RUNTIME_DATABASE_ROLES = new Set(["app_agent", "app_gateway", "app_webhooks", "app_worker"]); +const RUNTIME_DATABASE_ROLES = new Set(["app_agent", "app_gateway", "app_webhooks"]); export function assertAdministrativeConnectionTarget( databaseUrl: string, From 6c64870019360a4657b275fbd6a4aa60aa41d11e Mon Sep 17 00:00:00 2001 From: iamjr15 Date: Mon, 27 Jul 2026 18:30:54 +0530 Subject: [PATCH 2/9] refactor: delete dead worker routes, write-only stream parts, and unused DO surface --- apps/agent-worker/README.md | 3 - apps/agent-worker/src/agent-api-run-routes.ts | 13 --- .../durable-objects/agent-run-lifecycle.ts | 9 -- .../src/durable-objects/agent-run-progress.ts | 41 ------- .../project-sandbox-content-support.ts | 74 +----------- .../project-sandbox-content.ts | 92 --------------- .../project-sandbox-processes.ts | 10 -- .../project-sandbox-runtime.ts | 14 --- .../src/durable-objects/project-sandbox.ts | 16 --- .../src/sandbox-file-http-routes.ts | 108 ------------------ apps/agent-worker/src/sandbox-http-routes.ts | 2 - apps/gateway-worker/README.md | 11 +- apps/gateway-worker/src/agent-http-routes.ts | 7 -- apps/gateway-worker/src/metadata-routes.ts | 18 --- .../src/openapi-sandbox-routes.ts | 82 ------------- apps/gateway-worker/src/openapi.ts | 43 ------- .../src/provider-http-routes.ts | 20 +--- .../src/components/chat/message-timeline.ts | 1 + packages/agent-core/README.md | 6 +- packages/sandbox-contracts/src/runtime.ts | 5 - packages/types/src/api.ts | 21 ---- packages/types/src/capabilities.ts | 15 +-- packages/types/src/index.ts | 5 +- packages/types/src/ui-message.ts | 1 + 24 files changed, 15 insertions(+), 602 deletions(-) delete mode 100644 apps/agent-worker/src/durable-objects/agent-run-progress.ts delete mode 100644 apps/agent-worker/src/sandbox-file-http-routes.ts delete mode 100644 apps/gateway-worker/src/metadata-routes.ts diff --git a/apps/agent-worker/README.md b/apps/agent-worker/README.md index 2277f4c8..ec95aa50 100644 --- a/apps/agent-worker/README.md +++ b/apps/agent-worker/README.md @@ -188,9 +188,6 @@ Mastra tool-call chunks also emit `step_started`, `step_completed`, live stream. If the last stream subscriber disconnects while a run is still running, AgentRun emits `run_abandoned` for the watchdog/funnel trail. -AgentRun also emits `data-plan` and `data-task-status` UI chunks so the web app can -render task progress without polling a separate status endpoint. - Project deletion first fences project/thread mutations, refuses an active run, records a durable cleanup request, then removes that project's workspace folder. The database marks cleanup complete only after the Agent service succeeds, so a repeated DELETE retries a diff --git a/apps/agent-worker/src/agent-api-run-routes.ts b/apps/agent-worker/src/agent-api-run-routes.ts index 7b10ac96..9725aaee 100644 --- a/apps/agent-worker/src/agent-api-run-routes.ts +++ b/apps/agent-worker/src/agent-api-run-routes.ts @@ -63,7 +63,6 @@ type RejectedRunResult = Exclude< export function registerAgentRunHttpRoutes(app: Hono<{ Bindings: AgentEnv }>): void { app.post("/v1/threads/:threadId/runs", createRun); app.get("/v1/threads/:threadId/runs/stream", streamActiveRun); - app.get("/v1/threads/:threadId/runs/status", activeRunStatus); app.post("/v1/runs/:runId/cancel", cancelRun); app.get("/v1/threads/:threadId/browser-takeover", browserTakeoverStatus); app.post("/v1/threads/:threadId/browser-takeover/start", startBrowserTakeover); @@ -276,18 +275,6 @@ async function streamActiveRun(c: AgentContext): Promise { ); } -async function activeRunStatus(c: AgentContext): Promise { - const userId = readGatewayUserId(c.req.raw.headers); - const threadId = parseThreadRouteParam(c.req.param("threadId") ?? ""); - const run = await activeRunForThreadRoute(c.env, userId, threadId); - if (!run) { - return new Response(null, { status: 204 }); - } - return fetchAgentRun(agentRunForRunId(c.env, run.runId), "https://agent-run.internal/status", { - headers: { "X-Cheatcode-User-Id": userId }, - }); -} - async function cancelRun(c: AgentContext): Promise { const userId = readGatewayUserId(c.req.raw.headers); const runId = parseRunRouteParam(c.req.param("runId") ?? ""); diff --git a/apps/agent-worker/src/durable-objects/agent-run-lifecycle.ts b/apps/agent-worker/src/durable-objects/agent-run-lifecycle.ts index 873fa636..ab663cc8 100644 --- a/apps/agent-worker/src/durable-objects/agent-run-lifecycle.ts +++ b/apps/agent-worker/src/durable-objects/agent-run-lifecycle.ts @@ -5,7 +5,6 @@ import type { AgentRunEnv } from "./agent-run-env"; import { toAgentRunStreamError } from "./agent-run-errors"; import { persistOrQueueAssistantMessage } from "./agent-run-message-persistence"; import type { AgentRunOutput } from "./agent-run-output"; -import { runPlanChunk, runTaskStatusChunk } from "./agent-run-progress"; import type { StartRunInput } from "./agent-run-schemas"; import type { PersistableRunStatus } from "./agent-run-status-persistence"; import type { ProjectSandbox } from "./project-sandbox"; @@ -86,15 +85,12 @@ async function executeActiveRun(execution: RunExecution): Promise { const { deps, input } = execution; await deps.persistRunStatus(input, "running"); await deps.append({ messageId: input.runId, type: "start" }); - await deps.append(runPlanChunk()); await deps.append({ type: "data-sandbox-status", data: { v: 1, status: "starting" } }); deps.setRunStage("Preparing project sandbox."); await openRunLease(execution); if (deps.isCanceled()) { return; } - await deps.append(runTaskStatusChunk("prepare-sandbox", "completed")); - await deps.append(runTaskStatusChunk("run-agent", "running")); const path = await deps.executeRunPath( input, execution.sandbox, @@ -127,10 +123,7 @@ async function renewRunLease(execution: RunExecution): Promise { async function completeRun(execution: RunExecution): Promise { const { deps, input } = execution; await deps.finalizeTerminal("completed", async () => { - await deps.append(runTaskStatusChunk("run-agent", "completed")); - await deps.append(runTaskStatusChunk("stream-results", "running")); await deps.append({ type: "data-sandbox-status", data: { v: 1, status: "ready" } }); - await deps.append(runTaskStatusChunk("stream-results", "completed")); await deps.output.appendClosingBackstop(); await deps.output.ensureAnswerSegmentEnded(); await deps.append({ type: "finish", finishReason: "stop" }); @@ -152,8 +145,6 @@ async function failRun(execution: RunExecution, error: unknown): Promise { retriable: streamError.retriable, }); await deps.append({ type: "data-sandbox-status", data: { v: 1, status: "failed" } }); - await deps.append(runTaskStatusChunk("run-agent", "failed", streamError.message)); - await deps.append(runTaskStatusChunk("stream-results", "failed", streamError.message)); await deps.append({ type: "data-error", data: { diff --git a/apps/agent-worker/src/durable-objects/agent-run-progress.ts b/apps/agent-worker/src/durable-objects/agent-run-progress.ts deleted file mode 100644 index adfa7ecf..00000000 --- a/apps/agent-worker/src/durable-objects/agent-run-progress.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { TaskStatus } from "@cheatcode/types"; -import type { UIMessageChunk } from "ai"; - -type AgentRunTaskId = "prepare-sandbox" | "run-agent" | "stream-results"; - -const RUN_TASKS: ReadonlyArray<{ id: AgentRunTaskId; title: string }> = [ - { id: "prepare-sandbox", title: "Prepare sandbox" }, - { id: "run-agent", title: "Run agent tools" }, - { id: "stream-results", title: "Stream workspace result" }, -]; - -export function runPlanChunk(): UIMessageChunk { - return { - type: "data-plan", - data: { - v: 1, - parallelGroups: [[0], [1], [2]], - tasks: RUN_TASKS.map((task, index) => ({ - id: task.id, - status: index === 0 ? "running" : "pending", - title: task.title, - })), - }, - }; -} - -export function runTaskStatusChunk( - taskId: AgentRunTaskId, - status: TaskStatus, - error?: string, -): UIMessageChunk { - return { - type: "data-task-status", - data: { - v: 1, - taskId, - status, - ...(error ? { error } : {}), - }, - }; -} diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-content-support.ts b/apps/agent-worker/src/durable-objects/project-sandbox-content-support.ts index f9721620..6228a404 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox-content-support.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox-content-support.ts @@ -1,14 +1,10 @@ -import { PROJECT_ARCHIVE_MAX_OUTPUT_BYTES, type SandboxFilePreview } from "@cheatcode/types"; +import { PROJECT_ARCHIVE_MAX_OUTPUT_BYTES } from "@cheatcode/types"; import { shellQuote } from "./project-sandbox-process-support"; import { type ProjectSearchFilesInput, ProjectSearchFilesInputSchema, } from "./project-sandbox-runtime"; -// Base64 expands by one third; keep the encoded JSON response below the web -// client's 8 MiB file-response boundary and the Worker's isolate memory budget. -export const MAX_PREVIEW_BYTES = 5 * 1024 * 1024; -export const PREVIEW_DIR = "/workspace/.cheatcode-previews"; export const PROJECT_ARCHIVE_MAX_BYTES = 512 * 1024 * 1024; export const PROJECT_ARCHIVE_MAX_FILES = 25_000; export const WORKSPACE_DIR = "/workspace"; @@ -106,69 +102,6 @@ if archive_size > max_output_bytes: export { PROJECT_ARCHIVE_MAX_OUTPUT_BYTES }; -export function lowercaseExtension(path: string): string { - const filename = basename(path).toLowerCase(); - const dot = filename.lastIndexOf("."); - return dot === -1 ? "" : filename.slice(dot); -} - -export function imageMimeType(extension: string): string | null { - const mimeTypes: Record = { - ".gif": "image/gif", - ".jpeg": "image/jpeg", - ".jpg": "image/jpeg", - ".png": "image/png", - ".svg": "image/svg+xml", - ".webp": "image/webp", - }; - return mimeTypes[extension] ?? null; -} - -const OFFICE_PREVIEW_EXTENSIONS = new Set([ - ".doc", - ".docx", - ".odp", - ".ods", - ".odt", - ".pot", - ".potx", - ".pps", - ".ppsx", - ".ppt", - ".pptx", - ".xls", - ".xlsx", -]); - -export function isOfficePreviewExtension(extension: string): boolean { - return OFFICE_PREVIEW_EXTENSIONS.has(extension); -} - -export function unsupportedPreview(path: string, error: string): SandboxFilePreview { - return { - content: null, - encoding: null, - error, - kind: "unsupported", - mimeType: null, - path, - previewPath: null, - }; -} - -export function conversionErrorMessage(output: string): string { - const trimmed = output.trim(); - if (!trimmed) { - return "Office preview conversion failed."; - } - return trimmed.length > 1_000 ? `${trimmed.slice(0, 997)}...` : trimmed; -} - -export function withoutExtension(filename: string): string { - const dot = filename.lastIndexOf("."); - return dot <= 0 ? filename : filename.slice(0, dot); -} - export function buildGrepCommand(input: ProjectSearchFilesInput): string { const parsed = ProjectSearchFilesInputSchema.parse(input); const flags = ["-rnI"]; @@ -207,11 +140,6 @@ export function dirname(path: string): string { return index <= 0 ? "/" : path.slice(0, index); } -export function basename(path: string): string { - const index = path.lastIndexOf("/"); - return index === -1 ? path : path.slice(index + 1); -} - export function encodeBase64(bytes: Uint8Array): string { const chunkSize = 24 * 1024; const encoded: string[] = []; diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-content.ts b/apps/agent-worker/src/durable-objects/project-sandbox-content.ts index 07166ffe..9ec2769d 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox-content.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox-content.ts @@ -7,7 +7,6 @@ import type { SandboxWriteFileResult, } from "@cheatcode/sandbox-contracts"; import { DaytonaApiError } from "@cheatcode/tools-code"; -import type { SandboxFilePreview } from "@cheatcode/types"; import { metroForwardedHostFixScript } from "./expo-metro-forwarded-host"; import { CODE_SERVER_DISPLAY_DIR, @@ -20,25 +19,16 @@ import { codeServerTrustedOrigins, } from "./project-sandbox-code-server"; import { - basename, buildGrepCommand, - conversionErrorMessage, decodeBase64, dirname, encodeBase64, - imageMimeType, - isOfficePreviewExtension, - lowercaseExtension, - MAX_PREVIEW_BYTES, - PREVIEW_DIR, PROJECT_ARCHIVE_MAX_BYTES, PROJECT_ARCHIVE_MAX_FILES, PROJECT_ARCHIVE_MAX_OUTPUT_BYTES, PROJECT_ARCHIVE_SCRIPT, parseGrepOutput, - unsupportedPreview, WORKSPACE_DIR, - withoutExtension, } from "./project-sandbox-content-support"; import { listSandboxFiles } from "./project-sandbox-files"; import { buildPreviewUrl, signedUrlToExpo } from "./project-sandbox-preview"; @@ -66,8 +56,6 @@ import { ProjectDeleteFileInputSchema, type ProjectListFilesInput, ProjectListFilesInputSchema, - type ProjectPreviewFileInput, - ProjectPreviewFileInputSchema, type ProjectPreviewStatusInput, ProjectPreviewStatusInputSchema, type ProjectReadFileInput, @@ -175,22 +163,6 @@ export abstract class ProjectSandboxContent extends ProjectSandboxProjectFiles { }; } - public async previewFile(input: ProjectPreviewFileInput): Promise { - const parsed = ProjectPreviewFileInputSchema.parse(input); - const extension = lowercaseExtension(parsed.path); - const imageMime = imageMimeType(extension); - if (imageMime) { - return this.base64Preview(parsed.path, parsed.path, "image", imageMime); - } - if (extension === ".pdf") { - return this.base64Preview(parsed.path, parsed.path, "pdf", "application/pdf"); - } - if (isOfficePreviewExtension(extension)) { - return this.officePdfPreview(parsed.path); - } - return unsupportedPreview(parsed.path, "No preview renderer is available for this file type."); - } - public async writeFile(input: ProjectWriteFileInput): Promise { const parsed = ProjectWriteFileInputSchema.parse(input); const id = await this.ensureSandbox(); @@ -433,70 +405,6 @@ export abstract class ProjectSandboxContent extends ProjectSandboxProjectFiles { }; } - private async base64Preview( - sourcePath: string, - previewPath: string, - kind: "image" | "pdf", - mimeType: string, - ): Promise { - const id = await this.ensureSandbox(); - let bytes: Uint8Array; - try { - bytes = await this.client().downloadFile(id, previewPath, MAX_PREVIEW_BYTES + 1); - } catch (error) { - if (isDaytonaResponseTooLarge(error)) { - return unsupportedPreview(sourcePath, "Preview file is too large to display inline."); - } - throw error; - } - if (bytes.byteLength > MAX_PREVIEW_BYTES) { - return unsupportedPreview(sourcePath, "Preview file is too large to display inline."); - } - return { - content: encodeBase64(bytes), - encoding: "base64", - error: null, - kind, - mimeType, - path: sourcePath, - previewPath, - }; - } - - private async officePdfPreview(sourcePath: string): Promise { - const id = await this.ensureSandbox(); - if (!(await this.hasLibreOfficeRuntime(id))) { - return unsupportedPreview( - sourcePath, - "Office preview requires the current sandbox image with LibreOffice installed.", - ); - } - const outputDir = `${PREVIEW_DIR}/${crypto.randomUUID()}`; - const command = [ - `mkdir -p ${shellQuote(outputDir)}`, - `libreoffice --headless --nologo --nofirststartwizard --convert-to pdf --outdir ${shellQuote( - outputDir, - )} ${shellQuote(sourcePath)}`, - ].join(" && "); - const converted = await this.client() - .execute(id, { command, cwd: WORKSPACE_DIR, timeout: timeoutSeconds(90_000) }) - .catch((error: unknown) => { - throw this.toUpstreamError(error, "Office preview conversion failed."); - }); - if (converted.exitCode !== 0) { - return unsupportedPreview(sourcePath, conversionErrorMessage(converted.result ?? "")); - } - const previewPath = `${outputDir}/${withoutExtension(basename(sourcePath))}.pdf`; - return this.base64Preview(sourcePath, previewPath, "pdf", "application/pdf"); - } - - private async hasLibreOfficeRuntime(id: string): Promise { - const probe = await this.client() - .execute(id, { command: "command -v libreoffice >/dev/null", timeout: 5 }) - .catch(() => null); - return probe?.exitCode === 0; - } - private async ensureMobileMetroForwardedHostConfig(id: string, cwd: string): Promise { const current = await this.client() .execute(id, { diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-processes.ts b/apps/agent-worker/src/durable-objects/project-sandbox-processes.ts index 51cbf3ff..53ba0fdb 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox-processes.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox-processes.ts @@ -50,8 +50,6 @@ import { ProjectAllocateProcessPortInputSchema, type ProjectExecInput, ProjectExecInputSchema, - type ProjectGetPortInput, - ProjectGetPortInputSchema, type ProjectKillProcessInput, ProjectKillProcessInputSchema, type ProjectReadDevServerLogsInput, @@ -232,14 +230,6 @@ export abstract class ProjectSandboxProcesses extends ProjectSandboxLifecycle { }); } - public async getProjectPort(input: ProjectGetPortInput): Promise { - const parsed = ProjectGetPortInputSchema.parse(input); - const allocation = PortAllocationSchema.parse( - (await this.ctx.storage.get(PORT_ALLOC_KEY)) ?? {}, - ); - return allocation.ports[parsed.projectId] ?? null; - } - public async allocateProcessPort(input: ProjectAllocateProcessPortInput): Promise { const parsed = ProjectAllocateProcessPortInputSchema.parse(input); return this.ctx.storage.transaction(async (transaction) => { diff --git a/apps/agent-worker/src/durable-objects/project-sandbox-runtime.ts b/apps/agent-worker/src/durable-objects/project-sandbox-runtime.ts index 118ddb2b..0399e149 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox-runtime.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox-runtime.ts @@ -69,12 +69,6 @@ export const ProjectReadFileInputSchema = z }) .strict(); -export const ProjectPreviewFileInputSchema = z - .object({ - path: WorkspaceFilePathSchema, - }) - .strict(); - export const ProjectWriteFileInputSchema = z .object({ path: WorkspaceFilePathSchema, @@ -160,12 +154,6 @@ export const ProjectAllocatePortInputSchema = z }) .strict(); -export const ProjectGetPortInputSchema = z - .object({ - projectId: ProjectWorkspaceSlugSchema, - }) - .strict(); - export const ProjectAllocateProcessPortInputSchema = z .object({ maxPort: z.number().int().min(1_024).max(65_535), @@ -249,7 +237,6 @@ export const ProjectArchiveInputSchema = z export type ProjectExecInput = z.input; export type ProjectStartProcessInput = z.input; -export type ProjectPreviewFileInput = z.input; export type ProjectReadFileInput = z.input; export type ProjectWriteFileInput = z.input; export type ProjectUploadFileInput = z.input; @@ -259,7 +246,6 @@ export type ProjectSearchFilesInput = z.input; export type ProjectKillProcessInput = z.input; export type ProjectAllocatePortInput = z.input; -export type ProjectGetPortInput = z.input; export type ProjectAllocateProcessPortInput = z.input; export type ProjectCodeServerInput = z.input; export type ProjectWakePreviewInput = z.input; diff --git a/apps/agent-worker/src/durable-objects/project-sandbox.ts b/apps/agent-worker/src/durable-objects/project-sandbox.ts index 6de8564c..c7e04463 100644 --- a/apps/agent-worker/src/durable-objects/project-sandbox.ts +++ b/apps/agent-worker/src/durable-objects/project-sandbox.ts @@ -102,14 +102,6 @@ export class ProjectSandbox extends ProjectSandboxContent { ); } - public override getProjectPort( - ...args: Parameters - ): ReturnType { - return this.withActiveProjectWorkspaceOperation(workspaceSlug(args[0].projectId), () => - super.getProjectPort(...args), - ); - } - public override allocateProcessPort( ...args: Parameters ): ReturnType { @@ -174,14 +166,6 @@ export class ProjectSandbox extends ProjectSandboxContent { ); } - public override previewFile( - ...args: Parameters - ): ReturnType { - return this.withActiveProjectWorkspaceOperation(workspaceSlugFromPath(args[0].path), () => - super.previewFile(...args), - ); - } - public override writeFile( ...args: Parameters ): ReturnType { diff --git a/apps/agent-worker/src/sandbox-file-http-routes.ts b/apps/agent-worker/src/sandbox-file-http-routes.ts deleted file mode 100644 index a891b572..00000000 --- a/apps/agent-worker/src/sandbox-file-http-routes.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { workspacePathForSlug } from "@cheatcode/db"; -import { readJsonRequest } from "@cheatcode/observability"; -import { resolveProjectWorkspacePath } from "@cheatcode/tools-code"; -import { - SandboxFileListSchema, - SandboxFilePathSchema, - SandboxFilePreviewSchema, - SandboxFileSchema, - SandboxFileWriteSchema, - UpdateSandboxPathFileSchema, -} from "@cheatcode/types"; -import type { Context, Hono } from "hono"; -import { z } from "zod"; -import type { AgentEnv } from "./agent-env"; -import { requireWritableThreadProject, sandboxForUser } from "./agent-routing"; -import { SANDBOX_WORKSPACE_ROOT, terminalProjectForThread } from "./sandbox-route-helpers"; -import { parseThreadRouteParam, readGatewayUserId } from "./tenancy"; - -const DEFAULT_SANDBOX_FILE_LIST_ROOT = "/workspace"; -const MAX_SANDBOX_FILE_WRITE_REQUEST_BYTES = 10 * 1024 * 1024; -const QueryBooleanSchema = z.enum(["false", "true"]).transform((value) => value === "true"); -const SandboxFileListQuerySchema = z - .object({ - includeHidden: QueryBooleanSchema.default(false), - path: SandboxFilePathSchema.default(DEFAULT_SANDBOX_FILE_LIST_ROOT), - recursive: QueryBooleanSchema.default(true), - }) - .strict(); -const SandboxReadEncodingQuerySchema = z.enum(["utf8", "base64"]).optional(); - -type AgentContext = Context<{ Bindings: AgentEnv }>; - -export function registerSandboxFileHttpRoutes(app: Hono<{ Bindings: AgentEnv }>): void { - app.get("/v1/threads/:threadId/sandbox/files", listSandboxFiles); - app.get("/v1/threads/:threadId/sandbox/file", readSandboxFile); - app.get("/v1/threads/:threadId/sandbox/file-preview", previewSandboxFile); - app.patch("/v1/threads/:threadId/sandbox/file", writeSandboxFile); -} - -async function listSandboxFiles(c: AgentContext): Promise { - const userId = readGatewayUserId(c.req.raw.headers); - const threadId = parseThreadRouteParam(c.req.param("threadId") ?? ""); - const query = SandboxFileListQuerySchema.parse({ - includeHidden: c.req.query("includeHidden") ?? undefined, - path: c.req.query("path") ?? undefined, - recursive: c.req.query("recursive") ?? undefined, - }); - const scoped = await scopedThreadSandboxPath(c.env, userId, threadId, query.path); - const result = await scoped.sandbox.listFiles({ ...query, path: scoped.path }); - return c.json(SandboxFileListSchema.parse(result)); -} - -async function readSandboxFile(c: AgentContext): Promise { - const userId = readGatewayUserId(c.req.raw.headers); - const threadId = parseThreadRouteParam(c.req.param("threadId") ?? ""); - const path = SandboxFilePathSchema.parse(c.req.query("path")); - const encoding = SandboxReadEncodingQuerySchema.parse(c.req.query("encoding") ?? undefined); - const scoped = await scopedThreadSandboxPath(c.env, userId, threadId, path); - const file = await scoped.sandbox.readFile({ - path: scoped.path, - ...(encoding ? { encoding } : {}), - }); - return c.json(SandboxFileSchema.parse(file)); -} - -async function previewSandboxFile(c: AgentContext): Promise { - const userId = readGatewayUserId(c.req.raw.headers); - const threadId = parseThreadRouteParam(c.req.param("threadId") ?? ""); - const path = SandboxFilePathSchema.parse(c.req.query("path")); - const scoped = await scopedThreadSandboxPath(c.env, userId, threadId, path); - const preview = await scoped.sandbox.previewFile({ path: scoped.path }); - return c.json(SandboxFilePreviewSchema.parse(preview)); -} - -async function writeSandboxFile(c: AgentContext): Promise { - const userId = readGatewayUserId(c.req.raw.headers); - const threadId = parseThreadRouteParam(c.req.param("threadId") ?? ""); - const body = UpdateSandboxPathFileSchema.parse( - await readJsonRequest(c.req.raw, MAX_SANDBOX_FILE_WRITE_REQUEST_BYTES, "Sandbox file write"), - ); - await requireWritableThreadProject(c.env, userId, threadId); - const scoped = await scopedThreadSandboxPath(c.env, userId, threadId, body.path); - const result = await scoped.sandbox.writeFile({ - content: body.content, - encoding: body.encoding, - path: scoped.path, - }); - return c.json(SandboxFileWriteSchema.parse(result)); -} - -async function scopedThreadSandboxPath( - env: AgentEnv, - userId: string, - threadId: string, - path: string, -): Promise<{ - path: string; - sandbox: Awaited>; -}> { - const project = await terminalProjectForThread(env, userId, threadId); - const workspaceDir = project - ? workspacePathForSlug(project.workspaceSlug) - : SANDBOX_WORKSPACE_ROOT; - return { - path: resolveProjectWorkspacePath(path, workspaceDir), - sandbox: await sandboxForUser(env, userId), - }; -} diff --git a/apps/agent-worker/src/sandbox-http-routes.ts b/apps/agent-worker/src/sandbox-http-routes.ts index a28b3ce7..715dd8dd 100644 --- a/apps/agent-worker/src/sandbox-http-routes.ts +++ b/apps/agent-worker/src/sandbox-http-routes.ts @@ -1,13 +1,11 @@ import type { Hono } from "hono"; import type { AgentEnv } from "./agent-env"; import { registerProjectFileHttpRoutes } from "./project-file-http-routes"; -import { registerSandboxFileHttpRoutes } from "./sandbox-file-http-routes"; import { registerSandboxPreviewHttpRoutes } from "./sandbox-preview-http-routes"; import { registerSandboxTerminalHttpRoutes } from "./sandbox-terminal-http-routes"; export function registerSandboxHttpRoutes(app: Hono<{ Bindings: AgentEnv }>): void { registerProjectFileHttpRoutes(app); - registerSandboxFileHttpRoutes(app); registerSandboxPreviewHttpRoutes(app); registerSandboxTerminalHttpRoutes(app); } diff --git a/apps/gateway-worker/README.md b/apps/gateway-worker/README.md index 309460fb..de457d06 100644 --- a/apps/gateway-worker/README.md +++ b/apps/gateway-worker/README.md @@ -102,12 +102,11 @@ schema. New objects initialize that schema directly; existing objects must already match it before an operation is admitted. Run creation is also durably idempotent in Postgres, so request-cache state cannot create a duplicate run. -`/v1/tools` and `/v1/agents` read the shared framework-free capability catalog -from `@cheatcode/types`. The Mastra registries are statically constrained to the -same exact names; workflows are exposed through tools and are not reported as -agents. Each tool summary also declares whether it uses the sandbox and whether -it produces an artifact; AgentRun stream status and deliverable routing derive -from those same traits instead of maintaining parallel tool-name lists. +The shared framework-free tool capability catalog in `@cheatcode/types` +statically constrains the Mastra tool registry to the same exact names. Each +tool summary also declares whether it uses the sandbox and whether it produces +an artifact; AgentRun stream status and deliverable routing derive from those +same traits instead of maintaining parallel tool-name lists. ## Public exports diff --git a/apps/gateway-worker/src/agent-http-routes.ts b/apps/gateway-worker/src/agent-http-routes.ts index ed3b70a5..da78bd07 100644 --- a/apps/gateway-worker/src/agent-http-routes.ts +++ b/apps/gateway-worker/src/agent-http-routes.ts @@ -18,26 +18,19 @@ export function registerAgentHttpRoutes(app: GatewayApp): void { for (const [path, route] of POST_AGENT_ROUTES) { app.post(path, (c) => forwardAgentRequest(c, route)); } - app.patch("/v1/threads/:threadId/sandbox/file", (c) => - forwardAgentRequest(c, "PATCH /v1/threads/:threadId/sandbox/file"), - ); app.get("/v1/threads/:threadId/sandbox/console", (c) => readSandboxConsoleRoute(c)); } const GET_AGENT_ROUTES = [ ["/v1/threads/:threadId/runs/stream", "GET /v1/threads/:threadId/runs/stream"], - ["/v1/threads/:threadId/runs/status", "GET /v1/threads/:threadId/runs/status"], ["/v1/threads/:threadId/browser-takeover", "GET /v1/threads/:threadId/browser-takeover"], ["/v1/computer/ide", "GET /v1/computer/ide"], ["/v1/computer/terminal/context", "GET /v1/computer/terminal/context"], - ["/v1/threads/:threadId/sandbox/files", "GET /v1/threads/:threadId/sandbox/files"], ["/v1/threads/:threadId/sandbox/ide", "GET /v1/threads/:threadId/sandbox/ide"], [ "/v1/threads/:threadId/sandbox/preview/status", "GET /v1/threads/:threadId/sandbox/preview/status", ], - ["/v1/threads/:threadId/sandbox/file", "GET /v1/threads/:threadId/sandbox/file"], - ["/v1/threads/:threadId/sandbox/file-preview", "GET /v1/threads/:threadId/sandbox/file-preview"], [ "/v1/threads/:threadId/sandbox/terminal/context", "GET /v1/threads/:threadId/sandbox/terminal/context", diff --git a/apps/gateway-worker/src/metadata-routes.ts b/apps/gateway-worker/src/metadata-routes.ts deleted file mode 100644 index 23fc8ae1..00000000 --- a/apps/gateway-worker/src/metadata-routes.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { - AGENT_CAPABILITIES, - AgentSummarySchema, - TOOL_CAPABILITIES, - type ToolDomain, - ToolSummarySchema, -} from "@cheatcode/types"; - -export function listToolsRoute(domain: ToolDomain | undefined): Response { - const tools = domain - ? TOOL_CAPABILITIES.filter((capability) => capability.domain === domain) - : TOOL_CAPABILITIES; - return Response.json(ToolSummarySchema.array().parse(tools)); -} - -export function listAgentsRoute(): Response { - return Response.json(AgentSummarySchema.array().parse(AGENT_CAPABILITIES)); -} diff --git a/apps/gateway-worker/src/openapi-sandbox-routes.ts b/apps/gateway-worker/src/openapi-sandbox-routes.ts index 6a763466..ebc679ce 100644 --- a/apps/gateway-worker/src/openapi-sandbox-routes.ts +++ b/apps/gateway-worker/src/openapi-sandbox-routes.ts @@ -4,17 +4,12 @@ import { BrowserTakeoverSessionSchema, BrowserTakeoverStatusSchema, SandboxConsoleSnapshotSchema, - SandboxFileListSchema, - SandboxFilePreviewSchema, - SandboxFileSchema, - SandboxFileWriteSchema, SandboxIdeSessionSchema, SandboxPreviewStatusSchema, SandboxPreviewWakeSchema, SandboxTerminalCommandSchema, SandboxTerminalContextSchema, SandboxTerminalResultSchema, - UpdateSandboxPathFileSchema, } from "@cheatcode/types"; import { type JsonValue, @@ -32,50 +27,13 @@ export const sandboxSchemas: Record = { BrowserTakeoverStatus: zodJsonSchema(BrowserTakeoverStatusSchema), OpenSandboxTerminal: zodJsonSchema(SandboxTerminalCommandSchema, "input"), SandboxConsoleSnapshot: zodJsonSchema(SandboxConsoleSnapshotSchema), - SandboxFile: zodJsonSchema(SandboxFileSchema), - SandboxFileList: zodJsonSchema(SandboxFileListSchema), - SandboxFilePreview: zodJsonSchema(SandboxFilePreviewSchema), - SandboxFileWrite: zodJsonSchema(SandboxFileWriteSchema), SandboxIdeSession: zodJsonSchema(SandboxIdeSessionSchema), SandboxPreviewStatus: zodJsonSchema(SandboxPreviewStatusSchema), SandboxPreviewWake: zodJsonSchema(SandboxPreviewWakeSchema), TerminalContext: zodJsonSchema(SandboxTerminalContextSchema), TerminalPreview: zodJsonSchema(SandboxTerminalResultSchema), - WriteSandboxFile: zodJsonSchema(UpdateSandboxPathFileSchema, "input"), }; -const sandboxEncodingParameter: JsonValue = { - in: "query", - name: "encoding", - schema: { enum: ["utf8", "base64"], type: "string" }, -}; - -const sandboxFilePathParameter: JsonValue = { - in: "query", - name: "path", - required: true, - schema: { - maxLength: 1_000, - pattern: "^/workspace(?:/(?!\\.{1,2}(?:/|$))[^/\\u0000]+)*$", - type: "string", - }, -}; - -const sandboxFileListParameters: JsonValue[] = [ - { - in: "query", - name: "path", - schema: { - default: "/workspace", - maxLength: 1_000, - pattern: "^/workspace(?:/(?!\\.{1,2}(?:/|$))[^/\\u0000]+)*$", - type: "string", - }, - }, - { in: "query", name: "recursive", schema: { default: true, type: "boolean" } }, - { in: "query", name: "includeHidden", schema: { default: false, type: "boolean" } }, -]; - export const sandboxRoutes: OpenApiRoute[] = [ { method: "get", @@ -169,16 +127,6 @@ export const sandboxRoutes: OpenApiRoute[] = [ summary: "Tail dev-server console output for a thread's sandbox", tags: ["sandbox"], }, - { - method: "get", - operationId: "listSandboxFiles", - parameters: sandboxFileListParameters, - path: "/v1/threads/{threadId}/sandbox/files", - responses: { "200": jsonResponse("Sandbox files", schemaRef("SandboxFileList")) }, - security: [{ bearerAuth: [] }], - summary: "List sandbox files for a thread", - tags: ["sandbox"], - }, { method: "get", operationId: "openSandboxIde", @@ -210,36 +158,6 @@ export const sandboxRoutes: OpenApiRoute[] = [ summary: "Wake the thread's preview sandbox and dev server", tags: ["sandbox"], }, - { - method: "get", - operationId: "readSandboxFile", - parameters: [sandboxFilePathParameter, sandboxEncodingParameter], - path: "/v1/threads/{threadId}/sandbox/file", - responses: { "200": jsonResponse("Sandbox file", schemaRef("SandboxFile")) }, - security: [{ bearerAuth: [] }], - summary: "Read a sandbox file by path", - tags: ["sandbox"], - }, - { - method: "get", - operationId: "previewSandboxFile", - parameters: [sandboxFilePathParameter], - path: "/v1/threads/{threadId}/sandbox/file-preview", - responses: { "200": jsonResponse("Sandbox file preview", schemaRef("SandboxFilePreview")) }, - security: [{ bearerAuth: [] }], - summary: "Preview a sandbox file by path", - tags: ["sandbox"], - }, - { - method: "patch", - operationId: "writeSandboxFile", - path: "/v1/threads/{threadId}/sandbox/file", - requestBody: jsonBody(schemaRef("WriteSandboxFile")), - responses: { "200": jsonResponse("Sandbox file write", schemaRef("SandboxFileWrite")) }, - security: [{ bearerAuth: [] }], - summary: "Write a sandbox file by path", - tags: ["sandbox"], - }, { method: "get", operationId: "readSandboxTerminalContext", diff --git a/apps/gateway-worker/src/openapi.ts b/apps/gateway-worker/src/openapi.ts index 050b36f4..0d05253e 100644 --- a/apps/gateway-worker/src/openapi.ts +++ b/apps/gateway-worker/src/openapi.ts @@ -1,13 +1,9 @@ import { - AgentSummarySchema, ClientErrorBodySchema, ClientUserEventBodySchema, CreateRunSchema, ErrorResponseSchema, OutputDownloadUrlResponseSchema, - RunStatusSnapshotSchema, - ToolDomainSchema, - ToolSummarySchema, WebVitalsBodySchema, } from "@cheatcode/types"; import { accountRoutes, accountSchemas } from "./openapi-account-routes"; @@ -33,7 +29,6 @@ import { zodJsonSchema } from "./openapi-zod"; const COMPONENT_SCHEMAS: Record = { ...integrationSchemas, - Agent: zodJsonSchema(AgentSummarySchema), ClientError: zodJsonSchema(ClientErrorBodySchema, "input"), ClientUserEvent: zodJsonSchema(ClientUserEventBodySchema, "input"), CreateRun: zodJsonSchema(CreateRunSchema, "input"), @@ -72,8 +67,6 @@ const COMPONENT_SCHEMAS: Record = { type: "object", }, OutputDownloadUrl: zodJsonSchema(OutputDownloadUrlResponseSchema), - RunStatus: zodJsonSchema(RunStatusSnapshotSchema), - Tool: zodJsonSchema(ToolSummarySchema), WebVitals: zodJsonSchema(WebVitalsBodySchema, "input"), }; @@ -85,11 +78,6 @@ const runStreamCursorParameter: JsonValue = { name: "lastSeq", schema: { default: 0, minimum: 0, type: "integer" }, }; -const toolDomainParameter: JsonValue = { - in: "query", - name: "domain", - schema: zodJsonSchema(ToolDomainSchema), -}; const outputDownloadParameters: JsonValue[] = [ { in: "query", @@ -152,18 +140,6 @@ const routes: OpenApiRoute[] = [ summary: "Resume an agent run stream", tags: ["runs"], }, - { - method: "get", - operationId: "getThreadRunStatus", - path: "/v1/threads/{threadId}/runs/status", - responses: { - "200": jsonResponse("Run status", schemaRef("RunStatus")), - "204": emptyResponse("No active run"), - }, - security: [{ bearerAuth: [] }], - summary: "Get active run status for a thread", - tags: ["runs"], - }, { method: "post", operationId: "cancelRun", @@ -208,25 +184,6 @@ const routes: OpenApiRoute[] = [ summary: "Download a signed generated output", tags: ["outputs"], }, - { - method: "get", - operationId: "listTools", - parameters: [toolDomainParameter], - path: "/v1/tools", - responses: { "200": jsonResponse("Tools", arraySchema("Tool")) }, - security: [{ bearerAuth: [] }], - summary: "List tools", - tags: ["metadata"], - }, - { - method: "get", - operationId: "listAgents", - path: "/v1/agents", - responses: { "200": jsonResponse("Agents", arraySchema("Agent")) }, - security: [{ bearerAuth: [] }], - summary: "List agents", - tags: ["metadata"], - }, ...sandboxRoutes, ...skillRoutes, { diff --git a/apps/gateway-worker/src/provider-http-routes.ts b/apps/gateway-worker/src/provider-http-routes.ts index 3bfdffa0..07b280a3 100644 --- a/apps/gateway-worker/src/provider-http-routes.ts +++ b/apps/gateway-worker/src/provider-http-routes.ts @@ -6,32 +6,14 @@ import { } from "@cheatcode/byok"; import { createDb, lockUserProviderKeyMutations, withUserContext } from "@cheatcode/db"; import { APIError, emitUserEvent, readJsonRequest } from "@cheatcode/observability"; -import { ProviderSchema, ToolDomainSchema, UpsertProviderKeySchema } from "@cheatcode/types"; +import { ProviderSchema, UpsertProviderKeySchema } from "@cheatcode/types"; import { authenticate } from "./authenticate"; import type { GatewayApp, GatewayContext } from "./gateway-env"; -import { listAgentsRoute, listToolsRoute } from "./metadata-routes"; import { rateLimit } from "./rate-limit"; const MAX_PROVIDER_KEY_REQUEST_BYTES = 32 * 1024; export function registerProviderHttpRoutes(app: GatewayApp): void { - app.get("/v1/tools", async (c) => { - const userId = await authenticate(c.req.raw, c.env, c.executionCtx); - await rateLimit(c, userId, "GET /v1/tools"); - const parsedDomain = ToolDomainSchema.optional().safeParse(c.req.query("domain")); - if (!parsedDomain.success) { - throw new APIError(400, "invalid_query_param", "Invalid tool domain", { - details: { issues: parsedDomain.error.issues.map((issue) => issue.message) }, - retriable: false, - }); - } - return listToolsRoute(parsedDomain.data); - }); - app.get("/v1/agents", async (c) => { - const userId = await authenticate(c.req.raw, c.env, c.executionCtx); - await rateLimit(c, userId, "GET /v1/agents"); - return listAgentsRoute(); - }); app.get("/v1/provider-keys", async (c) => { const userId = await authenticate(c.req.raw, c.env, c.executionCtx); await rateLimit(c, userId, "GET /v1/provider-keys"); diff --git a/apps/web/src/components/chat/message-timeline.ts b/apps/web/src/components/chat/message-timeline.ts index 708d5ace..c7f05841 100644 --- a/apps/web/src/components/chat/message-timeline.ts +++ b/apps/web/src/components/chat/message-timeline.ts @@ -42,6 +42,7 @@ export function isHiddenTranscriptPart(part: MessagePart): boolean { return ( part.type === "data-artifact" || part.type === "data-sandbox-status" || + /* retained for historical transcripts */ part.type === "data-plan" || part.type === "data-task-status" || part.type === "data-transcript-fragment" diff --git a/packages/agent-core/README.md b/packages/agent-core/README.md index b477541a..8107a39a 100644 --- a/packages/agent-core/README.md +++ b/packages/agent-core/README.md @@ -10,9 +10,9 @@ Mastra agents, tool registry, and workflow entrypoints. The tool and agent registries are statically constrained by the lightweight capability catalog in `@cheatcode/types`. A runtime capability cannot be added -or removed without updating the public `/v1/tools` or `/v1/agents` contract. -Sandbox-status and artifact-stream routing derive from the catalog's exact -runtime traits, so a tool's registry, discovery, and stream behavior move together. +or removed without updating that shared contract. Sandbox-status and +artifact-stream routing derive from the catalog's exact runtime traits, so a +tool's registry and stream behavior move together. Sandbox and artifact capabilities cross tool-domain boundaries only through `@cheatcode/sandbox-contracts`; concrete code-tool executors remain in `@cheatcode/tools-code`. diff --git a/packages/sandbox-contracts/src/runtime.ts b/packages/sandbox-contracts/src/runtime.ts index af5fea18..5e109ddf 100644 --- a/packages/sandbox-contracts/src/runtime.ts +++ b/packages/sandbox-contracts/src/runtime.ts @@ -177,10 +177,6 @@ export interface SandboxAllocateProjectPortInput { stack: "web" | "mobile"; } -interface SandboxGetProjectPortInput { - projectId: string; -} - export interface SandboxAllocateProcessPortInput { maxPort: number; minPort: number; @@ -193,7 +189,6 @@ export interface SandboxLike { deleteFile?(input: SandboxDeleteFileInput): Promise; ensureReady?(): Promise; exec?(input: SandboxExecInput): Promise; - getProjectPort?(input: SandboxGetProjectPortInput): Promise; getSignedPreviewUrl?(input: SandboxSignedPreviewUrlInput): Promise; killAllProcesses?(): Promise; killProcess?(input: SandboxKillProcessInput): Promise; diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index 7a075e8c..2d266ce5 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -305,13 +305,6 @@ export const ToolSummarySchema = z }) .strict(); -export const AgentSummarySchema = z - .object({ - description: z.string(), - name: z.string(), - }) - .strict(); - export const UpsertProviderKeySchema = z .object({ provider: ProviderSchema, @@ -354,18 +347,6 @@ export const SandboxFileSchema = z }) .strict(); -export const SandboxFilePreviewSchema = z - .object({ - content: z.string().max(30_000_000).nullable(), - encoding: z.literal("base64").nullable(), - error: z.string().max(1_000).nullable(), - kind: z.enum(["image", "pdf", "unsupported"]), - mimeType: z.string().min(1).max(200).nullable(), - path: SandboxFilePathSchema, - previewPath: SandboxFilePathSchema.nullable(), - }) - .strict(); - const UpdateSandboxFileSchema = z .object({ content: z.string().max(2_000_000), @@ -672,7 +653,6 @@ export type GreetingResponse = z.infer; export type SearchResponse = z.infer; export type SearchResult = z.infer; export type SearchResultThread = z.infer; -export type AgentSummary = z.infer; export type Integration = z.infer; export type IntegrationAccount = z.infer; export type IntegrationCatalog = z.infer; @@ -695,7 +675,6 @@ export type SandboxConsoleLine = z.infer; export type SandboxConsoleProcess = z.infer; export type SandboxConsoleSnapshot = z.infer; export type SandboxFileEntry = z.infer; -export type SandboxFilePreview = z.infer; export type SandboxIdeSession = z.infer; export type BrowserTakeoverStatus = z.infer; export type BrowserTakeoverSession = z.infer; diff --git a/packages/types/src/capabilities.ts b/packages/types/src/capabilities.ts index b72f458f..3c4dfb3a 100644 --- a/packages/types/src/capabilities.ts +++ b/packages/types/src/capabilities.ts @@ -1,4 +1,4 @@ -import type { AgentSummary, ToolSummary } from "./api"; +import type { ToolSummary } from "./api"; const REMOTE_TOOL = { producesArtifact: false, usesSandbox: false } as const; const SANDBOX_TOOL = { producesArtifact: false, usesSandbox: true } as const; @@ -77,19 +77,8 @@ export const TOOL_CAPABILITIES = [ /** Exact names accepted by the live Mastra tool registry. */ export type ToolCapabilityName = (typeof TOOL_CAPABILITIES)[number]["name"]; -/** - * Public agent discovery contract. Workflows remain discoverable through their - * tool capabilities and are intentionally not represented as Mastra agents. - */ -export const AGENT_CAPABILITIES = [ - { - description: "General Cheatcode agent with sandbox, research, browser, and artifact tools.", - name: "general", - }, -] as const satisfies readonly AgentSummary[]; - /** Exact names accepted by the live Mastra agent registry. */ -export type AgentCapabilityName = (typeof AGENT_CAPABILITIES)[number]["name"]; +export type AgentCapabilityName = "general"; function tool< const Domain extends ToolSummary["domain"], diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 8e709c18..d696c50a 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -23,7 +23,6 @@ export type { SandboxConsoleProcess, SandboxConsoleSnapshot, SandboxFileEntry, - SandboxFilePreview, SandboxHourPoint, SandboxIdeSession, SandboxPreviewStatus, @@ -47,7 +46,6 @@ export type { export { ActivityHistoryResponseSchema, ActivityQuerySchema, - AgentSummarySchema, BrowserTakeoverActiveSchema, BrowserTakeoverResumeResultSchema, BrowserTakeoverResumeSchema, @@ -87,7 +85,6 @@ export { SandboxConsoleSnapshotSchema, SandboxFileListSchema, SandboxFilePathSchema, - SandboxFilePreviewSchema, SandboxFileSchema, SandboxFileWriteSchema, SandboxIdeSessionSchema, @@ -146,7 +143,7 @@ export { SandboxUsageSummaryResponseSchema, } from "./billing"; export type { AgentCapabilityName, ToolCapabilityName } from "./capabilities"; -export { AGENT_CAPABILITIES, TOOL_CAPABILITIES } from "./capabilities"; +export { TOOL_CAPABILITIES } from "./capabilities"; export type { ErrorCode } from "./errors"; export { ErrorResponseSchema } from "./errors"; export { diff --git a/packages/types/src/ui-message.ts b/packages/types/src/ui-message.ts index f2907705..0481fabc 100644 --- a/packages/types/src/ui-message.ts +++ b/packages/types/src/ui-message.ts @@ -20,6 +20,7 @@ export const ModelFallbackDataSchema = z }) .strict(); +/* retained for historical transcripts */ const PlanDataSchema = z .object({ v: z.literal(1), From 46c17a9a7856262495fb3518709392fec17501ab Mon Sep 17 00:00:00 2001 From: iamjr15 Date: Mon, 27 Jul 2026 18:46:39 +0530 Subject: [PATCH 3/9] refactor: strip dead css, unused exports, barrel bloat, and config husks --- .dockerignore | 3 - .editorconfig | 6 - .gitignore | 4 - .vercelignore | 5 - AGENTS.md | 7 +- CLAUDE.md | 7 +- apps/agent-worker/package.json | 1 - apps/gateway-worker/package.json | 1 - apps/preview-proxy/README.md | 9 +- apps/preview-proxy/package.json | 1 - apps/web/src/app/(app)/layout.tsx | 10 +- apps/web/src/app/chat-markdown.css | 185 ---------- apps/web/src/app/effects.css | 136 +------- apps/web/src/app/globals.css | 321 ------------------ apps/web/src/app/layout.tsx | 1 - .../components/auth/protected-app-shell.tsx | 14 - apps/web/src/components/chat/chat-panel.tsx | 24 +- .../src/components/chat/message-activity.tsx | 2 +- .../web/src/components/chat/message-parts.tsx | 4 +- .../chat/prompt-composer-controller.ts | 14 +- .../src/components/chat/prompt-composer.tsx | 12 - .../components/chat/use-prompt-attachments.ts | 4 - .../src/components/home/home-workspace.tsx | 4 +- .../navigation/prompt-launch-button.tsx | 3 - .../components/preview/booting-computer.tsx | 11 - .../preview/preview-address-bar.tsx | 11 - .../components/preview/preview-side-panel.tsx | 16 +- .../components/preview/preview-url-bar.tsx | 8 +- .../shell/sidebar-expanded-navigation.tsx | 2 +- .../components/ui/cheatcode-cursor-field.tsx | 38 +-- apps/web/src/lib/error-reporter.ts | 4 +- apps/web/src/lib/navigation/nav-model.ts | 4 - apps/web/src/lib/rum.ts | 4 +- apps/web/src/lib/telemetry-page.ts | 8 - apps/webhooks-worker/package.json | 1 - biome.jsonc | 6 +- .../sandbox/skill-runtime/src/index.ts | 13 - .../sandbox/skill-runtime/src/json-input.ts | 94 ----- .../sandbox/skill-runtime/src/logging.ts | 52 --- .../sandbox/skill-runtime/src/runtime.ts | 37 -- .../sandbox/skill-runtime/src/types.ts | 14 - knip.jsonc | 18 +- packages/auth/README.md | 1 - packages/auth/src/crypto.ts | 10 - packages/auth/src/index.ts | 8 - packages/composio/src/index.ts | 18 +- packages/db/drizzle.config.ts | 2 +- packages/db/src/index.ts | 86 +---- packages/db/src/lifecycle.ts | 8 - packages/db/src/schema/drizzle.ts | 17 - packages/db/src/schema/index.ts | 2 + packages/env/src/index.ts | 5 - packages/env/src/web-config.ts | 5 - packages/observability/src/index.ts | 1 - packages/sandbox-contracts/src/index.ts | 15 - packages/skills/README.md | 1 + packages/tools-code/src/index.ts | 7 - packages/tools-media/src/index.ts | 2 - packages/types/src/api.ts | 2 - packages/types/src/index.ts | 7 +- turbo.json | 4 - 61 files changed, 107 insertions(+), 1213 deletions(-) delete mode 100644 apps/web/src/app/chat-markdown.css delete mode 100644 apps/web/src/components/auth/protected-app-shell.tsx delete mode 100644 apps/web/src/components/chat/prompt-composer.tsx delete mode 100644 apps/web/src/components/chat/use-prompt-attachments.ts delete mode 100644 apps/web/src/components/preview/booting-computer.tsx delete mode 100644 apps/web/src/components/preview/preview-address-bar.tsx delete mode 100644 apps/web/src/lib/telemetry-page.ts delete mode 100644 infra/containers/sandbox/skill-runtime/src/json-input.ts delete mode 100644 infra/containers/sandbox/skill-runtime/src/logging.ts delete mode 100644 packages/db/src/schema/drizzle.ts diff --git a/.dockerignore b/.dockerignore index 118585b6..246ebb3d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -17,7 +17,4 @@ *.log /*.png **/*.tsbuildinfo -coverage node_modules -qa-output -supabase/.temp diff --git a/.editorconfig b/.editorconfig index 15cf692a..6b7f9e3f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,11 +11,5 @@ indent_size = 2 [*.py] indent_size = 4 -[*.toml] -indent_size = 4 - [*.md] trim_trailing_whitespace = false - -[Makefile] -indent_style = tab diff --git a/.gitignore b/.gitignore index d5bdec05..639957bc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,11 +6,7 @@ node_modules/ .next/ .vercel/ dist/ -coverage/ .qa/ -qa-output/ -qa-*.png -*.har *.tsbuildinfo .env .env.* diff --git a/.vercelignore b/.vercelignore index bc48339e..dda7365a 100644 --- a/.vercelignore +++ b/.vercelignore @@ -1,7 +1,3 @@ -# Local documentation and planning directories are not part of the deploy bundle. -/docs/ -/tasks/ -/plans/ # Build artifacts (match anywhere; Vercel installs + builds fresh) node_modules .pnpm-store @@ -17,4 +13,3 @@ node_modules compose.yaml .dockerignore infra/containers/dev -supabase diff --git a/AGENTS.md b/AGENTS.md index a23ad7ee..38bec636 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,6 +41,7 @@ apps/ Deployable services packages/ Shared libraries agent-core/ Mastra instance + workflows tools-*/ Tool implementations per domain + tools-media/ Image generation and media editing tools db/ Drizzle schema (per-domain) + queries + migrations byok/ Vault-backed BYOK key store skills/ Build-time skill bundler @@ -49,9 +50,9 @@ packages/ Shared libraries types/ Zod schemas + branded IDs + InferAgentUIMessage ui/ Shared Cheatcode UI primitives, icon barrel, AI response renderer -skills/ 8 curated Anthropic SKILL.md skills -infra/ Wrangler configs, Supabase migrations, Daytona sandbox Dockerfile -scripts/ Operational helpers only: build skills, local startup, deploy orchestration, migrations +skills/ 19 curated Anthropic SKILL.md skills +infra/ Container images and Dockerfiles for local development and Daytona sandboxes +scripts/ Operational helpers: build-skills, dev, dev-worker-config, jsonc, migrate, migration-drizzle, database-operation-safety ``` ## Build diff --git a/CLAUDE.md b/CLAUDE.md index e251136d..de382eba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,6 +42,7 @@ packages/ tools-browser/ Stagehand LOCAL browser automation tools-docs/ pptxgenjs, docx, exceljs, @react-pdf/renderer tools-data/ Arquero CSV analysis + deterministic SVG charts + tools-media/ Image generation and media editing tools-research/ Exa + Firecrawl db/ Drizzle schema (per-domain) + queries + migrations byok/ Vault-backed BYOK with provider validation @@ -54,9 +55,9 @@ packages/ ui/ shared UI primitives, icon barrel, AI response renderer tsconfig/ Shared base/nextjs/worker/library configs -skills/ 8 curated Anthropic SKILL.md skills -infra/ Wrangler configs, Supabase migrations, Daytona sandbox Dockerfile/snapshot -scripts/ Operational helpers only: build skills, local startup, deploy orchestration, migrations, audit archive +skills/ 19 curated Anthropic SKILL.md skills +infra/ Container images and Dockerfiles for local development and Daytona sandboxes +scripts/ Operational helpers: build-skills, dev, dev-worker-config, jsonc, migrate, migration-drizzle, database-operation-safety ``` ## Critical conventions (non-negotiable) diff --git a/apps/agent-worker/package.json b/apps/agent-worker/package.json index e035b2f3..be80adc5 100644 --- a/apps/agent-worker/package.json +++ b/apps/agent-worker/package.json @@ -7,7 +7,6 @@ "types": "./dist/index.d.ts", "scripts": { "build": "wrangler deploy --dry-run", - "deploy": "wrangler deploy", "lint": "biome check .", "typecheck": "tsc -p tsconfig.json --noEmit" }, diff --git a/apps/gateway-worker/package.json b/apps/gateway-worker/package.json index 11e55423..cc1a36e8 100644 --- a/apps/gateway-worker/package.json +++ b/apps/gateway-worker/package.json @@ -7,7 +7,6 @@ "types": "./src/index.ts", "scripts": { "build": "wrangler deploy --dry-run", - "deploy": "wrangler deploy", "lint": "biome check .", "typecheck": "tsc -p tsconfig.json --noEmit" }, diff --git a/apps/preview-proxy/README.md b/apps/preview-proxy/README.md index a7c11bb9..651065a9 100644 --- a/apps/preview-proxy/README.md +++ b/apps/preview-proxy/README.md @@ -212,12 +212,9 @@ the shared `@cheatcode/observability` emitters. for Clerk, documentation, and the Vercel frontend hostname. `preview.trycheatcode.com` deliberately has no exact route and inherits the preview wildcard for release health checks. -- [`infra/cloudflare/production-route-contract.json`](../../infra/cloudflare/production-route-contract.json) - is the production contract. `stage-closed` creates only a missing exact - no-script route through the Workers Routes API before deploying the wildcard; - it never updates or deletes an existing route. Conflicts, semantic duplicates, - and overlapping wildcard routes stop the release. The contract is checked - again after preview deployment and before the gateway can reopen. +- The wildcard route is declared in + [`apps/preview-proxy/wrangler.jsonc`](./wrangler.jsonc) and deployed directly + by [`.github/workflows/deploy-cloudflare.yml`](../../.github/workflows/deploy-cloudflare.yml). - DNS: a **proxied** wildcard record `*` -> the zone (orange-cloud) so Cloudflare terminates TLS and runs this Worker for every sub-subdomain. - TLS: the wildcard is one label deep beyond the configured apex; Cloudflare diff --git a/apps/preview-proxy/package.json b/apps/preview-proxy/package.json index 11ad0304..6796a775 100644 --- a/apps/preview-proxy/package.json +++ b/apps/preview-proxy/package.json @@ -7,7 +7,6 @@ "types": "./src/index.ts", "scripts": { "build": "wrangler deploy --dry-run", - "deploy": "wrangler deploy", "lint": "biome check .", "typecheck": "tsc -p tsconfig.json --noEmit" }, diff --git a/apps/web/src/app/(app)/layout.tsx b/apps/web/src/app/(app)/layout.tsx index 8ba9a7a8..b8173090 100644 --- a/apps/web/src/app/(app)/layout.tsx +++ b/apps/web/src/app/(app)/layout.tsx @@ -1,6 +1,12 @@ import type { ReactNode } from "react"; -import { ProtectedAppShell } from "@/components/auth/protected-app-shell"; +import { AuthRequiredGate } from "@/components/auth/auth-required-gate"; +import { AppChrome } from "@/components/shell/app-chrome"; +import { WorkspaceLoadingState } from "@/components/workspace/workspace-route-state"; export default function AppLayout({ children }: { children: ReactNode }) { - return {children}; + return ( + + }>{children} + + ); } diff --git a/apps/web/src/app/chat-markdown.css b/apps/web/src/app/chat-markdown.css deleted file mode 100644 index 693ca4cf..00000000 --- a/apps/web/src/app/chat-markdown.css +++ /dev/null @@ -1,185 +0,0 @@ -.prose.chat-markdown { - & > * + * { - margin-top: 0.75em; - } - - & h1 { - margin-top: 1em; - margin-bottom: 0.5em; - font-weight: 700; - font-size: 1.5rem; - line-height: 1.2; - } - - & h2 { - margin-top: 0.8em; - margin-bottom: 0.4em; - font-weight: 600; - font-size: 1.25rem; - line-height: 1.3; - } - - & h3 { - margin-top: 0.6em; - margin-bottom: 0.3em; - font-weight: 600; - font-size: 1.125rem; - } - - & h4, - & h5, - & h6 { - margin-top: 0.5em; - margin-bottom: 0.25em; - font-weight: 600; - font-size: 1rem; - } - - & li > ul, - & li > ol { - margin-top: 0.25em; - margin-bottom: 0.25em; - } - - & ul, - & ol { - margin-top: 0.5em; - margin-bottom: 0.5em; - padding-left: 1.5em; - } - - & ul { - list-style-type: disc; - } - - & ol { - list-style-type: decimal; - } - - & li { - margin-top: 0.25em; - margin-bottom: 0.25em; - } - - & pre { - margin-top: 0.5em; - margin-bottom: 0.5em; - overflow-x: auto; - border-radius: 0.375rem; - background-color: rgba(9, 9, 11, 0.95); - padding: 0.75em 1em; - font-family: var(--font-mono); - } - - & pre code { - overflow-wrap: normal; - background-color: transparent; - padding: 0; - color: inherit; - font-size: 0.9em; - font-family: var(--font-mono); - white-space: pre; - word-break: normal; - } - - & code:not([class*="language-"]) { - border-radius: 3px; - background-color: var(--bg-secondary); - padding: 0.2em 0.4em; - font-size: 0.85em; - font-family: var(--font-mono); - word-break: break-word; - } - - & table { - width: 100%; - margin-top: 0.75em; - margin-bottom: 0.75em; - border-collapse: collapse; - font-size: 0.9em; - } - - & th { - background-color: var(--bg-secondary); - padding: 0.5em 0.75em; - font-weight: 600; - text-align: left; - } - - & td { - border: 1px solid #e2e8f0; - padding: 0.5em 0.75em; - } - - & blockquote { - margin-left: 0; - border-left: 3px solid #cbd5e1; - padding-left: 1em; - color: #475569; - font-style: italic; - } - - .dark & { - & pre { - background-color: rgba(9, 9, 11, 0.95); - } - - & code:not([class*="language-"]) { - background-color: rgba(9, 9, 11, 0.95); - color: #e4e4e7; - } - - & th { - border-color: #3f3f46; - background-color: #27272a; - } - - & td { - border-color: #3f3f46; - } - - & blockquote { - border-left-color: #52525b; - color: #a1a1aa; - } - - & .hljs-keyword, - & .hljs-selector-tag, - & .hljs-built_in, - & .hljs-name, - & .hljs-tag { - color: #60a5fa; - } - - & .hljs-string, - & .hljs-title, - & .hljs-section, - & .hljs-attribute, - & .hljs-literal, - & .hljs-template-tag, - & .hljs-template-variable, - & .hljs-type, - & .hljs-addition { - color: #4ade80; - } - - & .hljs-comment, - & .hljs-quote, - & .hljs-deletion, - & .hljs-meta { - color: #71717a; - } - - & .hljs-keyword, - & .hljs-selector-tag, - & .hljs-literal, - & .hljs-title, - & .hljs-section, - & .hljs-doctag, - & .hljs-type, - & .hljs-name, - & .hljs-strong { - font-weight: bold; - } - } -} diff --git a/apps/web/src/app/effects.css b/apps/web/src/app/effects.css index 8835bbd7..9dc875e9 100644 --- a/apps/web/src/app/effects.css +++ b/apps/web/src/app/effects.css @@ -1,53 +1,5 @@ @reference "./globals.css"; -.gradient-home-bg { - background-image: linear-gradient( - 156.2deg, - rgba(0, 0, 0, 1) 14.8%, - rgba(32, 104, 177, 1) 68.1%, - rgba(222, 229, 237, 1) 129% - ); -} - -.bg-checker-pattern { - background-position: - 0 0, - 0 10px, - 10px -10px, - -10px 0; - background-size: 20px 20px; - background-color: #fff; - background-image: - linear-gradient(45deg, #f3f4f6 25%, transparent 25%), - linear-gradient(-45deg, #f3f4f6 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, #f3f4f6 75%), - linear-gradient(-45deg, transparent 75%, #f3f4f6 75%); -} - -.dark .bg-checker-pattern-dark { - background-position: - 0 0, - 0 10px, - 10px -10px, - -10px 0; - background-size: 20px 20px; - background-color: rgba(24, 24, 27, 0.7); - background-image: - linear-gradient(45deg, rgba(39, 39, 42, 0.7) 25%, transparent 25%), - linear-gradient(-45deg, rgba(39, 39, 42, 0.7) 25%, transparent 25%), - linear-gradient(45deg, transparent 75%, rgba(39, 39, 42, 0.7) 75%), - linear-gradient(-45deg, transparent 75%, rgba(39, 39, 42, 0.7) 75%); -} - -@keyframes shimmer { - 0% { - transform: translateX(-100%); - } - 100% { - transform: translateX(200%); - } -} - @keyframes cc-heartbeat { 0%, 100% { @@ -67,96 +19,10 @@ } } -@keyframes gradient-shift { - 0% { - background-position: 0% 50%; - } - 50% { - background-position: 100% 50%; - } - 100% { - background-position: 0% 50%; - } -} - -@theme { - --animate-shimmer: shimmer 1s infinite; - --animate-gradient-shift: gradient-shift 2s ease infinite; -} - -.animate-shimmer { - @apply relative overflow-hidden rounded-md; - @apply bg-gradient-to-r from-primary/10 via-primary/5 to-primary/10; - background-size: 200% 200%; - animation: var(--animate-gradient-shift); -} - -.animate-shimmer::before { - @apply absolute top-0 left-0 w-full h-full; - width: 100%; - transform: translateX(-100%); - animation: var(--animate-shimmer); - background: linear-gradient( - 140deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.3) 50%, - rgba(255, 255, 255, 0) 100% - ); - content: ""; -} - -.animate-shimmer-gray { - @apply relative overflow-hidden rounded-md; - @apply bg-gradient-to-r from-gray-200 via-gray-100 to-gray-200; - background-size: 200% 200%; - animation: var(--animate-gradient-shift); -} - -.animate-shimmer-gray::before { - @apply absolute top-0 left-0 w-full h-full; - width: 100%; - transform: translateX(-100%); - animation: var(--animate-shimmer); - background: linear-gradient( - 140deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0.8) 50%, - rgba(255, 255, 255, 0) 100% - ); - content: ""; -} - -@theme inline { - --animate-shiny-text: shiny-text 5s infinite; - --animate-liquid-shimmer: liquid-shimmer 2s ease-in-out infinite; - - @keyframes shiny-text { - 0%, - 90%, - 100% { - background-position: calc(-100% - var(--shiny-width)) 0; - } - 30%, - 60% { - background-position: calc(100% + var(--shiny-width)) 0; - } - } - - @keyframes liquid-shimmer { - 0% { - background-position: 200% 0; - } - 100% { - background-position: -200% 0; - } - } -} - @media (prefers-reduced-motion: reduce) { .cheatcode-composer-working, .cc-fade-in, - .animate-spin, - .animate-pulse { + .animate-spin { animation: none; } } diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index a9c634b4..0cd9a415 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -150,19 +150,6 @@ --color-foreground: var(--foreground); --font-sans: "circular", var(--font-geist-sans); --font-mono: var(--font-geist-mono); - --color-sidebar-ring: var(--sidebar-ring); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar: var(--sidebar); - --color-chart-5: var(--chart-5); - --color-chart-4: var(--chart-4); - --color-chart-3: var(--chart-3); - --color-chart-2: var(--chart-2); - --color-chart-1: var(--chart-1); --color-ring: var(--ring); --color-input: var(--input); --color-border: var(--border); @@ -178,25 +165,19 @@ --color-primary: var(--primary); --color-popover-foreground: var(--popover-foreground); --color-popover: var(--popover); - --color-card-foreground: var(--card-foreground); - --color-card: var(--card); - --color-bg-primary: var(--bg-primary); --color-bg-elevated: var(--bg-elevated); --color-bg-secondary: var(--bg-secondary); --color-bg-lifted: var(--bg-lifted); --color-bg-inverse: var(--bg-inverse); - --color-fg-brand: var(--fg-brand); --color-fg-primary: var(--fg-primary); --color-fg-secondary: var(--fg-secondary); --color-fg-tertiary: var(--fg-tertiary); --color-fg-inverse: var(--fg-inverse); --color-brand-accent-fg: var(--brand-accent-fg); - --color-border-default: var(--border-default); --color-border-subtle: var(--border-subtle); --color-border-tree: var(--border-tree); --color-placeholder: var(--placeholder); --color-success-fg: var(--success-fg); - --color-success-bg: var(--success-bg); --color-danger-fg: var(--danger-fg); --color-danger-bg: var(--danger-bg); --radius-sm: calc(var(--radius) - 4px); @@ -204,216 +185,21 @@ --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); - /* Thread Screen Color System - Tailwind integration */ - --color-thread-panel: var(--thread-panel-bg); - --color-thread-panel-translucent: var(--thread-panel-bg-translucent); - --color-thread-surface: var(--thread-surface); --color-thread-surface-hover: var(--thread-surface-hover); - --color-thread-surface-subtle: var(--thread-surface-subtle); --color-thread-border: var(--thread-border); --color-thread-border-subtle: var(--thread-border-subtle); - --color-thread-border-hover: var(--thread-border-hover); - --color-thread-divider: var(--thread-divider); --color-thread-text-primary: var(--thread-text-primary); --color-thread-text-secondary: var(--thread-text-secondary); --color-thread-text-tertiary: var(--thread-text-tertiary); --color-thread-text-muted: var(--thread-text-muted); - --color-thread-text-placeholder: var(--thread-text-placeholder); - --color-thread-hover: var(--thread-hover-bg); - --color-thread-active: var(--thread-active-bg); - --color-thread-status-success: var(--thread-status-success); - --color-thread-status-success-bg: var(--thread-status-success-bg); - --color-thread-status-warning: var(--thread-status-warning); - --color-thread-status-warning-bg: var(--thread-status-warning-bg); - --color-thread-status-error: var(--thread-status-error); - --color-thread-status-error-bg: var(--thread-status-error-bg); - --color-thread-status-info: var(--thread-status-info); --color-thread-accent: var(--thread-accent-purple); --color-thread-accent-purple: var(--thread-accent-purple); - --color-thread-skeleton: var(--thread-skeleton-bg); - --color-thread-loading: var(--thread-loading-dot); - --animate-accordion-down: accordion-down 0.2s ease-out; - --animate-accordion-up: accordion-up 0.2s ease-out; - --animate-marquee: marquee var(--duration) infinite linear; - --animate-marquee-vertical: marquee-vertical var(--duration) linear infinite; - --animate-orbit: orbit calc(var(--duration) * 1s) linear infinite; - --animate-slide-down: slide-down 300ms cubic-bezier(0.87, 0, 0.13, 1); - --animate-slide-up: slide-up 300ms cubic-bezier(0.87, 0, 0.13, 1); - --scaleIn: scaleIn 200ms ease; - --scaleOut: scaleOut 200ms ease; - --fadeIn: fadeIn 200ms ease; - --fadeOut: fadeOut 200ms ease; - --enterFromLeft: enterFromLeft 250ms ease; - --enterFromRight: enterFromRight 250ms ease; - --exitToLeft: exitToLeft 250ms ease; - --exitToRight: exitToRight 250ms ease; - --animate-elliptical-orbit: elliptical-orbit 20s linear infinite; - @keyframes orbit { - 0% { - transform: rotate(calc(var(--angle) * 1deg)) translateY(calc(var(--radius) * 1px)) - rotate(calc(var(--angle) * -1deg)); - } - 100% { - transform: rotate(calc(var(--angle) * 1deg + 360deg)) translateY(calc(var(--radius) * 1px)) - rotate(calc((var(--angle) * -1deg) - 360deg)); - } - } - - @keyframes accordion-down { - from { - height: 0; - } - to { - height: var(--radix-accordion-content-height); - } - } - - @keyframes accordion-up { - from { - height: var(--radix-accordion-content-height); - } - to { - height: 0; - } - } - - @keyframes marquee { - from { - transform: translateX(0); - } - to { - transform: translateX(calc(-100% - var(--gap))); - } - } - - @keyframes marquee-vertical { - from { - transform: translateY(0); - } - to { - transform: translateY(calc(-100% - var(--gap))); - } - } - @keyframes slide-down { - from { - height: 0px; - } - to { - height: var(--radix-accordion-content-height); - } - } - - @keyframes slide-up { - from { - height: var(--radix-accordion-content-height); - } - to { - height: 0px; - } - } - - /* Add this to your globals.css */ - @keyframes enterFromRight { - from { - opacity: 0; - transform: translateX(200px); - } - to { - opacity: 1; - transform: translateX(0); - } - } - - @keyframes enterFromLeft { - from { - opacity: 0; - transform: translateX(-200px); - } - to { - opacity: 1; - transform: translateX(0); - } - } - - @keyframes exitToRight { - from { - opacity: 1; - transform: translateX(0); - } - to { - opacity: 0; - transform: translateX(200px); - } - } - - @keyframes exitToLeft { - from { - opacity: 1; - transform: translateX(0); - } - to { - opacity: 0; - transform: translateX(-200px); - } - } - - @keyframes scaleIn { - from { - opacity: 0; - transform: rotateX(-30deg) scale(0.9); - } - to { - opacity: 1; - transform: rotateX(0deg) scale(1); - } - } - - @keyframes scaleOut { - from { - opacity: 1; - transform: rotateX(0deg) scale(1); - } - to { - opacity: 0; - transform: rotateX(-10deg) scale(0.95); - } - } - - @keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } - } - - @keyframes fadeOut { - from { - opacity: 1; - } - to { - opacity: 0; - } - } - - @keyframes elliptical-orbit { - from { - transform: rotate(calc(var(--angle, 0) * 1deg)) translate(var(--h-radius, 160px), 0) - rotate(calc(var(--angle, 0) * -1deg)); - } - to { - transform: rotate(calc((var(--angle, 0) * 1deg) + 360deg)) - translate(var(--h-radius, 160px), 0) rotate(calc((var(--angle, 0) * -1deg) - 360deg)); - } - } } :root { --neutral-0: #fff; --neutral-50: #f7f7f7; --neutral-100: #f8f8f8; - --neutral-200: #eee; --neutral-250: #e4e4e4; --neutral-300: #bebebe; --neutral-400: #9b9b9b; @@ -428,7 +214,6 @@ --neutral-1000: #121212; --accent-p-300: #f9b96c; --accent-p-500: #fba62a; - --accent-p-700: #bb7400; --destructive-500: #cc272e; --destructive-400: #e85854; --bg-primary: var(--neutral-0); @@ -436,7 +221,6 @@ --bg-secondary: var(--neutral-100); --bg-lifted: var(--neutral-50); --bg-inverse: var(--neutral-950); - --fg-brand: var(--neutral-800); --fg-primary: var(--neutral-950); --fg-secondary: var(--neutral-500); --fg-tertiary: var(--neutral-700); @@ -446,11 +230,8 @@ --border-subtle: var(--neutral-100); --border-tree: var(--neutral-250); --accent-default: var(--accent-p-500); - --accent-muted: var(--accent-p-300); --background: var(--bg-primary); --foreground: var(--fg-primary); - --card: var(--bg-primary); - --card-foreground: var(--fg-primary); --popover: var(--bg-primary); --popover-foreground: var(--fg-primary); --primary: var(--accent-default); @@ -468,90 +249,24 @@ --placeholder: var(--neutral-500); --focus-ring: var(--neutral-950); --ring: var(--focus-ring); - --chart-1: #b84b00; - --chart-2: #008479; - --chart-3: #144e66; - --chart-4: #d6a62e; - --chart-5: #d58d25; --radius: 0.625rem; - --sidebar: var(--bg-elevated); - --sidebar-foreground: var(--fg-primary); - --sidebar-primary: var(--fg-primary); - --sidebar-primary-foreground: var(--fg-inverse); - --sidebar-accent: var(--bg-elevated); - --sidebar-accent-foreground: var(--fg-primary); - --sidebar-border: var(--border-default); - --sidebar-ring: var(--neutral-400); --success-fg: #007a77; - --success-bg: #e7f1f0; --danger-fg: #9a504b; --danger-bg: #f5eceb; --sidebar-lifted-shadow: 0 0 1px color-mix(in oklch, var(--foreground) 8%, transparent), inset 0 0 2px color-mix(in oklch, var(--foreground) 2%, transparent); - /* ============================================ - * THREAD SCREEN COLOR SYSTEM - * All thread-related colors centralized here - * ============================================ */ - - /* Thread Panel Backgrounds */ - --thread-panel-bg: var(--bg-primary); - --thread-panel-bg-translucent: color-mix(in srgb, var(--bg-primary) 88%, transparent); - --thread-surface: var(--bg-secondary); --thread-surface-hover: var(--bg-elevated); - --thread-surface-subtle: color-mix(in srgb, var(--bg-secondary) 68%, transparent); - - /* Thread Borders */ --thread-border: var(--border-default); --thread-border-subtle: var(--border-subtle); - --thread-border-hover: var(--border-tree); - --thread-divider: var(--border-tree); - - /* Thread Text Colors */ --thread-text-primary: var(--fg-primary); --thread-text-secondary: var(--fg-secondary); --thread-text-tertiary: var(--fg-tertiary); --thread-text-muted: var(--placeholder); - --thread-text-placeholder: var(--placeholder); - - /* Thread Interactive States */ - --thread-hover-bg: var(--bg-elevated); - --thread-active-bg: var(--bg-secondary); - - /* Thread Status Colors */ - --thread-status-success: var(--success-fg); - --thread-status-success-bg: var(--success-bg); - --thread-status-success-border: color-mix(in srgb, var(--success-fg) 20%, transparent); - --thread-status-success-glow: color-mix(in srgb, var(--success-fg) 22%, transparent); - - --thread-status-warning: var(--accent-default); - --thread-status-warning-bg: color-mix(in srgb, var(--accent-default) 14%, transparent); - --thread-status-warning-border: color-mix(in srgb, var(--accent-default) 30%, transparent); - - --thread-status-error: var(--danger-fg); - --thread-status-error-bg: var(--danger-bg); - --thread-status-error-border: color-mix(in srgb, var(--danger-fg) 22%, transparent); - --thread-status-error-text: var(--danger-fg); - - --thread-status-info: var(--fg-secondary); - - /* Thread Accent Colors */ --thread-accent-purple: var(--accent-default); - --thread-accent-purple-glow: color-mix(in srgb, var(--accent-default) 18%, transparent); - - /* Thread Message Bubbles */ --thread-user-message-bg: #f5f5f5; - --thread-assistant-message-bg: var(--bg-primary); - --thread-assistant-message-border: var(--border-default); - - /* Thread Code/Tool Colors */ --thread-code-bg: var(--bg-secondary); - --thread-tool-border: var(--border-default); - - /* Thread Skeleton/Loading */ - --thread-skeleton-bg: var(--bg-elevated); - --thread-loading-dot: var(--accent-default); } .dark { @@ -560,7 +275,6 @@ --bg-secondary: var(--neutral-950); --bg-lifted: var(--neutral-975); --bg-inverse: var(--neutral-50); - --fg-brand: var(--neutral-500); --fg-primary: var(--neutral-50); --fg-secondary: var(--neutral-400); --fg-tertiary: var(--neutral-300); @@ -571,8 +285,6 @@ --border-tree: var(--neutral-850); --background: var(--bg-primary); --foreground: var(--fg-primary); - --card: var(--bg-elevated); - --card-foreground: var(--fg-primary); --popover: var(--bg-elevated); --popover-foreground: var(--fg-primary); --primary: var(--accent-default); @@ -590,21 +302,7 @@ --placeholder: var(--neutral-400); --focus-ring: var(--neutral-50); --ring: var(--focus-ring); - --chart-1: #3c68d9; - --chart-2: #1ea87b; - --chart-3: #d58d25; - --chart-4: #9b5ad9; - --chart-5: #d64651; - --sidebar: var(--bg-elevated); - --sidebar-foreground: var(--fg-primary); - --sidebar-primary: var(--accent-default); - --sidebar-primary-foreground: var(--fg-inverse); - --sidebar-accent: var(--bg-secondary); - --sidebar-accent-foreground: var(--fg-primary); - --sidebar-border: var(--border-default); - --sidebar-ring: var(--neutral-600); --success-fg: #a9d9d6; - --success-bg: #007a772e; --danger-fg: #edc2bd; --danger-bg: #9a504b2e; --sidebar-lifted-shadow: @@ -638,19 +336,6 @@ padding: 0; } - /* Add font fallbacks for CJK characters */ - .cjk-text, - .prose p, - .prose li, - .prose table td, - .prose table th, - .markdown-content { - font-family: - var(--font-sans), ui-sans-serif, -apple-system, "Segoe UI", "Helvetica Neue", "Noto Sans", - "Noto Sans CJK JP", "Noto Sans CJK KR", "Noto Sans CJK SC", "Noto Sans CJK TC", sans-serif; - line-height: 1.7; - } - /* Specific handling for monospace/code with CJK character support */ code, pre, @@ -669,12 +354,6 @@ background: color-mix(in srgb, var(--bg-secondary) 60%, transparent); } - .paper-card { - border: 1px solid var(--border-default); - background: var(--bg-primary); - box-shadow: 0 0 1px rgba(0, 0, 0, 0.08); - } - .cheatcode-composer-shell { border: 2px solid var(--border-default); background: var(--bg-primary); diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index c65c556d..7cc7205b 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -6,7 +6,6 @@ import { GeistSans } from "geist/font/sans"; import type { Metadata } from "next"; import type { ReactNode } from "react"; import "./globals.css"; -import "./chat-markdown.css"; import "./effects.css"; import { ClientObservability } from "@/components/observability/client-observability"; import { Providers } from "./providers"; diff --git a/apps/web/src/components/auth/protected-app-shell.tsx b/apps/web/src/components/auth/protected-app-shell.tsx deleted file mode 100644 index 1a7f35ee..00000000 --- a/apps/web/src/components/auth/protected-app-shell.tsx +++ /dev/null @@ -1,14 +0,0 @@ -"use client"; - -import type { ReactNode } from "react"; -import { AuthRequiredGate } from "@/components/auth/auth-required-gate"; -import { AppChrome } from "@/components/shell/app-chrome"; -import { WorkspaceLoadingState } from "@/components/workspace/workspace-route-state"; - -export function ProtectedAppShell({ children }: { children: ReactNode }) { - return ( - - }>{children} - - ); -} diff --git a/apps/web/src/components/chat/chat-panel.tsx b/apps/web/src/components/chat/chat-panel.tsx index 1b0b6ce2..381501fd 100644 --- a/apps/web/src/components/chat/chat-panel.tsx +++ b/apps/web/src/components/chat/chat-panel.tsx @@ -2,7 +2,8 @@ import { ChatContextRow } from "@/components/chat/chat-context-row"; import { MessageList } from "@/components/chat/message-list"; -import { PromptComposer } from "@/components/chat/prompt-composer"; +import { usePromptComposerController } from "@/components/chat/prompt-composer-controller"; +import { PromptComposerView } from "@/components/chat/prompt-composer-view"; import { StreamReconnectBanner } from "@/components/chat/stream-reconnect-banner"; import { type ChatPanelProps, @@ -11,6 +12,16 @@ import { export function ChatPanel(props: ChatPanelProps) { const controller = useChatPanelController(props); + const promptComposerController = usePromptComposerController({ + onChange: controller.actions.setDraft, + onStop: controller.actions.stopRun, + onSubmit: controller.actions.submitText, + project: props.project, + resolvedModelId: props.latestModelId, + status: controller.state.composerStatus, + threadId: props.threadId, + value: controller.state.draft, + }); return (
- +
); } diff --git a/apps/web/src/components/chat/message-activity.tsx b/apps/web/src/components/chat/message-activity.tsx index 9121be53..09ae8e8c 100644 --- a/apps/web/src/components/chat/message-activity.tsx +++ b/apps/web/src/components/chat/message-activity.tsx @@ -135,7 +135,7 @@ function ActivityNarration({ text }: { text: string }) { return null; } return ( -
+
{text}
); diff --git a/apps/web/src/components/chat/message-parts.tsx b/apps/web/src/components/chat/message-parts.tsx index e1f8204f..5513545f 100644 --- a/apps/web/src/components/chat/message-parts.tsx +++ b/apps/web/src/components/chat/message-parts.tsx @@ -83,7 +83,7 @@ function UserMessageParts({ message }: { message: CheatcodeUIMessage }) { Skill Creator ) : null} -
+
{text}
@@ -99,7 +99,7 @@ interface MessagePartViewProps { function MessagePartView({ onContinue, part, threadId }: MessagePartViewProps) { if (part.type === "text") { return ( -
+
{part.text}
); diff --git a/apps/web/src/components/chat/prompt-composer-controller.ts b/apps/web/src/components/chat/prompt-composer-controller.ts index a737e054..9e57c4bb 100644 --- a/apps/web/src/components/chat/prompt-composer-controller.ts +++ b/apps/web/src/components/chat/prompt-composer-controller.ts @@ -13,10 +13,6 @@ import { useState, } from "react"; import type { RunStatus } from "@/components/chat/status-pill"; -import { - type PromptAttachments, - usePromptAttachments, -} from "@/components/chat/use-prompt-attachments"; import { composePromptWithComposerContext } from "@/components/composer/composer-context-chips"; import type { ComposerMenuItem } from "@/components/composer/composer-popover"; import { useProjectFileItems } from "@/components/composer/project-file-source"; @@ -26,6 +22,10 @@ import { type TriggerDetector, useComposerTriggers, } from "@/components/composer/use-composer-triggers"; +import { + type ProjectFileUploads, + useProjectFileUploads, +} from "@/components/composer/use-project-file-uploads"; import { listUserSkills, USER_SKILLS_QUERY } from "@/lib/api/skills"; import { detectMentionToken, detectSlashToken } from "@/lib/input/caret-tokens"; import { useAppStore } from "@/lib/store/app-store"; @@ -72,7 +72,7 @@ interface PromptComposerActions { export interface PromptComposerController { actions: PromptComposerActions; - attachments: PromptAttachments; + attachments: ProjectFileUploads; meta: { textareaRef: RefObject }; state: PromptComposerState; triggers: ComposerTriggers; @@ -92,7 +92,7 @@ export function usePromptComposerController(props: PromptComposerProps): PromptC textareaRef, value: props.value, }); - const attachments = usePromptAttachments({ + const attachments = useProjectFileUploads({ getToken, latestValueRef: publisher.latestValueRef, onChange: publisher.publishValue, @@ -225,7 +225,7 @@ function useProjectSelection(project: ProjectSummary | null) { } type PromptComposerAssemblyOptions = { - attachments: PromptAttachments; + attachments: ProjectFileUploads; computerOpen: boolean; isRunning: boolean; menu: ReturnType; diff --git a/apps/web/src/components/chat/prompt-composer.tsx b/apps/web/src/components/chat/prompt-composer.tsx deleted file mode 100644 index 1684023b..00000000 --- a/apps/web/src/components/chat/prompt-composer.tsx +++ /dev/null @@ -1,12 +0,0 @@ -"use client"; - -import { - type PromptComposerProps, - usePromptComposerController, -} from "@/components/chat/prompt-composer-controller"; -import { PromptComposerView } from "@/components/chat/prompt-composer-view"; - -export function PromptComposer(props: PromptComposerProps) { - const controller = usePromptComposerController(props); - return ; -} diff --git a/apps/web/src/components/chat/use-prompt-attachments.ts b/apps/web/src/components/chat/use-prompt-attachments.ts deleted file mode 100644 index 6359ed87..00000000 --- a/apps/web/src/components/chat/use-prompt-attachments.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - type ProjectFileUploads as PromptAttachments, - useProjectFileUploads as usePromptAttachments, -} from "@/components/composer/use-project-file-uploads"; diff --git a/apps/web/src/components/home/home-workspace.tsx b/apps/web/src/components/home/home-workspace.tsx index f16925ef..4763d051 100644 --- a/apps/web/src/components/home/home-workspace.tsx +++ b/apps/web/src/components/home/home-workspace.tsx @@ -10,7 +10,7 @@ import { HomeSessionChrome } from "@/components/home/home-session-chrome"; import { HomeSidebarOffset } from "@/components/home/home-sidebar-offset"; import { AppSidebar } from "@/components/shell/app-sidebar"; import { SidebarContentFrame } from "@/components/shell/sidebar-content-frame"; -import { CheatcodeCursorField } from "@/components/ui/cheatcode-cursor-field"; +import { CheatcodeCursorTrail } from "@/components/ui/cheatcode-cursor-field"; import { CheatcodeMark } from "@/components/ui/cheatcode-mark"; import { WorkspaceRunLayout } from "@/components/workspace/workspace-run-layout"; import { useAppStore } from "@/lib/store/app-store"; @@ -85,7 +85,7 @@ function HomeContentPane({ computerOpen }: { computerOpen: boolean }) {
- +
& { children: ReactNode; - onLaunch?: (() => void) | undefined; prompt: string; query?: Readonly> | undefined; }; @@ -18,7 +17,6 @@ type PromptLaunchButtonProps = Omit< /** Navigates with an opaque, one-time session key so prompt text never enters the URL. */ export function PromptLaunchButton({ children, - onLaunch, prompt, query, ...buttonProps @@ -37,7 +35,6 @@ export function PromptLaunchButton({ } } params.set("promptKey", createPromptHandoff(prompt).promptKey); - onLaunch?.(); router.push(`/?${params.toString()}`); } catch (error) { toast.error(error instanceof Error ? error.message : "Could not open that prompt."); diff --git a/apps/web/src/components/preview/booting-computer.tsx b/apps/web/src/components/preview/booting-computer.tsx deleted file mode 100644 index 80d2ee2d..00000000 --- a/apps/web/src/components/preview/booting-computer.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { CheatcodeLoader } from "@/components/ui/cheatcode-loader"; - -/** Bare brand-mark loading state for sandbox and preview cold starts. */ -export function BootingComputer({ label = "Booting computer" }: { label?: string }) { - return ( - - ); -} diff --git a/apps/web/src/components/preview/preview-address-bar.tsx b/apps/web/src/components/preview/preview-address-bar.tsx deleted file mode 100644 index e0d913ad..00000000 --- a/apps/web/src/components/preview/preview-address-bar.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { PreviewDeviceMenu } from "@/components/preview/preview-device-menu"; -import { PreviewPathInput } from "@/components/preview/preview-path-input"; - -export function PreviewAddressBar({ previewUrl }: { previewUrl: string | null }) { - return ( -
- - -
- ); -} diff --git a/apps/web/src/components/preview/preview-side-panel.tsx b/apps/web/src/components/preview/preview-side-panel.tsx index 4b3583b1..82053379 100644 --- a/apps/web/src/components/preview/preview-side-panel.tsx +++ b/apps/web/src/components/preview/preview-side-panel.tsx @@ -5,6 +5,7 @@ import { Monitor, Smartphone } from "@cheatcode/ui"; import { useAuth } from "@clerk/nextjs"; import { QRCodeSVG } from "qrcode.react"; import { Activity, type ReactNode, useEffect } from "react"; +import { CheatcodeLoader } from "@/components/ui/cheatcode-loader"; import { CheatcodeTooltip } from "@/components/ui/cheatcode-tooltip"; import { RecoveryCard } from "@/components/ui/recovery-card"; import { PreviewSessionRefresh, useStablePreviewSource } from "@/lib/preview/preview-session"; @@ -14,7 +15,6 @@ import type { PreviewDevice, PreviewTab } from "@/lib/store/app-store"; import { useAppStore } from "@/lib/store/app-store"; import { emitFirstPreviewOpened } from "@/lib/telemetry/user-events"; import { cn } from "@/lib/ui/cn"; -import { BootingComputer } from "./booting-computer"; import { ComputerPanelTabs } from "./computer-panel-tabs"; import { ComputerSurfaceFrame } from "./computer-surface-frame"; import { ComputerToggleButton } from "./computer-toggle-button"; @@ -351,7 +351,12 @@ function AppTab({ !hasProject && (sandboxStatus === "cold" || sandboxStatus === "starting") ) { - return ; + return ( + + ); } return ( @@ -413,7 +418,12 @@ function AppTabContent({ return ( } + content={ + + } /> ); } diff --git a/apps/web/src/components/preview/preview-url-bar.tsx b/apps/web/src/components/preview/preview-url-bar.tsx index 39dbdf1b..efeff384 100644 --- a/apps/web/src/components/preview/preview-url-bar.tsx +++ b/apps/web/src/components/preview/preview-url-bar.tsx @@ -1,4 +1,5 @@ -import { PreviewAddressBar } from "@/components/preview/preview-address-bar"; +import { PreviewDeviceMenu } from "@/components/preview/preview-device-menu"; +import { PreviewPathInput } from "@/components/preview/preview-path-input"; import { PreviewExternalLink, PreviewNavigationControls, @@ -13,7 +14,10 @@ export function PreviewUrlBar({ previewUrl }: { previewUrl: string | null }) {
- +
+ + +
diff --git a/apps/web/src/components/shell/sidebar-expanded-navigation.tsx b/apps/web/src/components/shell/sidebar-expanded-navigation.tsx index 3dbfc030..d7fbf974 100644 --- a/apps/web/src/components/shell/sidebar-expanded-navigation.tsx +++ b/apps/web/src/components/shell/sidebar-expanded-navigation.tsx @@ -208,7 +208,7 @@ function SidebarHelpCard({ item, pathname }: { item: NavItem; pathname: string } {item.label} - {item.description ?? "Learn what Cheatcode can do"} + Learn what Cheatcode can do diff --git a/apps/web/src/components/ui/cheatcode-cursor-field.tsx b/apps/web/src/components/ui/cheatcode-cursor-field.tsx index 8318b6b8..98f6b40f 100644 --- a/apps/web/src/components/ui/cheatcode-cursor-field.tsx +++ b/apps/web/src/components/ui/cheatcode-cursor-field.tsx @@ -20,32 +20,13 @@ const CURSOR_IMAGE_SIZE = 20; const INTERACTIVE_SELECTOR = 'a, button, input, textarea, select, summary, [role="button"], [contenteditable="true"], [data-cheatcode-ignore]'; -type FieldVariant = "home" | "loading"; - -type CheatcodeCursorFieldProps = { - className?: string | undefined; - variant?: FieldVariant | undefined; -}; - type Point = { x: number; y: number; }; /** Runs Cheatcode's cursor-trail interaction while preserving the native cursor. */ -export function CheatcodeCursorField({ className, variant = "home" }: CheatcodeCursorFieldProps) { - return ( - - ); -} - -function CheatcodeCursorTrail({ - className, - restrictToWhitespace, -}: { - className?: string | undefined; - restrictToWhitespace: boolean; -}) { +export function CheatcodeCursorTrail({ className }: { className?: string | undefined }) { const surfaceRef = useRef(null); const imageRefs = useRef>([]); const nextImageRef = useRef(0); @@ -65,13 +46,13 @@ function CheatcodeCursorTrail({ }).current; useEffect(() => setIsMounted(true), []); - useExactTrailMotion(motionRefs, restrictToWhitespace); + useExactTrailMotion(motionRefs); return (