@netwatchai/chat
v0.42.0
Published
Embeddable AI chat widget for Netwatch monitoring
Readme
Netwatch Widget
Quark, Netwatch's AI monitoring assistant, shipped as a self-contained Web Component (Shadow DOM — styles are fully isolated from the host page). Drop in one script tag to add a chat bubble to any page.
Published to npm as @netwatchai/chat and served over jsDelivr:
https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js(Pin a version with @0.1.0 instead of @latest for stability.)
Features
- 💬 Real-time streaming chat interface
- 📱 Fully responsive and embeddable
- 🎨 Tailwind CSS styling with complete style isolation
- 🔄 Web Component with Shadow DOM
- ↔️ Resizable and expandable interface
- 🌙 Dark mode support
- 📦 Distributable via CDN
Embedding
Two equivalent ways — both load the single bundle from jsDelivr.
1. Declarative (custom element)
<script type="module"
src="https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js"></script>
<netwatch-widget
client-id="b48ea317-…"
api-endpoint="http://your-api:8000">
</netwatch-widget>2. Programmatic (one-liner — PHP / CMS friendly)
<script type="module">
import NetwatchChat from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";
NetwatchChat.initBubble({
clientId: "b48ea317-…",
apiHost: "http://your-api:8000",
});
</script>Options
| Attribute | initBubble key | Required | Notes |
|----------------|-----------------------|----------|-------|
| client-id | clientId | yes | Netwatch client UUID |
| api-endpoint | apiHost / apiEndpoint | yes | API base URL (a trailing /api/chat is stripped automatically) |
| username | username | no | Auto-resolved from the host page's localStorage when embedded in the Netwatch UI. Pass explicitly to override, or when embedding on other hosts. |
| stall-timeout-ms | stallTimeoutMs | no | Progress-watchdog window (default 90000; 0 disables). A reply with no stream frame for this long is re-sent once, then shown as failed with a Retry button. Widen for a slow model; the stub-server harness (scripts/chat_stall_stub.py) shrinks it. |
Embedding in the Netwatch monitoring UI
The widget auto-reads the logged-in user from the host page's localStorage, so it only needs its script injected on every (logged-in) page. The UI has no built-in custom-JS setting, so use one of:
Option A — reverse proxy injection (recommended, survives upgrades). With nginx in front of the frontend:
location / {
proxy_pass http://frontend-upstream;
proxy_set_header Accept-Encoding ""; # sub_filter needs uncompressed HTML
sub_filter_once on;
sub_filter_types text/html;
sub_filter '</body>'
'<script type="module">import N from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";N.initBubble({clientId:"b48ea317-…",apiHost:"http://your-api:8000"});</script></body>';
}Option B — edit the frontend's page layout template (ui/include/views/layout.htmlpage.php),
just before the </body> output. ⚠️ This is overwritten on every upgrade, so
reapply it after upgrading:
echo '<script type="module">import N from "https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js";N.initBubble({clientId:"b48ea317-…",apiHost:"http://your-api:8000"});</script>';⚠️ Mixed content: if the UI is served over HTTPS but
api-endpointishttp://…, browsers silently block the API calls. Serve the API over HTTPS too, or keep both on plain HTTP within a private network/tunnel.
Development
pnpm install
# Copy the env template and fill it in.
cp .env.example .envEdit .env:
VITE_API_ENDPOINT=http://localhost:8000
VITE_DEV_CLIENT_ID=your-client-uuid
VITE_DEV_USERNAME=your-netwatch-usernameBoth .env and .env.local are gitignored; only .env.example is committed.
Start the dev server:
pnpm run devVisit http://localhost:5173 for the test page; it reads the env vars via
src/config.js and mounts the widget automatically.
Build
pnpm run buildOutputs to lib/ (the @latest/lib/web.min.js jsDelivr path):
lib/web.min.js— ES module (modern<script type="module">/ npm import)lib/web.umd.js— UMD build (legacy<script>tag →window.NetwatchChat)
Publishing / Deploying
Published to npm as @netwatchai/chat by .github/workflows/widget-publish.yml,
triggered by pushing a widget-v* git tag. The version is taken from the
tag, so a release never commits back to the protected main branch and needs
no privileged token — just NPM_TOKEN. Consumers pick it up via jsDelivr at
https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js.
Quick path: bump the version (changesets, below) and commit, then run
pnpm run release:tagfromwidget/— it validates, builds, tags, pushes, and watches the publish run. Full reference: docs/widget-release.md.
Release steps
Bump the version on
mainvia a normal PR. Easiest is to consume any changesets intopackage.json+CHANGELOG.md:cd frontend/widget pnpm changeset # (optional) describe the change → feeds CHANGELOG pnpm run version-packages # bumps package.json + CHANGELOG, consumes changesetsKeep changeset summaries in Netwatch terms — they become the public
CHANGELOG.md. Commit, open a PR, and merge it tomain.Tag the merge commit and push the tag (must match
package.json):git fetch origin git tag widget-v0.6.0 origin/main # widget-v<version> git push origin widget-v0.6.0The workflow fires on the tag: it sets
package.jsonto the tag's version, builds, and runsnpm publish. It fails loudly if that version is already on npm (bump and re-tag) or if the tag isn'twidget-v<semver>.
Why tags, not push-to-main? The org ruleset requires PRs on
mainand blocks the Actions bot from pushing — so a CI-driven version-bump commit can't land. Pushing a tag sidesteps the protected branch entirely. (The earlier auto-on-merge workflow failed silently for exactly this reason.)
Requires repo secret NPM_TOKEN — a granular npm token with "Bypass
two-factor authentication (2FA)" checked and read/write on the @netwatchai
scope (a token without the 2FA bypass fails publish with EOTP).
What a release looks like (the 0.7.0 example)
The exact sequence used to cut @netwatchai/[email protected] (pnpm commands from
widget/, git from anywhere in the repo):
# 1. Describe the change (feeds CHANGELOG); pick patch / minor / major.
pnpm changeset # or hand-write .changeset/<slug>.md
# 2. Roll pending changesets into the version + CHANGELOG.
pnpm run version-packages # e.g. 0.6.0 → 0.7.0, deletes the changeset
# 3. Commit the bump and push the branch.
git commit -am "chore(widget): release 0.7.0 (SLA settings UI)"
git push origin <branch>
# 4. Tag that commit and push the tag — pushing the tag is what publishes.
git tag widget-v0.7.0
git push origin widget-v0.7.0 # → fires .github/workflows/widget-publish.ymlThe tag may point at any commit, not just main: CI checks out the tagged
commit, sets package.json to the tag's version, builds, and publishes. 0.7.0
was cut from a feature branch this way — shipping the widget ahead of merging its
backend PR. Prefer tagging main for normal releases.
Verify the publish
gh run watch --exit-status # follow the "Widget publish" run to green
npm view @netwatchai/chat version # → 0.7.0Live within a few minutes via jsDelivr at
https://cdn.jsdelivr.net/npm/@netwatchai/chat@latest/lib/web.min.js
(@latest resolves to the new version; pin @0.7.0 to be explicit).
Architecture
- Web Components — native browser API for encapsulation
- Shadow DOM — complete style isolation from the parent page
- React — internal rendering framework
- Vercel AI SDK — streaming chat interface
- Tailwind CSS — utility-first styling
- Streamdown — markdown rendering
License
MIT
