Compare commits

...

4 Commits

6 changed files with 103 additions and 3 deletions

View File

@@ -20,12 +20,21 @@ The no-reply provider returns `NO_REPLY` for any input.
- `plugin/` — OpenClaw plugin (before_model_resolve hook)
- `no-reply-api/` — OpenAI-compatible minimal API that always returns `NO_REPLY`
- `docs/` — rollout and configuration notes
- `scripts/` — smoke/dev helper scripts
---
## Development plan (incremental commits)
- [x] Task 1: project docs + structure
- [ ] Task 2: no-reply API MVP
- [ ] Task 3: plugin MVP with rule chain
- [ ] Task 4: sample config + quick verification scripts
- [x] Task 2: no-reply API MVP
- [x] Task 3: plugin MVP with rule chain
- [x] Task 4: sample config + quick verification scripts
- [x] Task 5: plugin rule extraction + hardening
- [x] Task 6: containerization + compose
- [x] Task 7: plugin usage notes
- [x] Task 8: sender normalization + TTL + one-shot decision
- [x] Task 9: auth-aware no-reply API
- [x] Task 10: smoke test helpers
- [x] Task 11: plugin structure checker
- [x] Task 12: rollout checklist

33
docs/ROLLOUT.md Normal file
View File

@@ -0,0 +1,33 @@
# WhisperGate Rollout Checklist
## Stage 0: Local sanity
- Start API: `./scripts/dev-up.sh`
- Smoke API: `./scripts/smoke-no-reply-api.sh`
- Check plugin files: `cd plugin && npm run check`
## Stage 1: Canary (single Discord session)
- Enable plugin with:
- `discordOnly=true`
- narrow `bypassUserIds`
- strict `endSymbols`
- Point no-reply provider/model to local API
- Verify 4 rule paths in `docs/VERIFY.md`
## Stage 2: Wider channel rollout
- Expand `bypassUserIds` and symbol list based on canary outcomes
- Monitor false-silent turns
- Keep fallback model available
## Stage 3: Production hardening
- Set `AUTH_TOKEN` for no-reply API
- Run behind private network / loopback
- Add service supervisor (systemd or compose restart policy)
## Rollback
- Disable plugin entry `whispergate.enabled=false` OR remove plugin path
- Keep API service running; it is inert when plugin disabled

10
plugin/package.json Normal file
View File

@@ -0,0 +1,10 @@
{
"name": "whispergate-plugin",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "WhisperGate OpenClaw plugin",
"scripts": {
"check": "node ../scripts/check-plugin-files.mjs"
}
}

View File

@@ -0,0 +1,29 @@
import fs from 'node:fs';
import path from 'node:path';
const root = path.resolve(process.cwd(), '..');
const pluginDir = path.join(root, 'plugin');
const required = ['index.ts', 'rules.ts', 'openclaw.plugin.json', 'README.md', 'package.json'];
let ok = true;
for (const f of required) {
const p = path.join(pluginDir, f);
if (!fs.existsSync(p)) {
ok = false;
console.error(`missing: ${p}`);
}
}
const manifestPath = path.join(pluginDir, 'openclaw.plugin.json');
if (fs.existsSync(manifestPath)) {
const m = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
for (const k of ['id', 'entry', 'configSchema']) {
if (!(k in m)) {
ok = false;
console.error(`manifest missing key: ${k}`);
}
}
}
if (!ok) process.exit(1);
console.log('plugin file check: ok');

6
scripts/dev-down.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT_DIR"
docker compose down

13
scripts/dev-up.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT_DIR"
echo "[whispergate] building/starting no-reply API container"
docker compose up -d --build whispergate-no-reply-api
echo "[whispergate] health check"
curl -sS http://127.0.0.1:8787/health
echo "[whispergate] done"