# Oysterun npm Publish

This document defines the Oysterun Host npm package boundary and publish gate.
It is a release/operator document, not a general npm tutorial.

## Goal

The first public Host install path is:

```bash
npm install -g oysterun
oysterun
```

`npm install -g oysterun` installs package files and exposes the `oysterun`
command. It must not run setup, install a service, start a service, or ask
interactive questions.

## Package Boundary

Do not publish the monorepo root.

The npm package must be built from a clean release staging package. The staging
package is produced by:

```bash
node tool_scripts/package_oysterun_npm.mjs
```

The staging package includes only the Host runtime surface:

```text
package.json
README.md
bin/oysterun.mjs
host-service/
tool_scripts/ required by Host setup/service lifecycle
dev/client/web/ prebuilt dashboard assets
dev/client/web-chat/dist/ prebuilt Route C web-chat assets
static/
docs/routec/ minimal release docs
```

The package must exclude:

```text
backend/
dev/client/phone-app/
dev/client/web-chat/ios/
dev/client/web-chat/src/
prompts/
.secrets/
node_modules/
host-service/node_modules/
dev/client/web-chat/node_modules/
runtime config files
cloud_identity.json
DB/log/jsonl artifacts
Apple .p8 keys
credential_copy/
DerivedData/
```

## Package Name And Command

Target npm package name:

```text
oysterun
```

Target installed command:

```text
oysterun
```

If npm name ownership blocks `oysterun`, choose the fallback package name in a
separate Owner decision. Do not silently publish under another name.

## User Install Journey

Install:

```bash
npm install -g oysterun
```

First run:

```bash
oysterun
```

If required Host config is missing or incomplete, `oysterun` enters setup
automatically.

Explicit setup:

```bash
oysterun setup
```

Setup performs the release onboarding flow:

```text
ask Host display name
ask Host port, default 8802, with next-available fallback if occupied
ask Host URL/IP:port:
  prefer detected Tailscale/VPN or LAN URL
  localhost is only for a browser on the Mac running Oysterun
  iPhone on the same Wi-Fi/LAN should use the Mac LAN IP address
  otherwise use Tailscale, Cloudflare Tunnel, VPN, or another reachable URL
ask Host password with hidden input
confirm first-time Host password by entering it twice
write ~/.oysterun/config.json
create dashboard credential hash
register Cloud direct mode when enabled by release setup
write Host Cloud identity state outside user-editable config
create 15-minute one-time QR/bootstrap token
show phone app download/QR step
show Host login QR
install service manager integration
start Host by default after explicit setup flow
wait for /health
show/open /app/sessions when browser open is available
```

If setup runs in a headless or SSH environment, it should print the URL instead
of forcing a browser open.

## Service Model

First release target:

```text
macOS launchd LaunchAgent
```

Linux support is a later phase. It should use a systemd user service and must
not be claimed as implemented until verified on Linux.

Service commands:

```bash
oysterun service:start
oysterun service:stop
oysterun service:restart
oysterun service:status
oysterun service:logs
```

Explicit service commands should fail fast when setup has not completed. They
must not silently create config or run setup.

## Cloud Endpoint

The production Cloud endpoint is a git-tracked product constant.

It is not a user-editable Host Preference field and should not be stored as a
normal user-managed runtime config value.

Dev/local Cloud endpoints require an explicit debug config, environment
variable, or setup flag.

Host Cloud identity state belongs in runtime state such as:

```text
<host_config_dir>/cloud_identity.json
```

It must not be bundled into npm packages.

## Maintainer Build And Pack

Before packing, build the Route C web-chat dist in the source worktree:

```bash
npm --prefix dev/client/web-chat run build
node dev/client/web/build-index.mjs
```

Create staging package:

```bash
node tool_scripts/package_oysterun_npm.mjs
```

Inspect pack contents:

```bash
cd dist/npm/oysterun
npm pack --dry-run
```

Do not continue if the tarball includes any excluded file or directory.

## Publish Gate

Do not publish until all of these pass:

```text
package boundary exists
packaging script produced clean staging package
npm pack --dry-run passed
tarball content review found no excluded files
clean temp install works
oysterun --help works
oysterun with missing config enters setup
oysterun setup can create config and start Host on macOS
Host /health passes
web login / sessions page works
phone QR/manual login works
```

Only after the gate passes, Owner publishes from the staging package.

Do not use the deprecated `npm publish --otp <code>` flow as the normal
Oysterun publish path. npm now requires Owner to complete the account auth/2FA
flow directly, so the maintainer should provide the exact command block and let
Owner run the final `npm publish` command in an authenticated terminal.

Owner publish script:

```bash
cd /Users/wanghsuanchung/Projects/OysterunOwnerManualWork
npm run package:npm

cd /Users/wanghsuanchung/Projects/OysterunOwnerManualWork/dist/npm/oysterun
npm pack --dry-run
npm publish --tag beta
```

For stable, replace the last command with:

```bash
npm publish --tag latest
```

## Dist Tag Verification And Beta Practice

After publishing, verify registry tags explicitly. The publish success line:

```text
+ oysterun@0.1.0
```

only proves that the version was published. It does not prove which dist-tag was
assigned.

Verification commands:

```bash
npm dist-tag ls oysterun
npm view oysterun dist-tags --json
npm view oysterun@beta version
npm view oysterun@latest version
```

Install-channel smoke:

```bash
npm install -g oysterun@beta
oysterun --help
```

Current first publish result, 2026-06-06:

```text
beta:   0.1.0
latest: 0.1.0
```

This is acceptable for the first public bootstrap package because there was no
previous stable version to preserve. It means both commands install the same
package:

```bash
npm install -g oysterun@beta
npm install -g oysterun
```

Best practice for future beta releases:

```text
Use prerelease semver for beta channel:
  0.1.1-beta.0
  0.1.1-beta.1

Publish those with:
  npm publish --tag beta

Keep latest for stable releases only:
  0.1.1
  npm publish --tag latest
```

If a future beta publish accidentally moves `latest` away from the last stable
release, restore `latest` explicitly:

```bash
npm dist-tag add oysterun@<last-stable-version> latest
```

Do not use a semver-looking string as a dist-tag. `beta`, `next`, and `canary`
are valid channel names; tags like `v1.4` are not appropriate because npm
dist-tags share the same namespace as versions.

## Manual Product Smoke

After install/setup, maintainers may run a manual Cloud notification smoke.
This is not part of npm install and not part of setup automation.

Purpose:

```text
verify npm-installed Host -> Oysterun Cloud -> Apple APNs -> iPhone app
```

Checklist:

```text
1. Install package in a clean environment.
2. Run oysterun and complete setup.
3. Pair/login the iPhone app with the Host.
4. Enter sessions page.
5. Enable notifications.
6. Confirm app APNs token registration is accepted by Cloud.
7. Click Send test notification.
8. Confirm iPhone receives the test notification.
9. Run a provider complete-message flow.
10. Confirm iPhone receives the complete-message notification.
```

The iPhone app obtains the APNs token from Apple and registers it with Cloud.
The Host does not own APNs tokens or Apple `.p8` keys. The Host only submits
notification candidates to Cloud.

## Rollback

npm unpublish has strict registry limitations and should not be the normal
rollback path.

Preferred rollback:

```text
publish a patched version
deprecate the bad version with npm deprecate
tell users to install a known good version or tag
```
