Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/browser-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"devDependencies": {
"@babel/generator": "^7.28.0",
"@babel/parser": "^7.28.0",
"@babel/traverse": "^7.27.0",
"@babel/traverse": "^7.28.0",
"@babel/types": "^7.28.1",
"@crxjs/vite-plugin": "2.0.0-beta.30",
"@tailwindcss/vite": "^4.1.11",
Expand Down
17 changes: 9 additions & 8 deletions apps/browser-extension/src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { executeCode } from '@evaluate/engine/execute';
import { searchRuntimes } from '@evaluate/engine/runtimes';
import {
getRuntimeDefaultFileName,
searchRuntimes,
} from '@evaluate/engine/runtimes';
import type { ExecuteResult, PartialRuntime } from '@evaluate/shapes';
import type { ProtocolWithReturn } from 'webext-bridge';
import { onMessage, sendMessage } from 'webext-bridge/background';
Expand Down Expand Up @@ -67,21 +70,19 @@ browser.contextMenus.onClicked.addListener(async (info, tab) => {

const promises = [];
for (const runtime of runtimes) {
const fileName = getRuntimeDefaultFileName(runtime.id) ?? 'file.code';
const initialPromise = executeCode({
runtime: runtime.id,
// TODO: Use the get runtime default file name function
files: { 'file.code': code },
entry: 'file.code',
files: { [fileName]: code },
entry: fileName,
})
.then((result) => {
posthog?.capture('executed_code', {
runtime_id: runtime.id,
code_length: code.length,
code_lines: code.split('\n').length,
compile_successful: result.compile ? result.compile.code === 0 : null,
execution_successful:
result.run.code === 0 &&
(!result.compile || result.compile.code === 0),
compile_successful: result.compile?.success ?? null,
execution_successful: result.success,
});
return result;
})
Expand Down
38 changes: 20 additions & 18 deletions apps/browser-extension/src/content-script/execution/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,27 @@ export function ExecutionDialog({
</DialogHeader>

<DialogContent>
<Tabs defaultValue={runtimes[~successIndex ? successIndex : 0]?.id}>
<TabsList className="w-full">
{runtimes.map((runtime) => (
<TabsTrigger key={runtime.id} value={runtime.id}>
{runtime.name}
</TabsTrigger>
))}
</TabsList>
{results.length > 0 && (
<Tabs defaultValue={runtimes[~successIndex ? successIndex : 0]?.id}>
<TabsList className="w-full">
{runtimes.map((runtime) => (
<TabsTrigger key={runtime.id} value={runtime.id}>
{runtime.name}
</TabsTrigger>
))}
</TabsList>

{runtimes.map((runtime, i) => (
<TabsContent key={runtime.id} value={runtime.id}>
<ResultDialog
code={code}
runtime={runtime}
result={results[i]!}
/>
</TabsContent>
))}
</Tabs>
{runtimes.map((runtime, i) => (
<TabsContent key={runtime.id} value={runtime.id}>
<ResultDialog
code={code}
runtime={runtime}
result={results[i]!}
/>
</TabsContent>
))}
</Tabs>
)}
</DialogContent>
</DialogBody>
</Dialog>
Expand Down
21 changes: 11 additions & 10 deletions apps/browser-extension/src/content-script/execution/result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Label } from '@evaluate/components/label';
import { Textarea } from '@evaluate/components/textarea';
import type { ExecuteResult, PartialRuntime } from '@evaluate/shapes';
import { ExternalLinkIcon } from 'lucide-react';
import { useMemo } from 'react';
import { twMerge as cn } from 'tailwind-merge';
import { makeEditCodeUrl, makePickRuntimeUrl } from '~/helpers/make-url';

Expand All @@ -16,11 +15,13 @@ export function ResultDialog({
runtime: PartialRuntime;
result: ExecuteResult;
}) {
const display = useMemo(() => {
if (!result) return { code: undefined, output: undefined };
if (result.compile?.code) return result.compile;
return result.run;
}, [result]);
let output = result.output;
if (result.compile?.expired)
output =
'Your code compilation exceeded the allotted time and was terminated. Consider optimising your code for faster compilation.';
else if (result.run.expired)
output =
'Your code execution exceeded the allotted time and was terminated. Consider optimising it for better performance.';

return (
<div className="space-y-2">
Expand All @@ -29,12 +30,12 @@ export function ResultDialog({
<Textarea
readOnly
name="output"
value={display.output}
placeholder="The code ran successfully, but it didn't produce an output to the console."
value={output}
placeholder="Your code executed successfully; however, it did not generate any output for the console."
className={cn(
'min-h-[40vh] w-full resize-none border-2',
display.code && 'border-destructive',
display.output && 'font-mono',
!result.success && 'border-destructive',
result.output && 'font-mono',
)}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/discord-bot/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@
"zod": "4.0.5"
},
"devDependencies": {
"tsup": "^8.4.0"
"tsup": "^8.5.0"
}
}
8 changes: 4 additions & 4 deletions apps/discord-bot/src/components/evaluate-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ class ArgumentsInput extends TextInput {
customId = 'args';
label = 'Arguments';
placeholder = 'Additional command line arguments to pass to the program.';
style = TextInputStyle.Paragraph;
minLength = 1;
style = TextInputStyle.Short;
minLength = 0;
maxLength = 500;
required = false;
}
Expand All @@ -82,8 +82,8 @@ class InputInput extends TextInput {
customId = 'input';
label = 'Input';
placeholder = 'The STDIN input to provide to the program.';
style = TextInputStyle.Paragraph;
minLength = 1;
style = TextInputStyle.Short;
minLength = 0;
maxLength = 500;
required = false;
}
90 changes: 27 additions & 63 deletions apps/discord-bot/src/handlers/evaluate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@ import {
Row,
type User,
} from '@buape/carbon';
import { compress } from '@evaluate/engine/compress';
import { executeCode } from '@evaluate/engine/execute';
import {
getRuntimeDefaultFileName,
searchRuntimes,
} from '@evaluate/engine/runtimes';
import type { ExecuteResult, PartialRuntime } from '@evaluate/shapes';
import { EditEvaluationButton } from '~/components/edit-evaluation-button';
import { OpenEvaluationButton } from '~/components/open-evaluation-button';
import env from '~/env';
import { captureEvent } from '~/services/posthog';
import { codeBlock } from '~/utilities/discord-formatting';
import { getInteractionContext } from '~/utilities/session-context';
import { EditEvaluationButton } from '~/components/edit-evaluation-button.js';
import { OpenEvaluationButton } from '~/components/open-evaluation-button.js';
import { captureEvent } from '~/services/posthog.js';
import { codeBlock } from '~/utilities/discord-formatting.js';
import { makeEditCodeUrl } from '~/utilities/make-url.js';
import { getInteractionContext } from '~/utilities/session-context.js';

function isNew(
interaction: CommandInteraction | ModalInteraction,
Expand All @@ -42,30 +41,11 @@ function isEdit(
);
}

function compressOptions(options: {
runtime: PartialRuntime;
code: string;
args?: string;
input?: string;
}) {
const identifier =
typeof options.runtime === 'string' ? options.runtime : options.runtime.id;
const fileName = getRuntimeDefaultFileName(identifier) ?? 'file.code';
return compress({
files: {
[fileName]: options.code,
'::input::': options.input,
'::args::': options.args,
},
entry: fileName,
focused: fileName,
});
}

export async function handleEvaluating(
interaction: CommandInteraction | ModalInteraction,
options: { runtime: string; code: string; args?: string; input?: string },
) {
// HACK: If trying to edit an existing evaluation owned by another user, create new instead
if (
interaction.rawData.message &&
interaction.rawData.message.interaction_metadata?.user.id !==
Expand Down Expand Up @@ -93,9 +73,10 @@ export async function handleEvaluating(
throw new Error(message);
}

const fileName = getRuntimeDefaultFileName(runtime.id) ?? 'file.code';
const executeOptions = {
files: { 'file.code': options.code },
entry: 'file.code',
files: { [fileName]: options.code },
entry: fileName,
input: options.input,
args: options.args,
};
Expand All @@ -116,37 +97,23 @@ export async function handleEvaluating(
runtime_id: runtime.id,
code_length: options.code.length,
code_lines: options.code.split('\n').length,
compile_successful: result.compile ? result.compile.code === 0 : null,
execution_successful:
result.run.code === 0 && (!result.compile || result.compile.code === 0),
compile_successful: result.compile?.success ?? null,
execution_successful: result.success,
});

const resultKey = result?.compile?.code ? 'compile' : 'run';
const hasTimedOut = result[resultKey]?.signal === 'SIGKILL';
const doesHaveDisplayableOutput = result[resultKey]?.output?.trim() !== '';

let output = result[resultKey]!.output;
if (!doesHaveDisplayableOutput) {
// TODO: This stuff would be better handled by the executeCode function
const isRun = resultKey === 'run';
if (hasTimedOut) {
if (isRun)
output =
'Your code execution exceeded the allotted time and was terminated. Consider optimising it for better performance.';
else
output =
'Your code compilation exceeded the allotted time and was terminated. Consider optimising your code for faster compilation.';
} else {
output =
'Your code executed successfully; however, it did not generate any output for the console.';
}
} else if (output.length > 1000) {
output = `Output was too large to display, [click here to view the full output](${
env.WEBSITE_URL
}/playgrounds/${runtime.id}#${compressOptions({ ...options, runtime })}).`;
} else {
output = codeBlock(output, 1000);
}
let output = result.output;
if (result.compile?.expired)
output =
'Your code compilation exceeded the allotted time and was terminated. Consider optimising your code for faster compilation.';
else if (result.run.expired)
output =
'Your code execution exceeded the allotted time and was terminated. Consider optimising it for better performance.';
else if (!output)
output =
'Your code executed successfully; however, it did not generate any output for the console.';
else if (output.length > 900)
output = `Output was too large to display, [click here to view the full output](${makeEditCodeUrl(options)})`;
else output = codeBlock(output, 1000);

return interaction.reply(
createEvaluationPayload(
Expand All @@ -172,10 +139,7 @@ export function createEvaluationPayload(
const embed = new Embed({
title: 'Code Evaluation',
description: `**${options.runtime.name}**\n${codeBlock(options.runtime.aliases[0]!, options.code, 4000)}`,
color:
result.run.code === 0 && (!result.compile || result.compile.code === 0)
? 0x2fc086
: 0xff0000,
color: result.success ? 0x2fc086 : 0xff0000,
fields: [],
author: user
? { name: user.username!, icon_url: user.avatarUrl! }
Expand Down Expand Up @@ -205,7 +169,7 @@ export function createEvaluationPayload(
new Row([
new EditEvaluationButton(),
new OpenEvaluationButton(
`${env.WEBSITE_URL}playgrounds/${options.runtime.id}#${compressOptions(options)}`,
makeEditCodeUrl({ ...options, runtime: options.runtime.id }),
),
]),
],
Expand Down
41 changes: 41 additions & 0 deletions apps/discord-bot/src/utilities/make-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// TODO: Move with apps/browser-extension/src/helpers/make-url.ts to shared package

import { compress } from '@evaluate/engine/compress';
import { getRuntimeDefaultFileName } from '@evaluate/engine/runtimes';
import env from '~/env';

export function makeEditCodeUrl(options: {
runtime: string;
code: string;
args?: string;
input?: string;
}) {
const fileName = getRuntimeDefaultFileName(options.runtime) ?? 'file.code';
const state = compress({
files: {
[fileName]: options.code,
'::args::': options.args,
'::input::': options.input,
},
entry: fileName,
focused: fileName,
});
return `${env.WEBSITE_URL}playgrounds/${options.runtime}#${state}`;
}

export function makePickRuntimeUrl(options: {
code: string;
args?: string;
input?: string;
}) {
const state = compress({
files: {
'file.code': options.code,
'::args::': options.args,
'::input::': options.input,
},
entry: 'file.code',
focused: 'file.code',
});
return `${env.WEBSITE_URL}playgrounds#${state}`;
}
4 changes: 2 additions & 2 deletions apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"jszip": "^3.10.1",
"lucide-react": "^0.525.0",
"material-icon-theme": "^5.24.0",
"next": "^15.3.5",
"next": "15.3.5",
"next-themes": "npm:@wits/next-themes@^0.2.16",
"posthog-js": "^1.257.0",
"react": "^19.1.0",
Expand All @@ -55,7 +55,7 @@
},
"devDependencies": {
"@million/lint": "^1.0.14",
"@next/bundle-analyzer": "^15.4.1",
"@next/bundle-analyzer": "15.3.5",
"@tailwindcss/postcss": "^4.1.11",
"@types/file-saver": "^2.0.7",
"@types/react": "^19.1.8",
Expand Down
Loading