Skip to content

feat(codegen): embed affine-vscode adapter at compile time (root-cause fix for #139/#104)#380

Merged
hyperpolymath merged 3 commits into
mainfrom
claude/codegen-embed-vscode-adapter
May 27, 2026
Merged

feat(codegen): embed affine-vscode adapter at compile time (root-cause fix for #139/#104)#380
hyperpolymath merged 3 commits into
mainfrom
claude/codegen-embed-vscode-adapter

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

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:

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

@hyperpolymath hyperpolymath enabled auto-merge May 26, 2026 09:22
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 41 issues detected

Severity Count
🔴 Critical 15
🟠 High 15
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

2 similar comments
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 41 issues detected

Severity Count
🔴 Critical 15
🟠 High 15
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 41 issues detected

Severity Count
🔴 Critical 15
🟠 High 15
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath and others added 2 commits May 26, 2026 12:31
…e fix for #139/#104)

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 the WASM activation failed:

  WebAssembly.instantiate(): Import #1 "Vscode":
    module is not an object or function

The previous CI workaround (PR #377) added a `file:` install of the
in-tree adapter as a smoke-test-step bridge — useful but not a root
fix.

This commit eliminates the runtime npm dependency entirely:

1. New dune rule generates `lib/affine_vscode_adapter_source.ml` from
   `packages/affine-vscode/mod.js` at build time, exposing the source
   as an OCaml string constant.

2. `vscode_extension_wiring` in `lib/codegen_node.ml` now inlines the
   adapter source into the generated `.cjs` as a CJS-style closure:

     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;
     }

   The require() is still attempted first so an upgraded adapter
   installed via npm can override the embedded copy — but it's no
   longer load-bearing.

3. Regenerated `editors/vscode/out/extension.cjs` with the new codegen
   (618 lines, up from 121 — the delta is the inlined adapter source).

4. Dropped `optionalDependencies` for `@hyperpolymath/affine-vscode`
   from `editors/vscode/package.json` — the extension no longer needs
   it 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. Dropped `continue-on-error: true` from the vscode-smoke job in
   `.github/workflows/ci.yml`. The job is now expected to be reliable;
   a real regression should turn it red and gate.

Verified locally: the regenerated `extension.cjs` loads cleanly under
plain Node (`require()` works, `extraImports` is a function), and the
existing `tools/run_codegen_wasm_tests.sh` suite still passes.

Refs #139 (smoke harness), #104 (pending npm publish — no longer a
runtime blocker), gitbot-fleet#148.

Closes the "fundamental root cause" path opened in PR #377.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…alse positives)

The two E2E tests `--vscode-extension-adapter overrides the require specifier`
and `--vscode-extension-no-lc skips the language client` were checking for
the *absence* of bare substrings `@hyperpolymath/affine-vscode` and
`vscode-languageclient/node`.

Codegen-embed now inlines the adapter source (packages/affine-vscode/mod.js),
which carries documentation comments showing example usage of the default
specifier and a `vscode-languageclient/node` section delimiter. Those bare
substrings legitimately appear inside the embedded source — but they are
not require() wiring.

The off-by-default test at line 2994 already uses the precise pattern
`require("@hyperpolymath/affine-vscode")` for exactly this reason. Bringing
the override + no-lc tests to the same precision restores their semantic
intent: assert which require() fires, not which strings appear anywhere.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 43 issues detected

Severity Count
🔴 Critical 15
🟠 High 16
🟡 Medium 12

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Action actions/checkout@v6 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action denoland/setup-deno@v2 needs attention",
    "type": "unpinned_action",
    "file": "publish-jsr.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/packages/affine-js/types.d.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 6749fd2 into main May 27, 2026
21 of 22 checks passed
@hyperpolymath hyperpolymath deleted the claude/codegen-embed-vscode-adapter branch May 27, 2026 12:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant