diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..d28bdf4 --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,56 @@ +name: Publish @synapt-dev/eval to npm + +on: + release: + types: [published] + workflow_dispatch: + # Manual re-trigger — needed because this workflow has no version-mismatch retry path: + # a `release` event fires it exactly once, and if npm's version hadn't moved yet at that + # point (e.g. a Python-only release, or this repo's own version-sync-deferred slices), + # there is no automatic second attempt once the npm version is later bumped. + +permissions: + contents: write + id-token: write + +jobs: + publish: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ts + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - run: npm ci + + - run: npm run typecheck + + - name: Check if this version is already published + id: check + run: | + VERSION=$(node -p "require('./package.json').version") + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + if npm view "@synapt-dev/eval@$VERSION" version >/dev/null 2>&1; then + echo "already_published=true" >> "$GITHUB_OUTPUT" + echo "@synapt-dev/eval@$VERSION is already published to npm -- skipping publish (this is expected on every release where only the PyPI side bumped, not an error)." + else + echo "already_published=false" >> "$GITHUB_OUTPUT" + fi + + - run: npm publish --provenance --access public + if: steps.check.outputs.already_published != 'true' + + - name: Generate SBOM + run: npm sbom --omit=dev --sbom-format cyclonedx > sbom.cdx.json + + - name: Upload SBOM to release + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ github.token }} + run: gh release upload ${{ github.event.release.tag_name }} sbom.cdx.json --clobber diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 0000000..04d1397 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,44 @@ +name: Publish synapt-eval to PyPI + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "3.12" + + - run: pip install build + + - run: python -m build + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pypi-dist + path: dist/ + + publish: + needs: build + runs-on: ubuntu-latest + environment: pypi + permissions: + id-token: write + steps: + - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: pypi-dist + path: dist/ + + - uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 + with: + packages-dir: dist/ + skip-existing: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 674de0b..b5ab4c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## v0.1.0 (2026-05-07) -Initial release of @synapt/eval. +Initial release of @synapt-dev/eval. ### Components diff --git a/README.md b/README.md index e8b68cd..23cb259 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# @synapt/eval +# @synapt-dev/eval [![PyPI](https://img.shields.io/pypi/v/synapt-eval)](https://pypi.org/project/synapt-eval/) [![Python](https://img.shields.io/pypi/pyversions/synapt-eval)](https://pypi.org/project/synapt-eval/) diff --git a/docs/ts-migration.md b/docs/ts-migration.md index 06a647d..378608b 100644 --- a/docs/ts-migration.md +++ b/docs/ts-migration.md @@ -1,6 +1,6 @@ # TypeScript Migration Guide -Migrate from a monolithic eval script to composable `@synapt/eval` adapters. +Migrate from a monolithic eval script to composable `@synapt-dev/eval` adapters. ## Before vs After @@ -15,7 +15,7 @@ See the working examples in `ts/examples/migration/`: Extract your retrieval/generation call into an adapter class: ```typescript -import type { RetrievalAdapter, RetrievalCandidate } from "@synapt/eval"; +import type { RetrievalAdapter, RetrievalCandidate } from "@synapt-dev/eval"; class MyRetrievalAdapter implements RetrievalAdapter { async retrieve(query: string, k = 10): Promise { @@ -30,7 +30,7 @@ class MyRetrievalAdapter implements RetrievalAdapter { Replace hand-rolled precision/recall with standard primitives: ```typescript -import { precisionAtK, recallAtK } from "@synapt/eval"; +import { precisionAtK, recallAtK } from "@synapt-dev/eval"; const p5 = precisionAtK(retrievedIds, expectedIds, 5); const r10 = recallAtK(retrievedIds, expectedIds, 10); @@ -41,7 +41,7 @@ const r10 = recallAtK(retrievedIds, expectedIds, 10); Replace `if (p5 < 0.5) failures.push(...)` with: ```typescript -import { SuggestionEngine } from "@synapt/eval"; +import { SuggestionEngine } from "@synapt-dev/eval"; const engine = SuggestionEngine.withDefaults(); const suggestions = engine.evaluateAll(results); @@ -53,7 +53,7 @@ const suggestions = engine.evaluateAll(results); Replace `console.log` with structured output: ```typescript -import { composeReportCard, generateMarkdown } from "@synapt/eval"; +import { composeReportCard, generateMarkdown } from "@synapt-dev/eval"; const card = composeReportCard({ results, suggestions }); console.log(generateMarkdown(card)); @@ -75,7 +75,7 @@ Write results to JSON and use the GitHub Action: With adapters, adding generation eval is one new class: ```typescript -import type { GenerationAdapter, GenerationOutput } from "@synapt/eval"; +import type { GenerationAdapter, GenerationOutput } from "@synapt-dev/eval"; class MyGenerationAdapter implements GenerationAdapter { async generate(query: string, context?: unknown[]): Promise { @@ -90,7 +90,7 @@ class MyGenerationAdapter implements GenerationAdapter { Extend the suggestion engine with domain-specific rules: ```typescript -import { SuggestionEngine, suggestionRule, SEVERITY_WARNING } from "@synapt/eval"; +import { SuggestionEngine, suggestionRule, SEVERITY_WARNING } from "@synapt-dev/eval"; const latencyRule = suggestionRule({ name: "high_latency" })((result) => { // Custom rule for your domain diff --git a/ts/examples/migration/after.ts b/ts/examples/migration/after.ts index 01e9584..a936f08 100644 --- a/ts/examples/migration/after.ts +++ b/ts/examples/migration/after.ts @@ -1,5 +1,5 @@ /** - * AFTER: Composable eval with @synapt/eval. + * AFTER: Composable eval with @synapt-dev/eval. * * Benefits: * - Adapter pattern decouples eval from backend implementation diff --git a/ts/examples/migration/before.ts b/ts/examples/migration/before.ts index 7a0d8f1..7742b00 100644 --- a/ts/examples/migration/before.ts +++ b/ts/examples/migration/before.ts @@ -1,5 +1,5 @@ /** - * BEFORE: Monolithic eval pattern (typical pre-@synapt/eval approach). + * BEFORE: Monolithic eval pattern (typical pre-@synapt-dev/eval approach). * * Problems with this pattern: * - Scoring, assertion, and reporting are interleaved diff --git a/ts/package-lock.json b/ts/package-lock.json index 9529865..a187347 100644 --- a/ts/package-lock.json +++ b/ts/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@synapt/eval", + "name": "@synapt-dev/eval", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@synapt/eval", + "name": "@synapt-dev/eval", "version": "0.1.0", "license": "MIT", "devDependencies": { diff --git a/ts/package.json b/ts/package.json index 8ced107..dd065ed 100644 --- a/ts/package.json +++ b/ts/package.json @@ -1,7 +1,12 @@ { - "name": "@synapt/eval", + "name": "@synapt-dev/eval", "version": "0.1.0", "description": "Domain-agnostic eval framework for AI applications", + "repository": { + "type": "git", + "url": "https://github.com/synapt-dev/eval.git", + "directory": "ts" + }, "type": "module", "exports": { ".": "./src/mod.ts"