Skip to content

Commit 6749fd2

Browse files
feat(codegen): embed affine-vscode adapter at compile time (root-cause fix for #139/#104) (#380)
## Summary The \`--vscode-extension\` codegen previously emitted a runtime \`require()\` of \`@hyperpolymath/affine-vscode\` to source the WASM's \`Vscode\` and \`VscodeLanguageClient\` import modules. That package isn't published to npm yet (gated on owner action in #104), so the require failed, \`extraImports()\` returned \`{}\`, and WASM activation failed every CI run with: \`\`\` WebAssembly.instantiate(): Import #1 \"Vscode\": module is not an object or function \`\`\` The previous CI workaround in PR #377 added a \`file:\` install of the in-tree adapter as a smoke-test-step bridge — useful, but a workaround. This PR is the **fundamental fix**: it eliminates the runtime npm dependency entirely by embedding the adapter source at codegen time. ## What this changes ### 1. \`lib/dune\` — adapter source as compile-time string constant New \`(rule …)\` generates \`lib/affine_vscode_adapter_source.ml\` from \`packages/affine-vscode/mod.js\` at build time, exposing the JS source as an OCaml string: \`\`\`ocaml (* AUTO-GENERATED from packages/affine-vscode/mod.js. Do not edit. *) let source = {affine_vscode|/* …mod.js content… */|affine_vscode} \`\`\` ### 2. \`lib/codegen_node.ml\` — inline at codegen time \`vscode_extension_wiring\` now emits a CJS-style closure that wraps the embedded adapter source. The runtime \`require()\` is still attempted first so an installed package can override the embedded copy — but it's no longer load-bearing: \`\`\`js try { _makeVscodeBindings = require(\"@hyperpolymath/affine-vscode\"); } catch (_e) { /* fall through to embedded adapter */ } if (typeof _makeVscodeBindings !== \"function\") { const _adapterModule = { exports: null }; (function (module, exports) { /* …embedded packages/affine-vscode/mod.js source… */ })(_adapterModule, _adapterModule.exports); _makeVscodeBindings = _adapterModule.exports; } \`\`\` ### 3. Regenerated \`editors/vscode/out/extension.cjs\` 618 lines, up from 121 — the delta is the inlined adapter source. ### 4. \`editors/vscode/package.json\` — drop \`optionalDependencies\` The \`@hyperpolymath/affine-vscode\` optional-dep is no longer needed at install time. The package keeps its in-tree home at \`packages/affine-vscode/\` as the source of truth for JSR/npm publishing and for \`--vscode-extension\` codegen consumption. ### 5. \`.github/workflows/ci.yml\` — drop \`continue-on-error: true\` The vscode-smoke job is now expected to be reliable. A real regression should turn it red and gate. ## Why this is the right fix Q: \"Can the VS Code extension use Deno instead of npm?\" A: No — the VS Code extension host is Electron-embedded Node. The host loads extensions via Node's \`require()\` and the \`.vsix\` package format expects CJS. CLAUDE.md \"Runtime Exemptions\" already documents this as a forced carve-out. But this PR **reduces** npm exposure by eliminating the runtime dependency on \`@hyperpolymath/affine-vscode\` (one less npm package needed at smoke time). The only remaining npm carve-outs at smoke time are \`@vscode/test-electron\` (smoke runner; no alternative exists) and \`vscode-languageclient\` (LSP client; npm-published). ## Verification Local: - Full build: \`opam exec -- dune build\` ✓ - Codegen WASM tests: \`opam exec -- ./tools/run_codegen_wasm_tests.sh\` ✓ (all pass) - Regenerated .cjs loads under plain Node: \`require('out/extension.cjs')\` exports \`activate\`, \`deactivate\`, \`extraImports\` (function) ✓ CI: - [ ] \`vscode-smoke\` green on this PR (the real test — was relying on file:-install bridge from #377; now self-contained) - [ ] Build / lint / format checks all pass ## Coordination with #377 #377 adds a \`file:\` install bridge in CI that solves the same symptom at the workflow level. If #377 lands first, this PR's removal of \`continue-on-error\` and the embedded adapter make the file: install redundant (it's harmless — the require() inside extension.cjs picks up the npm-installed version first and uses it; falls back to embedded only when not installed). If this PR lands first, #377 becomes a no-op pre-existing-step removal and can be closed. Refs #139 (smoke harness), #104 (pending npm publish — no longer a runtime blocker), gitbot-fleet#148. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d9f9971 commit 6749fd2

6 files changed

Lines changed: 582 additions & 50 deletions

File tree

.github/workflows/ci.yml

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -211,19 +211,13 @@ jobs:
211211
# (see CLAUDE.md "Runtime Exemptions") because the VS Code extension
212212
# host is npm/Node-native and no Deno/JSR equivalent exists.
213213
#
214-
# Visibility-only until #104 lands (continue-on-error). The extension's
215-
# wasm module imports the `Vscode` / `VscodeLanguageClient` module
216-
# objects from the @hyperpolymath/affine-vscode adapter; without the
217-
# adapter (gated on owner action — npm org create + NPM_TOKEN +
218-
# affine-vscode-v0.1.0 tag push) the wasm cannot instantiate and
219-
# activation fails. The defensive `optionalDependencies` move in
220-
# editors/vscode/package.json and the try/catch around the adapter
221-
# require in editors/vscode/out/extension.cjs already prevent the
222-
# `npm install` step from 404ing — activation degradation is the
223-
# remaining gap that #104 closes. Remove the `continue-on-error: true`
224-
# line when #104 publishes the adapter to npm.
214+
# Self-contained as of the codegen-embed fix: `--vscode-extension`
215+
# codegen now inlines the affine-vscode adapter source into the
216+
# generated .cjs at compile time, so activation no longer depends on
217+
# the @hyperpolymath/affine-vscode npm package being installed
218+
# (previously gated on #104's npm publish). A real regression should
219+
# turn this job red and gate, so no `continue-on-error`.
225220
runs-on: ubuntu-latest
226-
continue-on-error: true
227221

228222
steps:
229223
- name: Checkout code
@@ -236,14 +230,12 @@ jobs:
236230

237231
- name: Install test runner dependencies
238232
working-directory: editors/vscode
239-
# The compiled out/extension.cjs is checked in (see #35 Phase 3),
240-
# so the smoke test does not need the OCaml toolchain — only the
241-
# Node-side test runner deps. peerDeps `vscode` is provided by
242-
# @vscode/test-electron at launch; the extension's host-bindings
243-
# adapter @hyperpolymath/affine-vscode is an `optionalDependency`
244-
# — npm install succeeds when it is unpublished (issue #104), and
245-
# the smoke suite below detects the missing adapter and reports
246-
# SKIPPED rather than failing.
233+
# The compiled out/extension.cjs is checked in (see #35 Phase 3)
234+
# and now embeds the affine-vscode adapter inline (codegen-embed),
235+
# so the smoke test only needs the @vscode/test-electron runner
236+
# deps. `vscode` itself is provided by the test runner at launch.
237+
# The #381 SKIP-when-missing guard remains downstream as a safety
238+
# net but is now expected to find the adapter present.
247239
run: npm install --no-audit --no-fund
248240

249241
- name: Report adapter availability

0 commit comments

Comments
 (0)