diff --git a/apps/webapp/app/env.server.ts b/apps/webapp/app/env.server.ts index 1a49acddbc..9c95f902c3 100644 --- a/apps/webapp/app/env.server.ts +++ b/apps/webapp/app/env.server.ts @@ -436,6 +436,7 @@ const EnvironmentSchema = z.object({ EVENT_LOOP_MONITOR_ENABLED: z.string().default("1"), MAXIMUM_LIVE_RELOADING_EVENTS: z.coerce.number().int().default(1000), MAXIMUM_TRACE_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(25_000), + MAXIMUM_TRACE_DETAILED_SUMMARY_VIEW_COUNT: z.coerce.number().int().default(10_000), TASK_PAYLOAD_OFFLOAD_THRESHOLD: z.coerce.number().int().default(524_288), // 512KB TASK_PAYLOAD_MAXIMUM_SIZE: z.coerce.number().int().default(3_145_728), // 3MB BATCH_TASK_PAYLOAD_MAXIMUM_SIZE: z.coerce.number().int().default(1_000_000), // 1MB diff --git a/apps/webapp/app/v3/taskEventStore.server.ts b/apps/webapp/app/v3/taskEventStore.server.ts index 580541da9c..27fc498112 100644 --- a/apps/webapp/app/v3/taskEventStore.server.ts +++ b/apps/webapp/app/v3/taskEventStore.server.ts @@ -285,7 +285,7 @@ export class TaskEventStore { : Prisma.empty } ORDER BY "startTime" ASC - LIMIT ${env.MAXIMUM_TRACE_SUMMARY_VIEW_COUNT} + LIMIT ${env.MAXIMUM_TRACE_DETAILED_SUMMARY_VIEW_COUNT} `; } else { return await this.readReplica.$queryRaw` @@ -320,7 +320,7 @@ export class TaskEventStore { : Prisma.empty } ORDER BY "startTime" ASC - LIMIT ${env.MAXIMUM_TRACE_SUMMARY_VIEW_COUNT} + LIMIT ${env.MAXIMUM_TRACE_DETAILED_SUMMARY_VIEW_COUNT} `; } } diff --git a/packages/cli-v3/src/commands/dev.ts b/packages/cli-v3/src/commands/dev.ts index 7c82b46978..3253fdc573 100644 --- a/packages/cli-v3/src/commands/dev.ts +++ b/packages/cli-v3/src/commands/dev.ts @@ -107,47 +107,50 @@ export function configureDevCommand(program: Command) { export async function devCommand(options: DevCommandOptions) { runtimeChecks(); - const skipMCPInstall = typeof options.skipMCPInstall === "boolean" && options.skipMCPInstall; + // Only show these install prompts if the user is in a terminal (not in a Coding Agent) + if (process.stdout.isTTY) { + const skipMCPInstall = typeof options.skipMCPInstall === "boolean" && options.skipMCPInstall; - if (!skipMCPInstall) { - const hasSeenMCPInstallPrompt = readConfigHasSeenMCPInstallPrompt(); + if (!skipMCPInstall) { + const hasSeenMCPInstallPrompt = readConfigHasSeenMCPInstallPrompt(); - if (!hasSeenMCPInstallPrompt) { - const installChoice = await confirm({ - message: "Would you like to install the Trigger.dev MCP server?", - initialValue: true, - }); + if (!hasSeenMCPInstallPrompt) { + const installChoice = await confirm({ + message: "Would you like to install the Trigger.dev MCP server?", + initialValue: true, + }); - writeConfigHasSeenMCPInstallPrompt(true); + writeConfigHasSeenMCPInstallPrompt(true); - const skipInstall = isCancel(installChoice) || !installChoice; + const skipInstall = isCancel(installChoice) || !installChoice; - if (!skipInstall) { - log.step("Welcome to the Trigger.dev MCP server install wizard 🧙"); + if (!skipInstall) { + log.step("Welcome to the Trigger.dev MCP server install wizard 🧙"); - const [installError] = await tryCatch( - installMcpServer({ - yolo: false, - tag: VERSION as string, - logLevel: options.logLevel, - }) - ); + const [installError] = await tryCatch( + installMcpServer({ + yolo: false, + tag: VERSION as string, + logLevel: options.logLevel, + }) + ); - if (installError) { - log.error(`Failed to install MCP server: ${installError.message}`); + if (installError) { + log.error(`Failed to install MCP server: ${installError.message}`); + } } } } - } - const skipRulesInstall = - typeof options.skipRulesInstall === "boolean" && options.skipRulesInstall; + const skipRulesInstall = + typeof options.skipRulesInstall === "boolean" && options.skipRulesInstall; - if (!skipRulesInstall) { - await initiateRulesInstallWizard({ - manifestPath: options.rulesInstallManifestPath, - branch: options.rulesInstallBranch, - }); + if (!skipRulesInstall) { + await initiateRulesInstallWizard({ + manifestPath: options.rulesInstallManifestPath, + branch: options.rulesInstallBranch, + }); + } } const authorization = await login({ diff --git a/packages/cli-v3/src/commands/install-mcp.ts b/packages/cli-v3/src/commands/install-mcp.ts index 07219e07dd..c1d36374f7 100644 --- a/packages/cli-v3/src/commands/install-mcp.ts +++ b/packages/cli-v3/src/commands/install-mcp.ts @@ -233,12 +233,12 @@ export async function installMcpServer( ); log.info("More examples:"); - log.message(` • ${chalk.green('"List my Trigger.dev projects"')}`); - log.message(` • ${chalk.green('"Create a new Trigger.dev project called MyApp"')}`); - log.message(` • ${chalk.green('"Show me all tasks in my project"')}`); - log.message(` • ${chalk.green('"Trigger the email-notification task"')}`); + log.message(` • ${chalk.green('"Trigger the hello-world task"')}`); + log.message(` • ${chalk.green('"Can you help me debug the prod run run_1234"')}`); + log.message(` • ${chalk.green('"Deploy my trigger project to staging"')}`); + log.message(` • ${chalk.green('"What trigger task handles uploading files to S3?"')}`); log.message(` • ${chalk.green('"How do I create a scheduled task in Trigger.dev?"')}`); - log.message(` • ${chalk.green('"Search Trigger.dev docs for webhook examples"')}`); + log.message(` • ${chalk.green('"Search Trigger.dev docs for ffmpeg examples"')}`); log.info("Helpful links:"); log.message(` • ${cliLink("Trigger.dev docs", "https://trigger.dev/docs")}`); @@ -318,17 +318,13 @@ async function installMcpServerForClient( return; } - const clientSpinner = spinner(); - - clientSpinner.start(`Installing in ${clientName}`); - const scope = await resolveScopeForClient(clientName, options); - clientSpinner.message(`Installing in ${scope.scope} scope at ${scope.location}`); + // clientSpinner.message(`Installing in ${scope.scope} scope at ${scope.location}`); const configPath = await performInstallForClient(clientName, scope, options); - clientSpinner.stop(`Successfully installed in ${clientName} (${configPath})`); + // clientSpinner.stop(`Successfully installed in ${clientName} (${configPath})`); return { configPath, clientName, scope }; } diff --git a/packages/cli-v3/src/mcp/formatters.ts b/packages/cli-v3/src/mcp/formatters.ts index 8f693c5a89..12b3cf05dd 100644 --- a/packages/cli-v3/src/mcp/formatters.ts +++ b/packages/cli-v3/src/mcp/formatters.ts @@ -5,6 +5,8 @@ import { } from "@trigger.dev/core/v3/schemas"; import type { CursorPageResponse } from "@trigger.dev/core/v3/zodfetch"; +const DEFAULT_MAX_TRACE_LINES = 500; + export function formatRun(run: RetrieveRunResponse): string { const lines: string[] = []; @@ -170,14 +172,21 @@ function formatRelatedRuns(relatedRuns: RetrieveRunResponse["relatedRuns"]): str return parts.length > 0 ? `Related: ${parts.join("; ")}` : null; } -export function formatRunTrace(trace: RetrieveRunTraceResponseBody["trace"]): string { +export function formatRunTrace( + trace: RetrieveRunTraceResponseBody["trace"], + maxTraceLines: number = DEFAULT_MAX_TRACE_LINES +): string { const lines: string[] = []; lines.push(`Trace ID: ${trace.traceId}`); lines.push(""); // Format the root span and its children recursively - formatSpan(trace.rootSpan, lines, 0); + const reachedMaxLines = formatSpan(trace.rootSpan, lines, 0, maxTraceLines); + + if (reachedMaxLines) { + lines.push(`(truncated logs to ${maxTraceLines} lines)`); + } return lines.join("\n"); } @@ -185,8 +194,13 @@ export function formatRunTrace(trace: RetrieveRunTraceResponseBody["trace"]): st function formatSpan( span: RetrieveRunTraceResponseBody["trace"]["rootSpan"], lines: string[], - depth: number -): void { + depth: number, + maxLines: number +): boolean { + if (lines.length >= maxLines) { + return true; + } + const indent = " ".repeat(depth); const prefix = depth === 0 ? "└─" : "├─"; @@ -230,7 +244,7 @@ function formatSpan( } // Show output if it exists - if (span.data.output && Object.keys(span.data.output).length > 0) { + if (span.data.output) { lines.push( `${indent} Output: ${JSON.stringify(span.data.output, null, 2).replace( /\n/g, @@ -263,14 +277,20 @@ function formatSpan( // Recursively format children if (span.children) { - span.children.forEach((child, index) => { - formatSpan(child, lines, depth + 1); + const reachedMaxLines = span.children.some((child, index) => { + const reachedMaxLines = formatSpan(child, lines, depth + 1, maxLines); // Add spacing between sibling spans (except for the last one) - if (index < span.children.length - 1) { + if (index < span.children.length - 1 && !reachedMaxLines) { lines.push(""); } + + return reachedMaxLines; }); + + return reachedMaxLines; } + + return false; } function getStatusIndicator( diff --git a/packages/cli-v3/src/mcp/schemas.ts b/packages/cli-v3/src/mcp/schemas.ts index 104951647f..b98faca0da 100644 --- a/packages/cli-v3/src/mcp/schemas.ts +++ b/packages/cli-v3/src/mcp/schemas.ts @@ -123,7 +123,13 @@ export const CommonRunsInput = CommonProjectsInput.extend({ export type CommonRunsInput = z.output; -export const GetRunDetailsInput = CommonRunsInput.extend({}); +export const GetRunDetailsInput = CommonRunsInput.extend({ + maxTraceLines: z + .number() + .int() + .describe("The maximum number of lines to show in the trace. Defaults to 500") + .optional(), +}); export type GetRunDetailsInput = z.output; diff --git a/packages/cli-v3/src/mcp/tools/deploys.ts b/packages/cli-v3/src/mcp/tools/deploys.ts index 1c90150840..ab09659a54 100644 --- a/packages/cli-v3/src/mcp/tools/deploys.ts +++ b/packages/cli-v3/src/mcp/tools/deploys.ts @@ -74,7 +74,6 @@ export const deployTool = { cwd: cwd.cwd, env: { TRIGGER_MCP_SERVER: "1", - CI: "true", }, }, }); diff --git a/packages/cli-v3/src/mcp/tools/runs.ts b/packages/cli-v3/src/mcp/tools/runs.ts index ebe17be904..8a13603a23 100644 --- a/packages/cli-v3/src/mcp/tools/runs.ts +++ b/packages/cli-v3/src/mcp/tools/runs.ts @@ -35,7 +35,7 @@ export const getRunDetailsTool = { ]); const formattedRun = formatRun(runResult); - const formattedTrace = formatRunTrace(traceResult.trace); + const formattedTrace = formatRunTrace(traceResult.trace, input.maxTraceLines); const runUrl = await ctx.getDashboardUrl(`/projects/v3/${projectRef}/runs/${runResult.id}`); diff --git a/packages/cli-v3/src/rules/manifest.ts b/packages/cli-v3/src/rules/manifest.ts index 96b08d372d..f3bf73ba95 100644 --- a/packages/cli-v3/src/rules/manifest.ts +++ b/packages/cli-v3/src/rules/manifest.ts @@ -126,7 +126,7 @@ export class GithubRulesManifestLoader implements RulesManifestLoader { async loadRulesFile(relativePath: string): Promise { const response = await fetch( - `https://raw.githubusercontent.com/triggerdotdev/trigger.dev/refs/heads/${this.branch}/${relativePath}` + `https://raw.githubusercontent.com/triggerdotdev/trigger.dev/refs/heads/${this.branch}/rules/${relativePath}` ); if (!response.ok) { diff --git a/packages/core/package.json b/packages/core/package.json index f6f511d68e..55e93cfbf5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -187,7 +187,6 @@ "execa": "^8.0.1", "humanize-duration": "^3.27.3", "jose": "^5.4.0", - "lodash.get": "^4.4.2", "nanoid": "3.3.8", "prom-client": "^15.1.0", "socket.io": "4.7.4", diff --git a/packages/core/src/v3/schemas/api.ts b/packages/core/src/v3/schemas/api.ts index fff43ef7a1..da9f776568 100644 --- a/packages/core/src/v3/schemas/api.ts +++ b/packages/core/src/v3/schemas/api.ts @@ -1233,7 +1233,7 @@ export const RetrieveRunTraceSpanSchema = z.object({ runId: z.string(), taskSlug: z.string().optional(), taskPath: z.string().optional(), - events: z.array(z.any()), + events: z.array(z.any()).optional(), startTime: z.coerce.date(), duration: z.number(), isError: z.boolean(), @@ -1245,7 +1245,7 @@ export const RetrieveRunTraceSpanSchema = z.object({ queueName: z.string().optional(), machinePreset: z.string().optional(), properties: z.record(z.any()).optional(), - output: z.record(z.any()).optional(), + output: z.unknown().optional(), }), }); diff --git a/packages/core/src/v3/utils/ioSerialization.ts b/packages/core/src/v3/utils/ioSerialization.ts index b3049187e8..103260b85c 100644 --- a/packages/core/src/v3/utils/ioSerialization.ts +++ b/packages/core/src/v3/utils/ioSerialization.ts @@ -12,7 +12,7 @@ import { SemanticInternalAttributes } from "../semanticInternalAttributes.js"; import { TriggerTracer } from "../tracer.js"; import { zodfetch } from "../zodfetch.js"; import { flattenAttributes } from "./flattenAttributes.js"; -import get from "lodash.get"; +import { JSONHeroPath } from "@jsonhero/path"; export type IOPacket = { data?: string | undefined; @@ -536,7 +536,7 @@ export async function replaceSuperJsonPayload(original: string, newPayload: stri .map(([key]) => key); const overridenUndefinedKeys = originalUndefinedKeys.filter( - (key) => get(newPayloadObject, key) !== undefined + (key) => getKeyFromObject(newPayloadObject, key) !== undefined ); overridenUndefinedKeys.forEach((key) => { @@ -551,3 +551,9 @@ export async function replaceSuperJsonPayload(original: string, newPayload: stri return superjson.deserialize(newSuperJson); } + +function getKeyFromObject(object: unknown, key: string) { + const jsonHeroPath = new JSONHeroPath(key); + + return jsonHeroPath.first(object); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 255af411b5..57a40896ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1576,9 +1576,6 @@ importers: jose: specifier: ^5.4.0 version: 5.4.0 - lodash.get: - specifier: ^4.4.2 - version: 4.4.2 nanoid: specifier: 3.3.8 version: 3.3.8 @@ -28730,11 +28727,6 @@ packages: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} dev: true - /lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} - deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. - dev: false - /lodash.groupby@4.6.0: resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} dev: false