diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17d84fc..6762011 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [main] + branches: [main, feature/phase1-5] pull_request: - branches: [main] + branches: [main, feature/phase1-5] jobs: build-test: @@ -22,6 +22,10 @@ jobs: with: node-version: 22 + - name: Widget tests + run: npm ci && npm test + working-directory: npm/botwire-js + - name: Build (Release, warnings as errors) run: dotnet build BotWire.slnx -c Release diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2004eb4..71f5a2b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,3 +65,56 @@ jobs: args+=(--notes-file "$notes") fi gh release create "$GITHUB_REF_NAME" artifacts/*.nupkg artifacts/*.snupkg "${args[@]}" + + npm: + needs: release # only publish the JS SDK once the .NET release succeeded + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write # npm provenance (public-repo supply-chain attestation) + defaults: + run: + working-directory: npm/botwire-js + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + + - name: Verify tag matches package.json version + run: | + VERSION="${GITHUB_REF_NAME#v}" + PKG=$(node -p "require('./package.json').version") + if [ "$VERSION" != "$PKG" ]; then + echo "Tag $GITHUB_REF_NAME does not match botwire-js version $PKG in package.json" >&2 + exit 1 + fi + + - name: Setup Node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22 + registry-url: https://registry.npmjs.org + + - name: Install + run: npm ci + + - name: Build (SDK + widget) + run: npm run build + + - name: Test + run: npm test + + # Trusted Publishing (OIDC) needs a newer npm than Node 22 ships with. + - name: Upgrade npm + run: npm install -g npm@latest + + # No token: authenticates via OIDC against the trusted publisher configured + # for botwire-js on npmjs.com. Provenance is attached automatically. + # Idempotent: npm has no --skip-duplicate, so skip if the version already + # exists (e.g. a manually bootstrapped first publish) to keep re-runs green. + - name: Publish to npm (Trusted Publishing, OIDC) + run: | + VERSION=$(node -p "require('./package.json').version") + if npm view "botwire-js@$VERSION" version >/dev/null 2>&1; then + echo "botwire-js@$VERSION already published; skipping." + else + npm publish --access public + fi diff --git a/Directory.Build.props b/Directory.Build.props index 4b139d4..a2f30a6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ latest - 0.1.0 + 0.2.0 Object IT Limited diff --git a/NUGET.md b/NUGET.md new file mode 100644 index 0000000..a96254f --- /dev/null +++ b/NUGET.md @@ -0,0 +1,48 @@ +# BotWire + +**A 24/7 AI customer-support bot for your .NET app — self-hosted, bring-your-own-key, no SaaS fees.** + +Drop one package into your ASP.NET Core site, point it at your FAQ, and ship a support assistant that answers customers instantly from *your* docs — and quietly opens a human ticket the moment one is actually needed. You supply an OpenAI-compatible API key, so your only running cost is model tokens (pennies per conversation on `gpt-4o-mini` or DeepSeek). + +## Two lines to wire it up + +```csharp +builder.Services.AddBotWire(opts => +{ + opts.TopicDescription = "Online store customer support"; + opts.Documents = ["docs/faq.md"]; + opts.ChatProvider = new OpenAIProviderOptions { ApiKey = "sk-...", Model = "gpt-4o-mini" }; +}); + +app.MapBotWire(); +``` + +Embed the zero-dependency widget on any page: + +```html + + +``` + +## What you get + +- **Grounded answers.** Replies come only from the Markdown knowledge base you supply — no hallucinated policies, prices, or promises. +- **Knows when to get a human.** Collects contact details and raises a support ticket (emailed to your team) instead of guessing. +- **Streaming chat widget.** ~12 KB Web Component, Shadow DOM, no framework, one `