feat(senpi-codemode): expose CommonJS in JS eval cells - #1286
Conversation
JavaScript eval cells run through ESM-worker eval, so Node never wraps them with require/module/exports. Install cwd-resolved CommonJS bindings and pass them into the cell wrapper. Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
There was a problem hiding this comment.
All reported issues were addressed across 9 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Resolve the session cwd before createRequire so a relative cwd still produces an absolute filename. Leave top-level declarations that rebind require/module/exports/__filename/__dirname unrewritten so they cannot overwrite the persistent CommonJS bindings. Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
|
Pushed
Kernel tests cover both cases ( |
|
@code-yeongyu fork PR CI is stuck on GitHub's first-time-contributor workflow approval ( Cubic's two P2s are addressed in Please approve the workflow runs on this PR so Check and test can run, then merge when green. |
There was a problem hiding this comment.
1 issue found across 4 files (changes from recent commits).
You’re at about 91% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/senpi-codemode/src/kernels/js/worker-indirect-eval.js">
<violation number="1" location="packages/senpi-codemode/src/kernels/js/worker-indirect-eval.js:269">
P3: The guard makes a reserved-name declaration "SyntaxError against the CJS wrapper parameters instead of overwriting the persistent bindings", but that holds only for `const`/`let`. A top-level `var module = ...` (or `var require`/`var exports`/`var __filename`) is left in the cell body unchanged, and in sloppy mode `var` may redeclare a function parameter without error — it silently shadows the wrapper parameter for that cell only. A cell ending with `var exports = {}; exports.foo = 1` therefore writes to a local object and never reaches `module.exports`, silently diverging from the documented CommonJS behavior with no error surfaced. Consider handling `var` reserved bindings explicitly (error or rewrite them) or documenting the inconsistency, and add a test covering `var` declarations.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const bindings = []; | ||
| collectPatternNames(pattern, bindings); | ||
| if (bindings.length === 0) return undefined; | ||
| if (bindings.some((name) => COMMONJS_RESERVED_NAMES.has(name))) return undefined; |
There was a problem hiding this comment.
P3: The guard makes a reserved-name declaration "SyntaxError against the CJS wrapper parameters instead of overwriting the persistent bindings", but that holds only for const/let. A top-level var module = ... (or var require/var exports/var __filename) is left in the cell body unchanged, and in sloppy mode var may redeclare a function parameter without error — it silently shadows the wrapper parameter for that cell only. A cell ending with var exports = {}; exports.foo = 1 therefore writes to a local object and never reaches module.exports, silently diverging from the documented CommonJS behavior with no error surfaced. Consider handling var reserved bindings explicitly (error or rewrite them) or documenting the inconsistency, and add a test covering var declarations.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/senpi-codemode/src/kernels/js/worker-indirect-eval.js, line 269:
<comment>The guard makes a reserved-name declaration "SyntaxError against the CJS wrapper parameters instead of overwriting the persistent bindings", but that holds only for `const`/`let`. A top-level `var module = ...` (or `var require`/`var exports`/`var __filename`) is left in the cell body unchanged, and in sloppy mode `var` may redeclare a function parameter without error — it silently shadows the wrapper parameter for that cell only. A cell ending with `var exports = {}; exports.foo = 1` therefore writes to a local object and never reaches `module.exports`, silently diverging from the documented CommonJS behavior with no error surfaced. Consider handling `var` reserved bindings explicitly (error or rewrite them) or documenting the inconsistency, and add a test covering `var` declarations.</comment>
<file context>
@@ -265,6 +266,7 @@ function rewriteDeclaration(code, declarationStart, start, end, keyword) {
const bindings = [];
collectPatternNames(pattern, bindings);
if (bindings.length === 0) return undefined;
+ if (bindings.some((name) => COMMONJS_RESERVED_NAMES.has(name))) return undefined;
if (preserveDeclaration) {
for (const name of bindings) assignments.push(`globalThis[${JSON.stringify(name)}] = ${name};`);
</file context>
|
Thanks @jc01rho. Nice catch on the eval cells missing CJS bindings, and leaving the five CommonJS names unrewritten in the declaration pass so they SyntaxError instead of silently clobbering the worker globals is the right call. Pulled the branch locally and re-ran the kernel tests myself (31/31, incl. the new builtin |
Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
|
Merged latest The new head SHA needs another first-time-contributor workflow approval:
@code-yeongyu please approve those two runs (same fork-PR gate as before). |
|
The merge-main commit landed after your approval of the previous SHA. New head is — changelog-gate should now PASS against current main. The two runs that still need approval are 33614942705 (CI) and 33614942689 (Changelog gate). |
|
The merge-main commit landed after your approval of the previous SHA. New head is 1f5b5a0 — changelog-gate should now PASS against current main. The two runs that still need approval are: |
|
CI is green except a Windows-only flake in
I cannot rerun failed jobs from jc01rho (403). Please rerun the failed jobs on https://github.com/code-yeongyu/senpi/actions/runs/33614942705 and merge when green. |
|
The remaining red check is still the Windows RPC flake, not the JS eval CommonJS change.
with I cannot rerun failed jobs from this fork (403), and pushing a Windows-only test fix would retrigger first-time-contributor workflow approval. Please either:
|
Bring in code-yeongyu#1284 so CI no longer fails on Stop-Process racing an idle-exited supervisor. Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
|
Merged latest New head:
@code-yeongyu please approve those two runs. Once they go green, auto-merge should land this. |
|
The new head ( Failed job: https://github.com/code-yeongyu/senpi/actions/runs/33625644260/job/100235422233 ( Lifecycle tests were skipped after that. Changelog gate, static checks, workspace tests, all three coding-agent shards, and the other Windows jobs passed. Auto-merge is still enabled. I cannot rerun from jc01rho (403). Please rerun failed jobs on https://github.com/code-yeongyu/senpi/actions/runs/33625644260 — a bare rerun of this exact test is the documented #1290 workaround until #1294 lands. |
|
#1294 just went fully green, including This head ( Please either:
I cannot rerun from jc01rho (403). |
Bring in code-yeongyu#1294 so CI no longer fails on rpc-host-ensure SIGTERM / lifecycle probe races. Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>
|
Merged latest The two new runs need first-time-contributor approval again:
@code-yeongyu please approve those two runs. Once they go green, auto-merge should land this. |
Summary
JS eval cells run through an ESM worker
eval, so Node never wraps them with CommonJS parameters.typeof requirewasundefined.This installs cwd-resolved CommonJS bindings on the persistent JS worker and passes
exports,require,module,__filename, and__dirnameinto the cell wrapper.Changes
worker-runtime.js:createRequire(cwd/eval-cell.cjs)plusmodule/exports/__filename/__dirname; resyncexportstomodule.exportsbefore each cellworker-indirect-eval.js: wrap user cells with Node's CJS parameter listrequire, relative.cjs, metadata, andmodule.exportspersistence across cellsVerification
vitesttest/js-kernel.test.tstest/prompt.test.tstest/js-rewrite-imports.test.tstest/js-runtime-isolation.test.ts— 60 passedrequire('node:path'), relative./module.cjs, andmodule.exportspersistencescripts/check-pr-changelog.mjs --base origin/main— PASSbiome checkon changed files — PASSqa-js-cell.ts/ fullnpm run checkwere not run end-to-end here because this worktree was installed with--ignore-scripts, so workspacedist/artifacts (@earendil-works/pi-tui,pi-telemetry) are absent. Kernel-path tests do not need those packages.Test plan
require('node:path')from a JS eval cellrequire('./module.cjs')from session cwdmodule.exportsreassignment is visible to the next cell viaexportsSummary by cubic
JS eval cells now expose CommonJS bindings—
require,module,exports,__filename, and__dirname—instead of running without them through the ESM worker eval. Relative modules resolve from the session cwd, and rebinding a CommonJS name now raises aSyntaxErrorrather than replacing the persistent binding.require, with__filenameset toeval-cell.cjs.exportswithmodule.exportsbefore each cell so reassignment persists across cells..cjsfiles, metadata, cwd resolution, and reserved-name redeclarations.Written for commit 8c6f1eb. Summary will update on new commits.