Skip to content

Add C++ support#93

Merged
jayvdb merged 2 commits into
mainfrom
cplusplus
Jul 21, 2026
Merged

Add C++ support#93
jayvdb merged 2 commits into
mainfrom
cplusplus

Conversation

@jayvdb

@jayvdb jayvdb commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added Rust and Zig browser modules demonstrating error and exception handling.
    • Added browser-runner coverage for both new modules.
    • Extended the Zig data module with C++ support and improved hashing.
    • Added support for formatting and linting C++ source files.
  • Bug Fixes

    • Upstream asset checks now fail safely when release information cannot be retrieved.
    • Updated an integrity checksum for a downloaded tool and cached asset.
  • Documentation

    • Updated module lists, language guidance, and formatting/check documentation.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Rust and Zig WASM modules demonstrating recovered division errors and C++ exceptions, integrates them into builds and browser tests, expands C++ tooling, changes Zig data hashing, and makes upstream release-asset checks fail closed.

Changes

Browser WASM exception modules

Layer / File(s) Summary
Rust exception module
Cargo.toml, services/ws-modules/except1/...
Adds the et-ws-except1 crate with websocket lifecycle handling, checked division, browser status helpers, and exported asynchronous WASM execution.
Zig and C++ exception runtime
services/ws-modules/zig-except1/build.zig*, services/ws-modules/zig-except1/src/*
Adds an exception-enabled Zig WASM build, minimal C++ exception ABI support, and a Zig workflow that validates caught exceptions.
Zig browser worker bridge
services/ws-modules/zig-except1/pkg/*
Adds SharedArrayBuffer communication between the browser thread, Web Worker, and WASM imports for WebSocket and status operations.
Module registration and validation
.mise/config.rust.toml, CLAUDE.md, config/ast-grep/*, services/ws-web-runner/tests/modules.rs
Registers both modules in build tasks, documentation, lint rollout, and successful browser-runner cases.

C++ WASM tooling and hashing

Layer / File(s) Summary
C/C++ tooling scope
.mise/config.zig.toml, config/clang-*, config/ls-lint.yaml, config/semgrep/*, CLAUDE.md
Expands formatting and lint coverage to C++ and adds a wasm32 exception-handling clang-tidy pass.
Zig data FNV-1a hash
services/ws-modules/zig-data1/build.zig, services/ws-modules/zig-data1/src/*
Compiles a freestanding C++ FNV-1a utility and uses its hexadecimal hash output in the Zig data workflow.

Upstream asset integrity

Layer / File(s) Summary
Strict release asset checks
.github/workflows/upstream-cache.yaml
Four cache lanes now fail when GitHub release asset queries fail.
Asset checksum updates
.mise/config.toml, config/upstream-cache/data.toml
Updates the Augeas and upstream-cache SHA256 values.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Browser
  participant et_ws_zig_except1
  participant Worker
  participant WASM
  participant WebSocket
  Browser->>et_ws_zig_except1: run()
  et_ws_zig_except1->>Worker: send SharedArrayBuffer
  Worker->>WASM: instantiate and call run()
  WASM->>Worker: request WebSocket operations
  Worker->>et_ws_zig_except1: proxy requests
  et_ws_zig_except1->>WebSocket: connect and read agent id
  et_ws_zig_except1-->>Worker: return proxy responses
  Worker-->>et_ws_zig_except1: post WASM result
  et_ws_zig_except1-->>Browser: resolve or reject run()
Loading

Possibly related PRs

  • edge-toolkit/core#92: Introduces the documentation-summary rule and its file allowlist that this PR extends.

Suggested reviewers: pierre-tenedero

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title matches the primary change: broad C++ support was added across build configs, linting, docs, and WASM modules.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cplusplus

Comment @coderabbitai help to get the list of available commands.

@deepsource-io

deepsource-io Bot commented Jul 21, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in a83a08d...2db5674 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Jul 21, 2026 5:41a.m. Review ↗
C & C++ Jul 21, 2026 5:41a.m. Review ↗
Docker Jul 21, 2026 5:41a.m. Review ↗
Java Jul 21, 2026 5:41a.m. Review ↗
JavaScript Jul 21, 2026 5:41a.m. Review ↗
Python Jul 21, 2026 5:41a.m. Review ↗
Rust Jul 21, 2026 5:41a.m. Review ↗
Secrets Jul 21, 2026 5:41a.m. Review ↗
Code coverage Jul 21, 2026 5:41a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@codacy-production

codacy-production Bot commented Jul 21, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 58 high · 41 medium · 1 minor

Alerts:
⚠ 100 issues (≤ 0 issues of at least minor severity)

Results:
100 new issues

Category Results
Compatibility 31 medium
37 high
BestPractice 1 medium
ErrorProne 4 medium
21 high
Complexity 1 medium
1 minor
Performance 4 medium

View in Codacy

🟢 Metrics 94 complexity · 21 duplication

Metric Results
Complexity 94
Duplication 21

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp)
void __cxa_end_catch(void) {
if (pending_dtor != nullptr) {
pending_dtor(exception_slot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array is implicitly decaying into a pointer


Array-to-pointer decay refers to the automatic conversion of an array to a pointer to its first element. This means that when an array is used in an expression that expects a pointer, the name of the array is converted to a

// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp)
void __cxa_end_catch(void) {
if (pending_dtor != nullptr) {
pending_dtor(exception_slot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array is implicitly decaying into a pointer


Array-to-pointer decay refers to the automatic conversion of an array to a pointer to its first element. This means that when an array is used in an expression that expects a pointer, the name of the array is converted to a

// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp)
void __cxa_end_catch(void) {
if (pending_dtor != nullptr) {
pending_dtor(exception_slot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array is implicitly decaying into a pointer


Array-to-pointer decay refers to the automatic conversion of an array to a pointer to its first element. This means that when an array is used in an expression that expects a pointer, the name of the array is converted to a

// compiler-provided C headers only, no exceptions/RTTI (build.zig passes -fno-exceptions -fno-rtti), no operator
// new, and no non-trivial static initializers. Language-level features -- templates, constexpr, namespaces --
// all work.
#include <stddef.h>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead


The use of deprecated C++ headers such as signal.h and assert.h is considered an antipattern, as they are not part of the C++ standard library anymore and have been replaced by their C++ equivalents.

// new, and no non-trivial static initializers. Language-level features -- templates, constexpr, namespaces --
// all work.
#include <stddef.h>
#include <stdint.h>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead


The use of deprecated C++ headers such as signal.h and assert.h is considered an antipattern, as they are not part of the C++ standard library anymore and have been replaced by their C++ equivalents.

// (Zig has no C++ cleanup semantics and the exception would escape as a raw `WebAssembly.Exception`), so every
// extern "C" entry point in an exception-enabled TU catches everything it can throw and translates the failure
// to a status code at the boundary, as try_divide() does at the bottom of this file.
#include <stddef.h>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inclusion of deprecated C++ header 'stddef.h'; consider using 'cstddef' instead


The use of deprecated C++ headers such as signal.h and assert.h is considered an antipattern, as they are not part of the C++ standard library anymore and have been replaced by their C++ equivalents.

// extern "C" entry point in an exception-enabled TU catches everything it can throw and translates the failure
// to a status code at the boundary, as try_divide() does at the bottom of this file.
#include <stddef.h>
#include <stdint.h>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inclusion of deprecated C++ header 'stdint.h'; consider using 'cstdint' instead


The use of deprecated C++ headers such as signal.h and assert.h is considered an antipattern, as they are not part of the C++ standard library anymore and have been replaced by their C++ equivalents.

// NOLINTNEXTLINE(bugprone-reserved-identifier, cert-dcl37-c, cert-dcl51-cpp)
void __cxa_end_catch(void) {
if (pending_dtor != nullptr) {
pending_dtor(exception_slot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array is implicitly decaying into a pointer


Array-to-pointer decay refers to the automatic conversion of an array to a pointer to its first element. This means that when an array is used in an expression that expects a pointer, the name of the array is converted to a

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.58333% with 10 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
services/ws-modules/except1/src/lib.rs 89.58% 10 Missing ⚠️

📢 Thoughts on this report? Let us know!

@jayvdb
jayvdb marked this pull request as ready for review July 21, 2026 06:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
.mise/config.zig.toml (1)

79-88: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated 3-pass clang-tidy logic between clang-tidy-check and clang-tidy-fix.

The two tasks are identical apart from --fix, doubling future maintenance/drift risk (e.g. the -fno-rtti issue above would need fixing in two places). Consider factoring the shared pass logic into a small script under utilities/ invoked with a --fix toggle by both tasks.

Based on learnings, "Do not create a scripts/ directory or loose scripts; put simple scripts in mise tasks and substantial tools under utilities/ with documentation."

Also applies to: 96-105

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.mise/config.zig.toml around lines 79 - 88, Factor the duplicated three-pass
clang-tidy logic from the clang-tidy-check and clang-tidy-fix mise tasks into a
documented utility under utilities/. Make the utility accept a --fix toggle and
apply it consistently to all passes, then update both tasks to invoke the shared
utility while preserving their current behavior and flags.

Source: Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.mise/config.zig.toml:
- Around line 79-88: Update the wasm clang-tidy invocation in the run script so
`-fno-rtti` is applied only to C++ sources, not the `*.c` inputs. Split the `git
ls-files`/`xargs` processing for `services/ws-modules/zig-*/src/*.c` and
`*.cpp`, preserving the shared wasm flags while adding `-fno-rtti` only to the
C++ invocation.

In `@services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js`:
- Around line 38-127: Stop the poll loop when the worker completes or errors.
Add a shared stop flag checked at the start of poll(), and set it before
terminating and resolving/rejecting in worker.onmessage and worker.onerror;
preserve the existing completion result handling.

---

Nitpick comments:
In @.mise/config.zig.toml:
- Around line 79-88: Factor the duplicated three-pass clang-tidy logic from the
clang-tidy-check and clang-tidy-fix mise tasks into a documented utility under
utilities/. Make the utility accept a --fix toggle and apply it consistently to
all passes, then update both tasks to invoke the shared utility while preserving
their current behavior and flags.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 05067704-9812-4d14-9748-81e4684da490

📥 Commits

Reviewing files that changed from the base of the PR and between a83a08d and 78e019a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (26)
  • .github/workflows/upstream-cache.yaml
  • .mise/config.rust.toml
  • .mise/config.toml
  • .mise/config.zig.toml
  • CLAUDE.md
  • Cargo.toml
  • README.md
  • config/ast-grep/rules/doc-summary-ends-with-period.yaml
  • config/clang-format.yaml
  • config/clang-tidy.yaml
  • config/ls-lint.yaml
  • config/semgrep/comment-summary-line.yaml
  • config/upstream-cache/data.toml
  • services/ws-modules/except1/Cargo.toml
  • services/ws-modules/except1/src/lib.rs
  • services/ws-modules/zig-data1/build.zig
  • services/ws-modules/zig-data1/src/main.zig
  • services/ws-modules/zig-data1/src/util.cpp
  • services/ws-modules/zig-except1/build.zig
  • services/ws-modules/zig-except1/build.zig.zon
  • services/ws-modules/zig-except1/pkg/.gitignore
  • services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js
  • services/ws-modules/zig-except1/pkg/et_ws_zig_except1_worker.js
  • services/ws-modules/zig-except1/src/exceptions.cpp
  • services/ws-modules/zig-except1/src/main.zig
  • services/ws-web-runner/tests/modules.rs

Comment thread .mise/config.zig.toml
Comment on lines 79 to 88
run = """
git ls-files '*.c' '*.h' ':!services/ws-web-runner/mingw-shim' |
xargs -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
git ls-files '*.c' '*.cpp' '*.h' ':!services/ws-web-runner/mingw-shim' ':!services/ws-modules/zig-*' |
xargs -r -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- {{ vars.clang_resource_arg }}
llvm_ct="$(mise where 'github:mstorsjo/llvm-mingw')/bin/clang-tidy"
git ls-files 'services/ws-web-runner/mingw-shim/*.c' |
xargs -I{} "$llvm_ct" --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
xargs -r -I{} "$llvm_ct" --config-file=config/clang-tidy.yaml {} -- --target=x86_64-w64-mingw32 -std=c11
wasm_flags=({{ vars.clang_resource_arg }} --target=wasm32-unknown-unknown -fwasm-exceptions -mexception-handling)
git ls-files 'services/ws-modules/zig-*/src/*.c' 'services/ws-modules/zig-*/src/*.cpp' |
xargs -r -I{} clang-tidy --config-file=config/clang-tidy.yaml {} -- "${wasm_flags[@]}" -fno-rtti
"""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== .mise/config.zig.toml (relevant lines) ==\n'
cat -n .mise/config.zig.toml | goawk 'NR>=70 && NR<=110 { print }'

printf '\n== config/clang-tidy.yaml ==\n'
cat -n config/clang-tidy.yaml | goawk 'NR<=120 { print }'

Repository: edge-toolkit/core

Length of output: 244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

for path, start, end in [
    (Path('.mise/config.zig.toml'), 70, 110),
    (Path('config/clang-tidy.yaml'), 1, 160),
]:
    print(f"\n== {path} ({start}-{end}) ==")
    with path.open() as f:
        for i, line in enumerate(f, 1):
            if start <= i <= end:
                print(f"{i:4d}: {line}", end="")
            elif i > end:
                break

print("\n== matching zig module sources ==")
for p in sorted(Path('services/ws-modules').glob('zig-*/src/*')):
    if p.suffix in {'.c', '.cpp'}:
        print(p)
PY

Repository: edge-toolkit/core

Length of output: 4244


🌐 Web query:

Clang -fno-rtti C input unused argument warning warnings as errors driver

💡 Result:

In Clang, the "argument unused during compilation" message is a driver-level diagnostic controlled by the -Wunused-command-line-argument flag [1]. When you use -Werror, this warning is promoted to an error [2][1]. To manage or suppress this error, you can use the following methods: 1. Use -Qunused-arguments: This flag instructs the Clang driver to suppress warnings about unused command-line arguments entirely [3][4]. This is often the simplest approach if you want to silence these messages globally [2]. 2. Use -Wno-unused-command-line-argument: This explicitly disables the unused command-line argument diagnostic [2]. 3. Downgrade to a warning: If you are using -Werror globally but want to treat this specific diagnostic as a warning, you can pass -Wno-error=unused-command-line-argument [2]. This ensures the driver still reports the issue but does not halt the compilation [2]. 4. Selective suppression: For more granular control, the driver provides --start-no-unused-arguments and --end-no-unused-arguments, which can be wrapped around specific flags that are known to be unused in certain contexts (e.g., flags that only apply to linking but appear during compilation) [3][2]. Note that this diagnostic is intentionally designed to catch misspellings or incompatible flags, as Clang does not support all the command-line options found in other compilers like GCC [5]. Some flags may be annotated as TargetSpecific in newer Clang versions, which can elevate these warnings to errors automatically for certain targets [1].

Citations:


Move -fno-rtti off the C inputs The wasm clang-tidy pass matches both *.c and *.cpp, but -fno-rtti is C++-only. With WarningsAsErrors: "*", the C invocation can fail on services/ws-modules/zig-data1/src/util.c. Split the glob or pass that flag only to *.cpp.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.mise/config.zig.toml around lines 79 - 88, Update the wasm clang-tidy
invocation in the run script so `-fno-rtti` is applied only to C++ sources, not
the `*.c` inputs. Split the `git ls-files`/`xargs` processing for
`services/ws-modules/zig-*/src/*.c` and `*.cpp`, preserving the shared wasm
flags while adding `-fno-rtti` only to the C++ invocation.

Comment on lines +38 to +127
const poll = () => {
if (Atomics.load(ctrl, 0) !== 1) {
setTimeout(poll, 0);
return;
}

const type = Atomics.load(ctrl, 1);
const plen = Atomics.load(ctrl, 2);
const payload = dec.decode(Uint8Array.from(data.subarray(0, plen)));

switch (type) {
case 0:
setTimeout(
() => {
respond();
poll();
},
parseInt(payload) || 0,
);
return;
case 1:
ws = new WebSocket(payload);
wsState = "connecting";
ws.onopen = () => {
wsState = "connected";
ws.send(JSON.stringify({ type: "et-connect" }));
};
ws.onmessage = (e) => {
try {
const msg = JSON.parse(e.data);
if (msg.type === "et-connect-ack" && msg.agent_id) agentId = msg.agent_id;
} catch {}
};
ws.onclose = ws.onerror = () => {
wsState = "disconnected";
};
respond();
break;
case 2:
respond(wsState);
break;
case 3:
respond(agentId);
break;
case 6:
ws?.close();
wsState = "disconnected";
respond();
break;
case 7:
console.log(payload);
appendOutput(payload);
respond();
break;
case 8:
appendOutput(payload);
respond();
break;
case 9: {
const p = location.protocol === "https:" ? "wss:" : "ws:";
respond(`${p}//${location.host}/ws`);
break;
}
default:
respond();
break;
}
setTimeout(poll, 0);
};

const worker = new Worker(workerUrl, { type: "module" });
worker.onmessage = (e) => {
if (e.data.done) {
worker.terminate();
if (e.data.ret === 0) {
resolve();
} else {
reject(new Error("zig-except1: run() returned " + e.data.ret));
}
}
};
worker.onerror = (e) => {
worker.terminate();
reject(e);
};
// The worker resolves its own wasm URL from import.meta.url; only the shared buffer crosses the boundary.
worker.postMessage({ sab });
poll();
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

poll() never stops after the worker finishes.

Once worker.onmessage sees done and resolves/rejects, nothing halts the poll loop: ctrl[0] stays 0, so poll() keeps rescheduling itself via setTimeout(poll, 0) indefinitely, busy-spinning the main thread until page teardown. Add a stop flag flipped on completion/error.

Proposed fix
   return new Promise((resolve, reject) => {
     let ws = null,
       wsState = "disconnected",
       agentId = "";
+    let running = true;

     const poll = () => {
+      if (!running) return;
       if (Atomics.load(ctrl, 0) !== 1) {
         setTimeout(poll, 0);
         return;
       }
@@
     const worker = new Worker(workerUrl, { type: "module" });
     worker.onmessage = (e) => {
       if (e.data.done) {
+        running = false;
         worker.terminate();
         if (e.data.ret === 0) {
           resolve();
         } else {
           reject(new Error("zig-except1: run() returned " + e.data.ret));
         }
       }
     };
     worker.onerror = (e) => {
+      running = false;
       worker.terminate();
       reject(e);
     };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const poll = () => {
if (Atomics.load(ctrl, 0) !== 1) {
setTimeout(poll, 0);
return;
}
const type = Atomics.load(ctrl, 1);
const plen = Atomics.load(ctrl, 2);
const payload = dec.decode(Uint8Array.from(data.subarray(0, plen)));
switch (type) {
case 0:
setTimeout(
() => {
respond();
poll();
},
parseInt(payload) || 0,
);
return;
case 1:
ws = new WebSocket(payload);
wsState = "connecting";
ws.onopen = () => {
wsState = "connected";
ws.send(JSON.stringify({ type: "et-connect" }));
};
ws.onmessage = (e) => {
try {
const msg = JSON.parse(e.data);
if (msg.type === "et-connect-ack" && msg.agent_id) agentId = msg.agent_id;
} catch {}
};
ws.onclose = ws.onerror = () => {
wsState = "disconnected";
};
respond();
break;
case 2:
respond(wsState);
break;
case 3:
respond(agentId);
break;
case 6:
ws?.close();
wsState = "disconnected";
respond();
break;
case 7:
console.log(payload);
appendOutput(payload);
respond();
break;
case 8:
appendOutput(payload);
respond();
break;
case 9: {
const p = location.protocol === "https:" ? "wss:" : "ws:";
respond(`${p}//${location.host}/ws`);
break;
}
default:
respond();
break;
}
setTimeout(poll, 0);
};
const worker = new Worker(workerUrl, { type: "module" });
worker.onmessage = (e) => {
if (e.data.done) {
worker.terminate();
if (e.data.ret === 0) {
resolve();
} else {
reject(new Error("zig-except1: run() returned " + e.data.ret));
}
}
};
worker.onerror = (e) => {
worker.terminate();
reject(e);
};
// The worker resolves its own wasm URL from import.meta.url; only the shared buffer crosses the boundary.
worker.postMessage({ sab });
poll();
});
}
const poll = () => {
if (!running) return;
if (Atomics.load(ctrl, 0) !== 1) {
setTimeout(poll, 0);
return;
}
const type = Atomics.load(ctrl, 1);
const plen = Atomics.load(ctrl, 2);
const payload = dec.decode(Uint8Array.from(data.subarray(0, plen)));
switch (type) {
case 0:
setTimeout(
() => {
respond();
poll();
},
parseInt(payload) || 0,
);
return;
case 1:
ws = new WebSocket(payload);
wsState = "connecting";
ws.onopen = () => {
wsState = "connected";
ws.send(JSON.stringify({ type: "et-connect" }));
};
ws.onmessage = (e) => {
try {
const msg = JSON.parse(e.data);
if (msg.type === "et-connect-ack" && msg.agent_id) agentId = msg.agent_id;
} catch {}
};
ws.onclose = ws.onerror = () => {
wsState = "disconnected";
};
respond();
break;
case 2:
respond(wsState);
break;
case 3:
respond(agentId);
break;
case 6:
ws?.close();
wsState = "disconnected";
respond();
break;
case 7:
console.log(payload);
appendOutput(payload);
respond();
break;
case 8:
appendOutput(payload);
respond();
break;
case 9: {
const p = location.protocol === "https:" ? "wss:" : "ws:";
respond(`${p}//${location.host}/ws`);
break;
}
default:
respond();
break;
}
setTimeout(poll, 0);
};
const worker = new Worker(workerUrl, { type: "module" });
worker.onmessage = (e) => {
if (e.data.done) {
running = false;
worker.terminate();
if (e.data.ret === 0) {
resolve();
} else {
reject(new Error("zig-except1: run() returned " + e.data.ret));
}
}
};
worker.onerror = (e) => {
running = false;
worker.terminate();
reject(e);
};
// The worker resolves its own wasm URL from import.meta.url; only the shared buffer crosses the boundary.
worker.postMessage({ sab });
poll();
});
}
🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 39-39: Avoid using the initial state variable in setState
Context: setTimeout(poll, 0)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)


[warning] 104-104: Avoid using the initial state variable in setState
Context: setTimeout(poll, 0)
Note: [CWE-710] Improper Adherence to Coding Standards. Security best practice.

(setstate-same-var)

🪛 GitHub Check: Codacy Static Code Analysis

[warning] 38-38: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L38
ES2015 arrow function expressions are forbidden.


[warning] 38-38: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L38
ES2015 block-scoped variables are forbidden.


[warning] 38-38: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L38
Function must end with a return statement, so that it doesn't return undefined


[warning] 38-38: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L38
Method poll has 80 lines of code (limit is 50)


[notice] 38-38: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L38
Method poll has a cyclomatic complexity of 16 (limit is 10)


[warning] 39-39: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L39
ES2017 'Atomics' class is forbidden.


[warning] 40-40: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L40
Restricted async operation "setTimeout"


[warning] 41-41: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L41
Return statement must return an explicit value, so that it doesn't evaluate to undefined


[warning] 44-44: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L44
ES2015 block-scoped variables are forbidden.


[warning] 44-44: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L44
ES2017 'Atomics' class is forbidden.


[warning] 45-45: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L45
ES2015 block-scoped variables are forbidden.


[warning] 45-45: services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js#L45
ES2017 'Atomics' class is forbidden.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/ws-modules/zig-except1/pkg/et_ws_zig_except1.js` around lines 38 -
127, Stop the poll loop when the worker completes or errors. Add a shared stop
flag checked at the start of poll(), and set it before terminating and
resolving/rejecting in worker.onmessage and worker.onerror; preserve the
existing completion result handling.

@jayvdb
jayvdb requested a review from pierre-tenedero July 21, 2026 07:14
@jayvdb
jayvdb merged commit 7adb78f into main Jul 21, 2026
34 of 39 checks passed
@jayvdb
jayvdb deleted the cplusplus branch July 21, 2026 07:23
@coderabbitai coderabbitai Bot mentioned this pull request Jul 21, 2026
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.

2 participants