Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/dirsql-rust-ci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
name: dirsql Rust CI

# The binding crates fan in (packages/ts/napi, packages/python/src): they are
# cargo workspace members, so the workspace-wide unit/lint jobs compile them.
# The binding crates fan in (packages/ts/napi with its manifest at
# packages/ts/Cargo.toml, and packages/python/src): they are cargo workspace
# members, so the workspace-wide unit/lint jobs compile them.
# The root testing-conventions.toml carries this lane's config and the
# [rust.coverage] floors the coverage job reads.
on:
Expand All @@ -10,6 +11,7 @@ on:
paths:
- 'packages/rust/**'
- 'packages/ts/napi/**'
- 'packages/ts/Cargo.toml'
- 'packages/python/src/**'
- 'Cargo.toml'
- 'Cargo.lock'
Expand All @@ -22,6 +24,7 @@ on:
- '!packages/rust/migrations.d/**'
- '!packages/rust/README.md'
- 'packages/ts/napi/**'
- 'packages/ts/Cargo.toml'
- 'packages/python/src/**'
- 'Cargo.toml'
- 'Cargo.lock'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/dirsql-typescript-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:
build:
# Builds the napi addon once and shares it with unit/binding/distcheck
# below instead of each job/matrix-cell rebuilding it independently.
# The addon is N-API (napi6, see packages/ts/napi/Cargo.toml), which is
# The addon is N-API (napi6, see packages/ts/Cargo.toml), which is
# ABI-stable across Node majors, so one build serves the whole Node
# 20/22/24 matrix.
name: Build native module
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["packages/python", "packages/rust", "packages/ts/napi"]
members = ["packages/python", "packages/rust", "packages/ts"]
# Test-only loadable-extension fixture, built on demand by
# packages/rust/tests/extensions.rs. Excluded so it isn't built/linted by
# `cargo build --workspace` / `cargo clippy --workspace`.
Expand Down
4 changes: 2 additions & 2 deletions agents/reference/e2e-attestation.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Receipts are append-only in practice -- a merged branch's receipt stays in the d
**Everything compiled into the binding is in scope -- CI-enforced via `[e2e].extra_scope`.** The shared Rust core (`packages/rust/src`) is compiled into both bindings but lives in neither binding's subtree, and `e2e verify --scope` requires the scope to be a **descendant of the caller's `path`** -- so a binding caller cannot point its own `--scope` at the core. That case is solved by the `e2e verify --extra-scope` / `--exclude` flags (upstream #333): an `[e2e]` block declares the extra roots, `detect.py` reads it, and the reusable `e2e-verify` job passes it through. Pure config; the former bespoke `e2e_core_freshness.py` gate is not needed. Two roots per binding:

- **The core, `packages/rust/src` -- puts BOTH bindings in scope** (#337). **After any shared-core change, attest each binding** (`just e2e-attest-python`, `just e2e-attest-ts`) -- CI enforces this, it is no longer a by-hand-only promise. **`cli`-only** core source (`packages/rust/src/cli/**`, `packages/rust/src/bin/**`) is feature-gated out of the binding *libraries*, but since #721 each launcher calls the core's `run_cli` **in-process through its binding** -- a CLI change alters what those suites exercise, so it demands a receipt from both bindings like any other core change (no `exclude` carve-out).
- **The binding crate itself -- puts ONLY its own package in scope** (#933): `packages/python/src` (the PyO3 glue) for python, `packages/ts/napi` (the napi-rs crate, manifest and `build.rs` included) for typescript. Same #721 argument one layer out: `run_cli` in each binding does argv framing, GIL detach / exit-code handling, and runs in every e2e case, so a binding-only diff changes what the suites exercise with no core change at all. A napi change has no bearing on the python suite and never demands a python receipt, and vice versa.
- **The binding crate itself -- puts ONLY its own package in scope** (#933): `packages/python/src` (the PyO3 glue) for python, `packages/ts/napi` plus `packages/ts/Cargo.toml` (the napi-rs crate, `build.rs` included; the manifest sits at the package root so the release stamps its version) for typescript. Same #721 argument one layer out: `run_cli` in each binding does argv framing, GIL detach / exit-code handling, and runs in every e2e case, so a binding-only diff changes what the suites exercise with no core change at all. A napi change has no bearing on the python suite and never demands a python receipt, and vice versa.

**That per-package split is why `packages/python` and `packages/ts` each carry their own `testing-conventions.toml`** (passed explicitly as the lane's `config:`, the pattern `internals/checks` established in #550). `[e2e]` is a single global table applied to every caller reading a given config, so "core + *my* binding" is not expressible in one shared file: declaring both bindings at the repo root would make a napi change demand a python receipt (and force `packages/ts/napi/**` into the python lane's path triggers to enforce it at all). The root `[e2e]` block stays as the default for a caller with no config of its own.

Expand All @@ -41,7 +41,7 @@ Agents must run the full e2e suite locally before any `git push` that includes a

**"Substantial" means any change touching:**
- `packages/rust/**` (Rust core)
- `packages/ts/napi/**` (napi-rs binding crate)
- `packages/ts/napi/**` and `packages/ts/Cargo.toml` (napi-rs binding crate)
- `packages/python/src/**` (excluding files matching `*_test.py`)
- `packages/ts/src/**` (excluding files matching `*.test.ts` / `*.spec.ts`)
- Any shared SDK runtime code reachable from the above
Expand Down
14 changes: 14 additions & 0 deletions internals/checks/tests/integration/release_globs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

from __future__ import annotations

import tomllib
from pathlib import Path

import pytest

from checks.release_globs.carve_out import carve_out
Expand Down Expand Up @@ -81,3 +84,14 @@ def it_rejects_a_leading_bang_negation_in_the_publish_globs(tmp_path, capsys, ne
globs = [*carve_out("packages/rust"), negation]
assert run(*write(tmp_path, globs)) == 1
assert "leading-`!` negation" in capsys.readouterr().out


def describe_the_real_release_config():
def it_keeps_the_napi_manifest_at_the_npm_package_path():
# The release stamps the planned version into a napi crate only when its
# Cargo.toml sits at the npm package's `path`; elsewhere the CLI reports
# the committed literal.
repo = Path(__file__).resolve().parents[4]
config = tomllib.loads((repo / "putitoutthere.toml").read_text())
(npm,) = [package for package in config["package"] if package["kind"] == "npm"]
assert (repo / npm["path"] / "Cargo.toml").is_file()
4 changes: 4 additions & 0 deletions packages/ts/napi/Cargo.toml → packages/ts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ name = "dirsql-napi"
version.workspace = true
edition.workspace = true
publish = false
# Colocated with package.json because the release only stamps the planned
# version into a napi crate whose manifest sits at the npm package path.
build = "napi/build.rs"

[lib]
path = "napi/src/lib.rs"
crate-type = ["cdylib"]

[dependencies]
Expand Down
2 changes: 2 additions & 0 deletions packages/ts/changelog.d/2026-10-05-npm-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
**Fixed** `npx dirsql --version` reports the npm package's version. It used to
print `0.2.7`, the unreleased crate version, on every release.
7 changes: 7 additions & 0 deletions packages/ts/e2e-attestations/claude-1297-npm-version.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "pnpm test:e2e",
"ran_at": 1791237028,
"exit_code": 0,
"commit": "ce521cdd6a0d9088f75a689159ec3f37ff2c864a",
"branch": "claude/1297-npm-version"
}
22 changes: 22 additions & 0 deletions packages/ts/migrations.d/2026-10-05-npm-version.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
### npm: `dirsql --version` reports the published version

#### Summary

`npx dirsql --version` now prints the installed package's version instead of
`0.2.7`. Nothing breaks.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

_None._

#### Verification

_None._
8 changes: 4 additions & 4 deletions packages/ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
},
"wireit": {
"napi:build": {
"command": "napi build --release --manifest-path napi/Cargo.toml --output-dir .",
"command": "napi build --release --manifest-path Cargo.toml --output-dir .",
"output": ["dirsql.node", "index.d.ts"]
},
"tsc": {
Expand All @@ -66,7 +66,7 @@
"src/platforms.json",
"napi/src/**/*.rs",
"napi/build.rs",
"napi/Cargo.toml",
"Cargo.toml",
"../rust/src/**/*.rs",
"../rust/Cargo.toml"
],
Expand All @@ -76,11 +76,11 @@
"dependencies": ["napi:build", "tsc", "stage:platform"]
},
"build:debug": {
"command": "napi build --manifest-path napi/Cargo.toml --output-dir . && tsc -p tsconfig.build.json",
"command": "napi build --manifest-path Cargo.toml --output-dir . && tsc -p tsconfig.build.json",
"files": [
"napi/src/**/*.rs",
"napi/build.rs",
"napi/Cargo.toml",
"Cargo.toml",
"../rust/src/**/*.rs",
"src/**/*.ts",
"src/**/*.json",
Expand Down
8 changes: 4 additions & 4 deletions packages/ts/testing-conventions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# start staling this package.
#
# The napi crate is in scope because the npm launcher runs the CLI in-process
# through it (#721), so every e2e case crosses it -- the whole crate dir, since
# Cargo.toml and build.rs decide what lands in the addon. packages/python/src is
# not: it cannot reach this suite.
# through it (#721), so every e2e case crosses it -- the whole crate dir plus its
# manifest at the package root, since Cargo.toml and build.rs decide what lands
# in the addon. packages/python/src is not: it cannot reach this suite.
[e2e]
extra_scope = ["packages/rust/src", "packages/ts/napi"]
extra_scope = ["packages/rust/src", "packages/ts/napi", "packages/ts/Cargo.toml"]

# The live TypeScript floors; the root file carries no `[typescript]` table.
[typescript.coverage]
Expand Down
4 changes: 2 additions & 2 deletions packages/ts/tools/stage-platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ function stageOne(args: StageOneArgs): StageResult["staged"][number] {
// instead of `dirsql.node`. Without it the cross-build's output
// collides with the host's napi:build file at the package root.
// `--manifest-path`/`--output-dir` point napi at the colocated
// `dirsql-napi` crate (packages/ts/napi) while still dropping the
// `dirsql-napi` crate (packages/ts/Cargo.toml) while still dropping the
// artifact into this package (packages/ts) root.
const cross = spawn(
"npx",
Expand All @@ -148,7 +148,7 @@ function stageOne(args: StageOneArgs): StageResult["staged"][number] {
"--release",
"--platform",
"--manifest-path",
"napi/Cargo.toml",
"Cargo.toml",
"--output-dir",
".",
"--target",
Expand Down
Loading