feat(napi): in-process ai-hist capture (no CLI shell-out) - #39
Conversation
Lets a host (the Agent Relay runtime) sync + push history in-process, with no
subprocess and no CLI invocation.
- Split the `ai-hist` crate into a lib + a thin bin. `main.rs` is a 3-line
wrapper over `ai_hist_cli::run()`; adds `pub fn sync_and_push()` (the
in-process equivalent of `ai-hist sync && ai-hist push`) with sync progress
gated behind a quiet flag so an embedding host's stdout isn't spammed. No CLI
behavior change; 30 lib tests pass.
- `crates/ai-hist-napi`: a napi-rs cdylib exposing `syncAndPush()` to Node,
running the blocking work on a worker thread. Published as `ai-hist-native`
(per-platform `.node` packages, same distribution model as
@agent-relay/broker-*, but loaded in-process rather than spawned). Verified:
`napi build` produces a loadable addon whose `syncAndPush()` returns
`{ sent, accepted, authenticated }`.
- `.github/workflows/publish-napi.yml` builds the four targets and publishes via
napi's tooling; `docs/reflex-zero-setup.md` documents the flow + the one-time
publish/wire-up steps.
The companion relay change calls `require('ai-hist-native').syncAndPush()` from
the Reflex capture loop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Warning Review limit reached
Next review available in: 47 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (13)
📝 WalkthroughWalkthroughAdds a new Changesai-hist-napi Addon and Publishing
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant NodeApp
participant IndexJs as index.js
participant NapiLib as ai-hist-napi lib.rs
participant AiHistCli as ai_hist_cli::sync_and_push
participant RelayCloud as relayhistory-cloud
NodeApp->>IndexJs: require native binding
IndexJs->>NapiLib: syncAndPush()
NapiLib->>AiHistCli: spawn_blocking(sync_and_push)
AiHistCli->>RelayCloud: POST /v1/ingest
RelayCloud-->>AiHistCli: sent/accepted counts
AiHistCli-->>NapiLib: sync result
NapiLib-->>IndexJs: SyncPushResult
IndexJs-->>NodeApp: Promise<SyncPushResult>
sequenceDiagram
participant GitHubActions
participant BuildJob as build job
participant PublishJob as publish job
participant Npm as npm registry
GitHubActions->>BuildJob: run matrix build (macOS, Linux musl)
BuildJob->>BuildJob: napi build --zig (aarch64-musl)
BuildJob-->>GitHubActions: upload .node artifacts
GitHubActions->>PublishJob: trigger after build
PublishJob->>PublishJob: napi create-npm-dirs / napi artifacts
alt dry_run true
PublishJob->>PublishJob: napi prepublish --dry-run
else dry_run false
PublishJob->>Npm: napi prepublish --provenance
end
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Warning Gemini encountered an error creating the review. You can try again by commenting |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 138b40982e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (localFileExisted) { | ||
| nativeBinding = require('./ai-hist-native.linux-x64-gnu.node') | ||
| } else { | ||
| nativeBinding = require('ai-hist-native-linux-x64-gnu') |
There was a problem hiding this comment.
Publish the GNU Linux native packages
On standard glibc Linux (for example Ubuntu x64), this branch runs because isMusl() is false and tries to load ai-hist-native-linux-x64-gnu, but the new package/workflow only builds the musl triples (x86_64-unknown-linux-musl and aarch64-unknown-linux-musl). That means require('ai-hist-native') will throw on the most common Linux runtime instead of loading the published musl artifact; either publish the *-gnu packages too or make the loader/package targets match the Linux artifacts you ship.
Useful? React with 👍 / 👎.
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. Only the pre-existing runtime state file is modified (not part of this PR, not touched by me). No stray edits from my review. Clean. Review: PR #39 — feat(napi): in-process ai-hist capture (no CLI shell-out)SummaryThis PR adds a napi (Node native addon) crate I traced the refactor and the new library API across callers, types, and config, and ran the canonical CI Rust steps end-to-end. Verification
No mechanical fixes were required — the new/changed files are clean (no lint, typo, or import-order issues) and I made no edits. Working tree left unchanged (only a pre-existing untracked runtime Addressed comments
Advisory Notes
The Rust build/test that this PR affects passes locally. Remaining items (npm publish dry-run, version reconciliation) require human judgment and post-merge OIDC/publish setup that can't be exercised here, and I cannot confirm the status of the other CI jobs (Python/TS/e2e) or GitHub mergeability from this sandbox — so I am not declaring the PR final. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
crates/ai-hist-napi/Cargo.toml (1)
12-14: 🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy liftConfirm the
ai-hist-clidependency alias resolves to the actual package name.Same concern as the
ai-hist/Cargo.tomlreview:ai-hist-cli = { path = "../ai-hist" }(Line 13) has nopackagefield, so Cargo will require the target manifest's[package] nameto literally beai-hist-cli. This is consistent withai_hist_cli::sync_and_push()used insrc/lib.rs, but should be confirmed against the actual[package]section ofcrates/ai-hist/Cargo.toml, which isn't part of this diff.🤖 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 `@crates/ai-hist-napi/Cargo.toml` around lines 12 - 14, Confirm that the ai-hist-cli dependency in the ai-hist-napi Cargo.toml actually matches the package name defined in the target manifest for ai-hist; since the dependency uses ai-hist-cli = { path = "../ai-hist" } without a package field, Cargo will only resolve it if the [package] name in crates/ai-hist/Cargo.toml is exactly ai-hist-cli. Check the ai_hist_cli reference in src/lib.rs and either keep the alias as-is if the package name matches, or add an explicit package mapping if the package name differs.
🧹 Nitpick comments (2)
.github/workflows/publish-napi.yml (2)
84-110: 🔒 Security & Privacy | 🔵 TrivialConsider gating the publish job behind a protected environment.
For a job that publishes 5 npm packages via OIDC, adding
environment: name: npm-publishwith required reviewers gives a human approval gate before token exchange — mirroring the pattern recommended for other trusted-publishing setups (e.g. PyPI'senvironment:+ required reviewers) and reducing blast radius if the workflow file itself is ever compromised.🤖 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 @.github/workflows/publish-napi.yml around lines 84 - 110, The publish job in publish-napi.yml should be gated behind a protected environment so npm OIDC publishing cannot proceed without approval. Update the publish job definition to use a dedicated environment such as npm-publish, and ensure the workflow relies on that environment’s required reviewers before the Publish step in the publish job runs.
46-46: 🔒 Security & Privacy | 🔵 Trivial | ⚖️ Poor tradeoffConsider pinning third-party actions to commit SHAs.
This workflow has real publish power (npm OIDC trusted publishing + provenance across 5 packages), which makes it an attractive target — per npm's trusted-publishing guidance, a compromised action inside a publish workflow can be used to ship a malicious package while still appearing "trusted."
dtolnay/rust-toolchain@stableandSwatinem/rust-cache@v2float; pinning to SHAs (with Dependabot updates) reduces this supply-chain exposure.Also applies to: 53-53, 57-57, 78-78, 90-90, 96-96
🤖 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 @.github/workflows/publish-napi.yml at line 46, The publish workflow uses floating third-party action tags, which should be pinned to immutable commit SHAs to reduce supply-chain risk. Update the action references in this workflow (including actions/checkout, dtolnay/rust-toolchain, and Swatinem/rust-cache) to specific commit SHAs, and keep Dependabot configured to manage future SHA updates so the publish path stays secure.
🤖 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 @.github/workflows/publish-napi.yml:
- Line 46: The checkout step in the publish-napi workflow leaves unnecessary
GitHub credentials on disk. Update the actions/checkout usage in both affected
jobs to set persist-credentials to false, so the GITHUB_TOKEN is not retained
after checkout; use the checkout step itself as the unique place to apply this
change.
- Around line 101-110: The Publish step is interpolating the workflow_dispatch
input directly inside the shell script, which is unsafe and flagged by zizmor.
Update the Publish job to read the dry_run value from the safer inputs context
via an env var, then use that env var in the shell condition instead of
embedding github.event.inputs.dry_run directly in the run block.
- Around line 21-23: The workflow-level permissions are too broad because
`id-token: write` is granted to every job, including the `build` job that never
publishes. Move the OIDC permission off the top-level `permissions` block and
scope `id-token: write` only to the publish job, keeping `contents: read`
wherever needed and preserving the existing `build` matrix behavior.
- Around line 68-76: The Build addon job in the publish-napi workflow calls npx
napi build with --zig for the aarch64-unknown-linux-musl target, but Zig is
never installed or added to PATH first. Add a Zig setup step before this matrix
branch runs, and ensure the build step in the Build addon job can find zig when
matrix.target is aarch64-unknown-linux-musl.
---
Duplicate comments:
In `@crates/ai-hist-napi/Cargo.toml`:
- Around line 12-14: Confirm that the ai-hist-cli dependency in the ai-hist-napi
Cargo.toml actually matches the package name defined in the target manifest for
ai-hist; since the dependency uses ai-hist-cli = { path = "../ai-hist" } without
a package field, Cargo will only resolve it if the [package] name in
crates/ai-hist/Cargo.toml is exactly ai-hist-cli. Check the ai_hist_cli
reference in src/lib.rs and either keep the alias as-is if the package name
matches, or add an explicit package mapping if the package name differs.
---
Nitpick comments:
In @.github/workflows/publish-napi.yml:
- Around line 84-110: The publish job in publish-napi.yml should be gated behind
a protected environment so npm OIDC publishing cannot proceed without approval.
Update the publish job definition to use a dedicated environment such as
npm-publish, and ensure the workflow relies on that environment’s required
reviewers before the Publish step in the publish job runs.
- Line 46: The publish workflow uses floating third-party action tags, which
should be pinned to immutable commit SHAs to reduce supply-chain risk. Update
the action references in this workflow (including actions/checkout,
dtolnay/rust-toolchain, and Swatinem/rust-cache) to specific commit SHAs, and
keep Dependabot configured to manage future SHA updates so the publish path
stays secure.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: bf590f8e-0405-4874-b1da-71720ffd0142
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockcrates/ai-hist-napi/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (13)
.github/workflows/publish-napi.ymlCargo.tomlcrates/ai-hist-napi/.gitignorecrates/ai-hist-napi/Cargo.tomlcrates/ai-hist-napi/build.rscrates/ai-hist-napi/index.d.tscrates/ai-hist-napi/index.jscrates/ai-hist-napi/package.jsoncrates/ai-hist-napi/src/lib.rscrates/ai-hist/Cargo.tomlcrates/ai-hist/src/lib.rscrates/ai-hist/src/main.rsdocs/reflex-zero-setup.md
| permissions: | ||
| contents: read | ||
| id-token: write |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Scope id-token: write to the publish job only.
The build job never publishes and doesn't need OIDC tokens; granting id-token: write at the workflow level gives every job (including the multi-platform matrix build) unnecessary token-minting capability, which flags as excessive-permissions.
🔒️ Proposed fix
permissions:
contents: read
- id-token: write
defaults:
run:
working-directory: crates/ai-hist-napi
jobs:
build:
name: Build ${{ matrix.target }}
+ permissions:
+ contents: read
runs-on: ${{ matrix.os }}
@@
publish:
name: Publish to npm
needs: build
+ permissions:
+ contents: read
+ id-token: write
runs-on: ubuntu-latest📝 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.
| permissions: | |
| contents: read | |
| id-token: write | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: crates/ai-hist-napi | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.target }} | |
| permissions: | |
| contents: read | |
| runs-on: ${{ matrix.os }} | |
| publish: | |
| name: Publish to npm | |
| needs: build | |
| permissions: | |
| contents: read | |
| id-token: write | |
| runs-on: ubuntu-latest |
🧰 Tools
🪛 zizmor (1.26.1)
[error] 23-23: overly broad permissions (excessive-permissions): id-token: write is overly broad at the workflow level
(excessive-permissions)
🤖 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 @.github/workflows/publish-napi.yml around lines 21 - 23, The workflow-level
permissions are too broad because `id-token: write` is granted to every job,
including the `build` job that never publishes. Move the OIDC permission off the
top-level `permissions` block and scope `id-token: write` only to the publish
job, keeping `contents: read` wherever needed and preserving the existing
`build` matrix behavior.
Source: Linters/SAST tools
| - os: ubuntu-latest | ||
| target: aarch64-unknown-linux-musl | ||
| steps: | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win
Set persist-credentials: false on checkout.
Neither job pushes to the repo, so the default persisted GITHUB_TOKEN credential left on disk by actions/checkout is unnecessary attack surface (flagged by zizmor as artipacked) — especially risky in the build job where npm ci executes third-party install scripts.
🔒️ Proposed fix
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v4
+ with:
+ persist-credentials: falseAlso applies to: 89-89
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 46-46: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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 @.github/workflows/publish-napi.yml at line 46, The checkout step in the
publish-napi workflow leaves unnecessary GitHub credentials on disk. Update the
actions/checkout usage in both affected jobs to set persist-credentials to
false, so the GITHUB_TOKEN is not retained after checkout; use the checkout step
itself as the unique place to apply this change.
Source: Linters/SAST tools
| - name: Build addon | ||
| run: | | ||
| set -euo pipefail | ||
| # zig simplifies the aarch64 musl cross-compile. | ||
| if [ "${{ matrix.target }}" = "aarch64-unknown-linux-musl" ]; then | ||
| npx napi build --platform --release --target "${{ matrix.target }}" --zig | ||
| else | ||
| npx napi build --platform --release --target "${{ matrix.target }}" | ||
| fi |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does napi-rs napi build --zig flag automatically download the zig toolchain?
💡 Result:
No, the napi-rs CLI does not automatically download or install the Zig toolchain [1]. When you use flags like --cross-compile or -x (which utilize cargo-zigbuild), or when you previously used the --zig flag, the napi-rs CLI expects the zig binary to already be installed and available in your system's PATH [1]. If the tool is missing, the build will fail with an error such as zig: not found [1]. To use cross-compilation features provided by napi-rs, you must ensure that the Zig compiler is manually installed in your environment [1]. In CI/CD environments (such as GitHub Actions), this is typically handled by adding a step to install Zig before running the build command, for example by using actions like goto-bus-stop/setup-zig [1].
Citations:
Install Zig before the aarch64-musl build. napi build --zig still expects zig on PATH, so this branch will fail unless a Zig setup step runs first.
🤖 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 @.github/workflows/publish-napi.yml around lines 68 - 76, The Build addon job
in the publish-napi workflow calls npx napi build with --zig for the
aarch64-unknown-linux-musl target, but Zig is never installed or added to PATH
first. Add a Zig setup step before this matrix branch runs, and ensure the build
step in the Build addon job can find zig when matrix.target is
aarch64-unknown-linux-musl.
| - name: Publish | ||
| run: | | ||
| set -euo pipefail | ||
| if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then | ||
| echo "Dry run — skipping publish. Prepared packages:" | ||
| npx napi prepublish -t npm --dry-run || true | ||
| else | ||
| # Publishes the per-platform packages then the main package (OIDC provenance). | ||
| npx napi prepublish -t npm --provenance | ||
| fi |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Avoid interpolating the workflow_dispatch input directly into shell.
${{ github.event.inputs.dry_run }} is always a string (not a validated boolean) when read via github.event.inputs — GitHub only coerces the type for the inputs.* context. Direct expression interpolation into a run: block is a template-injection vector flagged by zizmor; assign it to an env var first (and prefer inputs.dry_run over github.event.inputs.dry_run).
🛡️ Proposed fix
+ env:
+ DRY_RUN: ${{ inputs.dry_run }}
run: |
set -euo pipefail
- if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then
+ if [ "$DRY_RUN" = "true" ]; then
echo "Dry run — skipping publish. Prepared packages:"
npx napi prepublish -t npm --dry-run || true
else
# Publishes the per-platform packages then the main package (OIDC provenance).
npx napi prepublish -t npm --provenance
fi📝 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.
| - name: Publish | |
| run: | | |
| set -euo pipefail | |
| if [ "${{ github.event.inputs.dry_run }}" = "true" ]; then | |
| echo "Dry run — skipping publish. Prepared packages:" | |
| npx napi prepublish -t npm --dry-run || true | |
| else | |
| # Publishes the per-platform packages then the main package (OIDC provenance). | |
| npx napi prepublish -t npm --provenance | |
| fi | |
| - name: Publish | |
| env: | |
| DRY_RUN: ${{ inputs.dry_run }} | |
| run: | | |
| set -euo pipefail | |
| if [ "$DRY_RUN" = "true" ]; then | |
| echo "Dry run — skipping publish. Prepared packages:" | |
| npx napi prepublish -t npm --dry-run || true | |
| else | |
| # Publishes the per-platform packages then the main package (OIDC provenance). | |
| npx napi prepublish -t npm --provenance | |
| fi |
🧰 Tools
🪛 zizmor (1.26.1)
[error] 104-104: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 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 @.github/workflows/publish-napi.yml around lines 101 - 110, The Publish step
is interpolating the workflow_dispatch input directly inside the shell script,
which is unsafe and flagged by zizmor. Update the Publish job to read the
dry_run value from the safer inputs context via an env var, then use that env
var in the shell condition instead of embedding github.event.inputs.dry_run
directly in the run block.
Source: Linters/SAST tools
- P1 (Codex): the napi loader resolves `ai-hist-native-linux-<arch>-gnu` on
standard glibc Linux (Ubuntu etc.), but only the musl triples were built, so
`require('ai-hist-native')` threw on the most common Linux runtime. Now build
BOTH gnu and musl for x64/arm64 (6 targets total); the loader picks the right
one per libc.
- Workflow hardening (CodeRabbit): scope `id-token: write` to the publish job
only (build no longer mints OIDC tokens); `persist-credentials: false` on both
checkouts; install zig for the cross-compiled Linux targets (napi
--cross-compile needs it); read `dry_run` via an env var + `inputs.` instead
of interpolating `github.event.inputs.*` into the shell.
- docs: note the gnu+musl split.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Addressed the review feedback (latest commit). P1 (Codex) — glibc Linux was unsupported. The napi loader resolves Workflow hardening (CodeRabbit):
Verified locally: workflow YAML + package.json valid, |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. Review: PR #39 — feat(napi): in-process ai-hist capture (no CLI shell-out)SummaryThis PR extracts the I traced the real change by diffing the base
Type-checked the casts: Verification (CI-equivalent, run end to end)
No mechanical issues found (napi Safety review
Addressed comments
Advisory Notes
The PR is mechanically clean, behavior-preserving, and passes the full CI-equivalent build/test suite locally. Remaining gating (PR mergeability and the actual GitHub CI check runs) is not observable from this sandbox, so I'm not asserting those are green. |
Enables the Agent Relay runtime to sync + push history in-process — no subprocess, no CLI invocation — per the requirement not to shell out to the
ai-histCLI.What
ai-hist→ lib + thin bin. Splits the crate so its logic is callable as a library.main.rsbecomes a 3-line wrapper overai_hist_cli::run(). Addspub fn sync_and_push()— the in-process equivalent ofai-hist sync && ai-hist push— with sync progress gated behind aSYNC_QUIETflag so an embedding host's stdout isn't spammed. No CLI behavior change.crates/ai-hist-napi. A napi-rs cdylib exposingsyncAndPush()to Node, running the blocking work on a worker thread so the event loop isn't blocked. Published asai-hist-nativewith per-platform.nodepackages — same distribution model as@agent-relay/broker-*, except loaded in-process, not spawned.publish-napi.ymlbuilds the 4 targets (darwin arm64/x64, linux musl x64/arm64) and publishes via napi's tooling;docs/reflex-zero-setup.mdcovers the flow and the one-time publish/wire-up steps.Verified locally
cargo build --workspace✅,cargo test -p ai-hist-cli --lib✅ (30 tests)napi buildproduces a loadable addon; Node loadsindex.jsandsyncAndPushis a callable async function returning{ sent, accepted, authenticated }.Companion + follow-up
require('ai-hist-native').syncAndPush()from its Reflex capture loop (relay#1233).ai-hist-native+ the 4 platform packages, runpublish-napi.yml(dry-run first — validate the musl cross-compiles), then addai-hist-nativeas an optional dependency ofagent-relay.🤖 Generated with Claude Code