Skip to content

Commit acf0448

Browse files
run stuff in parallel!
1 parent ea2b05c commit acf0448

File tree

10 files changed

+104
-27
lines changed

10 files changed

+104
-27
lines changed

app/components/chat/Chat.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ export const Chat = memo(
277277
},
278278
});
279279

280+
(window as any).chefMessages = messages;
281+
280282
useEffect(() => {
281283
const prompt = searchParams.get('prompt');
282284

app/components/chat/ToolCall.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import { deployToolParameters } from '~/lib/runtime/deployTool';
3232
import type { ZodError } from 'zod';
3333
import { Spinner } from '@ui/Spinner';
3434
import { FolderIcon } from '@heroicons/react/24/outline';
35+
import { getRelativePath } from '~/lib/stores/files';
36+
import { outputLabels } from '~/lib/runtime/deployToolOutputLabels';
3537

3638
export const ToolCall = memo(function ToolCall({ partId, toolCallId }: { partId: PartId; toolCallId: string }) {
3739
const userToggledAction = useRef(false);
@@ -394,7 +396,7 @@ function toolTitle(invocation: ConvexToolInvocation): React.ReactNode {
394396
extra = ` (lines ${start} - ${endName})`;
395397
}
396398
if (args.success) {
397-
renderedPath = args.data.path || '/home/project';
399+
renderedPath = getRelativePath(args.data.path) || '/home/project';
398400
}
399401
return (
400402
<div className="flex items-center gap-2">
@@ -429,10 +431,8 @@ function toolTitle(invocation: ConvexToolInvocation): React.ReactNode {
429431
);
430432
} else if (invocation.result?.startsWith('Error:')) {
431433
if (
432-
// This is a hack, but `npx convex dev` prints this out when the typecheck fails
433-
invocation.result.includes('To ignore failing typecheck') ||
434-
// this is a bigger hack! TypeScript fails with error codes like TS
435-
invocation.result.includes('Error TS')
434+
invocation.result.includes(outputLabels.convexTypecheck) ||
435+
invocation.result.includes(outputLabels.frontendTypecheck)
436436
) {
437437
return (
438438
<div className="flex items-center gap-2">

app/lib/runtime/action-runner.ts

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { z } from 'zod';
1717
import { editToolParameters } from './editTool';
1818
import { getAbsolutePath } from '~/lib/stores/files';
1919
import { streamOutput } from '~/utils/process';
20+
import { outputLabels, type OutputLabels } from './deployToolOutputLabels';
2021

2122
const logger = createScopedLogger('ActionRunner');
2223

@@ -372,25 +373,88 @@ export class ActionRunner {
372373
case 'deploy': {
373374
const container = await this.#webcontainer;
374375
await waitForContainerBootState(ContainerBootState.READY);
375-
const convexProc = await container.spawn('sh', [
376-
'-c',
377-
'eslint . && convex dev --once && tsc --noEmit -p tsconfig.app.json',
378-
]);
379-
action.abortSignal.addEventListener('abort', () => {
380-
convexProc.kill();
381-
});
382-
383-
const { output, exitCode } = await streamOutput(convexProc, {
384-
onOutput: (output) => {
385-
this.terminalOutput.set(output);
386-
},
387-
debounceMs: 50,
388-
});
389-
const cleanedOutput = cleanConvexOutput(output);
390-
if (exitCode !== 0) {
391-
throw new Error(`Convex failed with exit code ${exitCode}: ${cleanedOutput}`);
376+
377+
// TODO need to get the output into here
378+
result = '';
379+
380+
/** Return a promise of output on success, throws an error containing output on failure. */
381+
const run = async (command: string, args: string[], errorPrefix: OutputLabels): Promise<string> => {
382+
const t0 = performance.now();
383+
const proc = await container.spawn(command, args);
384+
let abortListener: () => void = () => {
385+
proc.kill();
386+
};
387+
action.abortSignal.addEventListener('abort', abortListener);
388+
const { output: output, exitCode: exitCode } = await streamOutput(proc, {
389+
onOutput: (output) => {
390+
this.terminalOutput.set(output);
391+
},
392+
debounceMs: 50,
393+
});
394+
395+
const cleanedOutput = cleanConvexOutput(output);
396+
const time = performance.now() - t0;
397+
logger.trace('finished', errorPrefix, 'in', Math.round(time));
398+
if (exitCode !== 0) {
399+
throw new Error(`[${errorPrefix}] Failed with exit code ${exitCode}: ${cleanedOutput}`);
400+
}
401+
action.abortSignal.removeEventListener('abort', abortListener);
402+
return cleanedOutput + '\n\n';
403+
};
404+
405+
/*
406+
result += await run(
407+
'sh',
408+
[
409+
'-c',
410+
'convex codegen' +
411+
' && tsc --noEmit -p tsconfig.app.json' +
412+
' && eslint convex' +
413+
' && convex dev --once --typecheck=disable',
414+
],
415+
'do everything' as any,
416+
);
417+
*/
418+
419+
const t0 = performance.now();
420+
result += await run('convex', ['codegen', '--typecheck=disable'], outputLabels.convexTypecheck);
421+
422+
// what if we ran tsc, eslint, and deploy all at the same time?
423+
const tscP = await run('tsc', ['--noEmit', '-p', 'tsconfig.app.json'], outputLabels.frontendTypecheck);
424+
425+
const eslintP = (async function maybeRunEslint(): Promise<string> {
426+
// Only run eslint if the file we expect is present and contains '@convex-dev/eslint-plugin'
427+
// Projects created with older versions of Chef have this file but it does not container
428+
// @convex-dev/eslint-plugin.
429+
let contents = '';
430+
try {
431+
contents = await container.fs.readFile('eslint.config.js', 'utf-8');
432+
} catch (e: any) {
433+
if (!e.message.includes('ENOENT: no such file or directory')) {
434+
throw e;
435+
}
436+
}
437+
if (contents.includes('@convex-dev/eslint-plugin')) {
438+
await run('eslint', ['convex'], outputLabels.convexLint);
439+
}
440+
return '';
441+
})();
442+
443+
const deployP = run('convex', ['dev', '--once', '--typecheck=disable'], outputLabels.convexDeploy);
444+
445+
const [tscResult, eslintResult, deployResult] = await Promise.allSettled([tscP, eslintP, deployP]);
446+
console.log('parallel stuff done in', performance.now() - t0);
447+
// TODO abort later ones?
448+
// Throw the first failure in this order
449+
for (const pResult of [tscResult, eslintResult, deployResult]) {
450+
if (pResult.status === 'fulfilled') {
451+
result += pResult.value;
452+
} else {
453+
throw pResult.reason;
454+
}
392455
}
393-
result = cleanedOutput;
456+
457+
result += await run('convex', ['dev', '--once', '--typecheck=disable'], outputLabels.convexDeploy);
394458

395459
// Start the default preview if it’s not already running
396460
if (!workbenchStore.isDefaultPreviewRunning()) {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const outputLabels = {
2+
convexCodegen: '[ConvexCodegen]',
3+
convexTypecheck: '[ConvexTypecheck]',
4+
frontendTypecheck: '[FrontendTypecheck]',
5+
convexLint: '[ConvexLint]',
6+
convexDeploy: '[convexDeploy]',
7+
} as const;
8+
export type OutputLabels = (typeof outputLabels)[keyof typeof outputLabels];

app/lib/stores/startup/useContainerSetup.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { workbenchStore } from '~/lib/stores/workbench.client';
1818
import { initializeConvexAuth } from '~/lib/convexAuth';
1919
import { appendEnvVarIfNotSet } from '~/utils/envFileUtils';
2020

21-
const TEMPLATE_URL = '/template-snapshot-24853bcf.bin';
21+
const TEMPLATE_URL = '/template-snapshot-dbe070eb.bin';
2222

2323
export function useNewChatContainerSetup() {
2424
const convex = useConvex();
@@ -82,6 +82,8 @@ async function setupContainer(
8282
// we won't receive file events for snapshot files.
8383
await workbenchStore.prewarmWorkdir(container);
8484

85+
(window as any).chefWebContainer = container;
86+
8587
setContainerBootState(ContainerBootState.DOWNLOADING_DEPENDENCIES);
8688
const npm = await container.spawn('npm', ['install', '--no-fund', '--no-deprecated']);
8789
const { output, exitCode } = await streamOutput(npm);

app/styles/components/editor.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/* Cursor */
2121

2222
--cm-cursor-width: 2px;
23-
--cm-cursor-backgroundColor: var(--bolt-elements-editor-cursorColor, var(--content-secondary));
23+
--cm-cursor-backgroundColor: var(--bolt-elements-editor-cursorColor, rgb(var(--content-secondary)));
2424

2525
/* Matching Brackets */
2626

make-bootstrap-snapshot.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ async function main() {
3232
console.log(`Writing snapshot (${compressed.length} bytes) to ${filename}...`);
3333
await fs.writeFile(`public/${filename}`, compressed);
3434
console.log("Done!");
35+
console.log("Next update TEMPLATE_URL in app/lib/stores/startup/useContainerSetup.ts to see your change.");
3536
}
3637

3738
async function getSnapshotFiles(dir) {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"build": "remix vite:build",
1212
"build:proxy": "node proxy/build.cjs",
1313
"dev": "remix vite:dev",
14-
"rebuild-template": "node make-bootstrap-snapshot.js && open http://localhost:5173/admin/build-snapshot",
14+
"rebuild-template": "node make-bootstrap-snapshot.js",
1515
"test": "vitest run",
1616
"test:watch": "vitest",
1717
"lint:app": "eslint --cache --cache-location ./node_modules/.cache/eslint app",
233 KB
Binary file not shown.

template/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@convex-dev/auth": "^0.0.80",
14-
"@convex-dev/eslint-plugin": "^0.0.1-alpha.2",
14+
"@convex-dev/eslint-plugin": "0.0.1-alpha.3",
1515
"clsx": "^2.1.1",
1616
"convex": "1.21.1-alpha.1",
1717
"react": "^19.0.0",

0 commit comments

Comments
 (0)