Branch remote runner plugin fixe#46
Conversation
Set up the remote runner plugin, and associated directory and index files to be linked to the ev3 engine in py-slang
Updated the directory of the remote runner plugin
Modified the remoteRunnerPlugin repository structure and added the ev3Engine usage with the relevant test suite.
The updated directory structure is as follows:
plugins/
├── src/
│ ├── common/
│ │ └── test/
│ │ └── src/
│ │ └── index.ts # Added PySlangMessage type
│ ├── runner/
│ │ ├── remoteExecution/ # New package
│ │ │ ├── src/
│ │ │ │ └── index.ts # Entry point, exports remoteRunnerPlugin
│ │ │ ├── index.ts # Abstract remoteRunnerPlugin class
│ │ │ ├── jest.config.cjs
│ │ │ ├── manifest.json
│ │ │ ├── package.json
│ │ │ ├── rollup.config.mjs
│ │ │ └── tsconfig.json
│ │ └── test/
│ │ └── src/
│ │ ├── __tests__/
│ │ │ └── runner.test.ts # Tests engine-plugin connection
│ │ └── index.ts
└── lib/
└── build.ts # Fixed Windows yarn spawn issue
…onfigs - Replace jest/ts-jest/@types/jest with vitest in remoteExecution package - Add proper installable plugin fields (files, exports, publishConfig, peerDeps) - Remove spurious `abstract` from remoteRunnerPlugin (has no abstract methods) - Add `type` modifier to interface imports in remoteExecution/index.ts - Fix both rollup configs to use typescript() without __dirname (not valid in ESM) - Remove hardcoded Windows path from remoteExecution/tsconfig.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…/wasm-util Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move @sourceacademy/wasm-util before @sourceacademy/web-* (alphabetical) - Merge commander@^2.19.0 range (nearley dep) - Add fast-levenshtein@^3.0.0 and fastest-levenshtein@^1.0.7 (py-slang dep) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
py-slang is imported from source (py-slang/src/...) and its internal imports don't use type-only syntax, which violates the repo's verbatimModuleSyntax:true setting. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lity py-slang/src uses BigInt (requires ES2020+) and imports untyped modules (moo, nearley, fast-levenshtein). Both remoteExecution and runner-test pull in py-slang source transitively, so both need these overrides. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Importing from py-slang/src/ pulls in untyped modules (moo, nearley) and namespace patterns that don't work under our strict tsconfig. noCheck:true compiles without type-checking, which is appropriate until py-slang exposes EV3Engine through its public API with proper types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
runner-test/src/index.ts re-exported remoteRunnerPlugin via a relative path into another package's source, which rollup can't resolve when building the bundle. The test file imports it directly from the package so the re-export is redundant. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change inline type qualifiers to top-level import type (no-import-type-side-effects) - Add eslint-disable comments for required `as any` mock casts in tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without .ts in the extensions list, @rollup/plugin-node-resolve could not find py-slang/src/engines/ev3/EV3Engine.ts and left it as an unresolved external. This caused the bundle to emit a bare require() pointing at the TypeScript source, which fails at test time with a SyntaxError. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rollup/plugin-typescript only transforms files that are part of the TS program (files in tsconfig include). Without this, when nodeResolve finds EV3Engine.ts from node_modules, rollup's default acorn parser receives the TypeScript file and fails. Adding py-slang to include lets the TypeScript compiler process and transpile it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…pileModule @rollup/plugin-typescript excludes node_modules from its TypeScript program, so py-slang's TypeScript source files (EV3Engine.ts, etc.) never get transformed — rollup's acorn parser receives raw TypeScript and fails. Add a lightweight inline plugin that calls ts.transpileModule() on any .ts file from node_modules before the main TypeScript plugin runs. This strips TypeScript syntax without needing a full type-checking program. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
py-slang depends on moo and nearley, which are CommonJS UMD modules. When rollup bundles them as ESM it can't resolve their default exports without the commonjs interop plugin. Adding commonjs() before our TypeScript transform plugin resolves the 'default is not exported' error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntry Yarn lockfile workspace entry must mirror package.json; adding the dep to package.json without updating yarn.lock triggers YN0028. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bundling py-slang TypeScript source causes CJS interop and circular dependency issues at runtime. Since py-slang is a listed dependency (installed alongside the plugin), it's correct to keep it external. At test time, vitest's server.deps.inline transforms py-slang with esbuild, handling TypeScript source and CJS interop cleanly without the issues rollup's commonjs plugin introduces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The pre-built dist/index.mjs has py-slang as an external import, and Node.js can't load TypeScript source files natively. Using vi.mock to stub EV3Engine tests the plugin's channel subscription behavior without needing to load py-slang's TypeScript at test time. Also fixes the debug FORCE_FAIL assertion and adds a meaningful result assertion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nt rule Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a new conductor-compatible EV3 evaluator to the remoteExecution runner package: - Ev3Evaluator.ts: BasicEvaluator subclass that calls EV3Engine from py-slang to compile Python code to SVML, returning the result via conductor's sendResult channel back to the frontend host - entry.ts: bundle entry point that initialises the Ev3Evaluator via conductor's initialise utility - rollup.config.mjs: updated to include a second build target that bundles entry.ts into a self-contained iife output (ev3-pyslang.js) for use as a Web Worker in the frontend
|
There was a problem hiding this comment.
Code Review
This pull request introduces a new remote execution runner package (@sourceacademy/runner-remote-execution) integrating with the py-slang EV3 engine, along with corresponding Rollup and TypeScript configurations, and updates the test suite to verify its behavior. The review feedback identifies critical issues including a missing entry file (src/entry.ts) in the Rollup configuration, an invalid noCheck compiler option in tsconfig.json, and potential unhandled promise rejections in the asynchronous subscription callback. Additionally, the reviewer suggests renaming remoteRunnerPlugin to RemoteRunnerPlugin to follow PascalCase conventions, and improving type safety in the constructor to avoid using any.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| this.__channel.subscribe(async message => { | ||
| if (message.type === "run") { | ||
| const result = await this.engine.execute(message.code); | ||
| console.log("Engine response:", result); | ||
| this.__channel.send({ type: "result", output: JSON.stringify(result) }); | ||
| } | ||
| }); |
There was a problem hiding this comment.
If this.engine.execute or JSON.stringify throws an error, the asynchronous subscription callback will result in an unhandled promise rejection. Wrapping the execution in a try-catch block allows us to handle the error gracefully and send an error message back through the channel using the error message type defined in PySlangMessage.
this.__channel.subscribe(async message => {
if (message.type === "run") {
try {
const result = await this.engine.execute(message.code);
console.log("Engine response:", result);
this.__channel.send({ type: "result", output: JSON.stringify(result) });
} catch (error) {
console.error("Engine execution failed:", error);
this.__channel.send({
type: "error",
message: error instanceof Error ? error.message : String(error),
});
}
}
});| }, | ||
| // new EV3 conductor worker bundle | ||
| { | ||
| input: "src/entry.ts", |
| import type { IPlugin, IChannel, IConduit } from "@sourceacademy/conductor/conduit"; | ||
| import { EV3Engine } from "py-slang/src/engines/ev3/EV3Engine"; | ||
|
|
||
| export class remoteRunnerPlugin implements IPlugin { |
There was a problem hiding this comment.
Class names in TypeScript should follow the PascalCase naming convention (e.g., as per standard TypeScript style guides). Renaming remoteRunnerPlugin to RemoteRunnerPlugin improves readability and consistency with standard naming conventions.
| export class remoteRunnerPlugin implements IPlugin { | |
| export class RemoteRunnerPlugin implements IPlugin { |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| constructor(_conduit: IConduit, [channel]: IChannel<any>[]) { |
There was a problem hiding this comment.
| "declaration": true, | ||
| "outDir": "./dist", | ||
| "rootDir": ".", | ||
| "noCheck": true |
There was a problem hiding this comment.
noCheck is not a valid TypeScript compiler option in tsconfig.json. If the intention is to skip type checking of declaration files, use skipLibCheck: true. If the intention is to disable type checking entirely, it is highly discouraged as it defeats the purpose of using TypeScript.
| "noCheck": true | |
| "skipLibCheck": true |
| @@ -0,0 +1 @@ | |||
| export { remoteRunnerPlugin } from "../index"; | |||
| }, | ||
| })); | ||
|
|
||
| import { remoteRunnerPlugin } from "@sourceacademy/runner-remote-execution"; |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| const mockConduit = {} as any; | ||
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
| new remoteRunnerPlugin(mockConduit, [mockChannel as any]); |
plugins repo PR description
Title:
feat(ev3): add conductor-based EV3 evaluator bundle
Description:
Overview
Adds a conductor-compatible EV3 evaluator to the remoteExecution runner
package as part of the py-slang EV3 integration. This replaces the
js-slang compilation step in the existing EV3 remote execution flow
with py-slang's EV3Engine, which compiles Python code to SVML.