whistle-cli
v0.1.6
Published
AI-friendly CLI facade over Whistle
Downloads
979
Maintainers
Readme
whistle-cli
AI-friendly CLI facade over Whistle.
Prerequisites
- Node.js >= 20
whistleinstalled (npm install -g whistle) sow2is available on PATH
Install
# Install from npm (global)
npm i -g whistle-cli --registry=https://registry.npmjs.org/
# Upgrade
npm i -g whistle-cli@latest --registry=https://registry.npmjs.org/
# This repository (dev mode)
npm install
npm run dev -- --helpQuick Start
# Check command surface in dev mode
npm run dev -- --help
# Check Whistle availability
npm run dev -- raw w2 status
# Structured JSON output (default)
npm run dev -- --format json instance status
# Human-readable output
npm run dev -- --format pretty instance statusSkill (for AI agents)
Install from the public GitHub repository with a compatible skills installer:
skills add https://github.com/maxjchuang/whistle-cli --skill whistle-cliInstall the repository-distributed skill into the default skills directory:
./scripts/install-skill.shCommand Structure
whistle-cli provides three layers of commands:
| Layer | Purpose | Example |
| ------------ | ------------------------------------------------ | ----------------------------------------- |
| raw | Escape hatch, passthrough to w2 | whistle-cli raw w2 status |
| resource | Stable resource operations, preferred for agents | whistle-cli rules patch --preview |
| shortcut | High-frequency intent-driven commands | whistle-cli rule set-header --match ... |
Resource Commands (v1 target)
instance— start / stop / restart / status / list / selectrules— rollback / patch / import / export / apply / verify / list / get / enable / disablevalues— rollback / list / get / set / remove / import / exportcaptures— find / get / tail / diff / exportcomposer— replay / composeframes— list / sendruntime— serve the optional__whistle_cli__backend APIcerts— status / install / verify / guideproxy— status / set / off / verifyplugins— list / install / uninstall / enable / disable / inspectdoctor— instance-status / proxy-routing / https-captureraw— w2 passthrough
Shortcut Commands
bootstrap—start/preparerule—set-header/map-localcapture—find/find-errorplugin—install/remove/inspect/invoke(invokeis out of scope in v1)
Global Flags
| Flag | Description |
| ---------------------------------------- | --------------------------------------- |
| --format <json\|pretty\|table\|ndjson> | Output format, default json |
| --instance <id> | Target instance, defaults to current |
| --non-interactive | Fail instead of waiting for user action |
--preview, --apply, --verify, and --rollback are command-level flags on mutating resource commands (not global flags).
Common rollback forms:
rules rollback --action-id <id>values rollback --action-id <id>proxy set --rollback <id>plugins install --rollback <id>
Output Envelope
All output is a structured JSON envelope designed for machine parsing:
{
"status": "ok | warning | error | blocked",
"resource": "raw | instance | rules | values | captures | composer | frames | runtime | certs | proxy | plugins | doctor",
"action": "w2 status",
"data": {},
"error": {
"code": "INSTANCE_NOT_RUNNING",
"message": "...",
"reason": "...",
"suggested_fix": "..."
},
"next_actions": [{ "action": "...", "reason": "..." }],
"effective": true
}Reading the Envelope
status— success / failure decisionerror.code— stable machine-readable error classificationnext_actions— suggested next steps (agent doesn't need to guess)effective— whether a mutation is actually live at runtime
Error Codes
| Code | Meaning |
| ------------------------------- | ------------------------------------- |
| INSTANCE_NOT_RUNNING | Whistle instance is not running |
| INSTANCE_PORT_CONFLICT | Port already in use |
| CERT_NOT_INSTALLED | CA certificate not installed |
| CERT_NOT_TRUSTED | CA certificate not trusted by system |
| PROXY_NOT_ACTIVE | System proxy not pointing to Whistle |
| RULE_CONFLICT | Conflicting rules detected |
| RULE_VERIFY_FAILED | Rule verification failed |
| NO_CAPTURE_MATCH | No captured traffic matched the query |
| CAPTURE_BACKEND_UNAVAILABLE | Capture backend not accessible |
| PLUGIN_NOT_INSTALLED | Plugin not installed |
| PLUGIN_CAPABILITY_UNAVAILABLE | Plugin capability not available |
| PERMISSION_REQUIRED | Insufficient permissions |
| USER_ACTION_REQUIRED | Manual user action needed |
| UNSUPPORTED_OPERATION | Operation not supported |
Agent Integration
Typical Workflow
1. Environment check
whistle-cli --format json instance status
2. Start instance
whistle-cli --format json instance start
3. Safe mutation (preview -> apply -> verify)
whistle-cli rules patch --id main --file ./patch.txt --format json
whistle-cli rules apply --id main --file ./patch.txt --apply --verify --format json
4. Diagnose issues
whistle-cli --format json captures find --host api.example.com
whistle-cli --format json doctor https-capture
5. Handle blocked/error states
-> Read error.suggested_fix and inform user
-> Read next_actions for next stepRuntime Backend
whistle-cli includes an optional local runtime backend that serves the __whistle_cli__ API consumed by --backend runtime commands.
# Start a backend in front of a running Whistle Web API
whistle-cli --format json runtime serve \
--target-url http://127.0.0.1:8899 \
--host 127.0.0.1 \
--port 8898
# In another shell, route RuntimeClient calls to it
export WHISTLE_CLI_RUNTIME_URL=http://127.0.0.1:8898
whistle-cli --format json captures find --backend runtime --host example.com
whistle-cli --format ndjson captures tail --backend runtime --host example.com --limit 5
whistle-cli --format json composer compose --method GET --url https://example.com --applyThe runtime backend currently adapts capture data from Whistle's Web API and executes compose/replay with local HTTP requests. Frame routes return UNSUPPORTED_OPERATION until frame-level backend support is implemented.
Whistle Web Capture Retrieval
For browser-driven automation, prefer Whistle Web capture retrieval when the capture was detected with --backend whistle-web:
# Wait for a newly triggered request and keep only a redacted summary in the result
whistle-cli --format json captures assert-request \
--backend whistle-web \
--host app.example.com \
--path /api/ \
--timeout 90s \
--poll-interval 2s \
--fields capture_id,method,status_code,path,refererSafe Header Handoff
When an agent needs authenticated request headers for a follow-up command, prefer capture-headers so values are written to local files and not printed to stdout:
whistle-cli --format json captures capture-headers \
--backend whistle-web \
--host app.example.com \
--path /api/session \
--headers cookie,x-csrftoken,x-signature-key \
--timeout 120s \
--save-env .devops-headers.envBy default, the command ignores captures that were already present when it started. Use --allow-existing only when reusing a recent matching request is intended. Use --env-map cookie=DEVOPS_COOKIE to override generated env keys such as COOKIE or X_SIGNATURE_KEY.
The command fails unless --save-env or --save-json is provided. Its JSON output reports capture metadata and header presence only; it does not include header values.
# Retrieve the exact capture while it is still in the Whistle Web data window
whistle-cli --format json captures get \
--backend whistle-web \
--id <capture_id>
# Extract one request header from the exact capture
whistle-cli --format json captures get-header \
--backend whistle-web \
--id <capture_id> \
--header cookie
# Export filtered Whistle Web captures as JSON
whistle-cli --format json captures export \
--backend whistle-web \
--host app.example.com \
--path /api/ \
--export-format jsonassert-request remains redacted by default for safe agent-facing reporting. Explicit retrieval commands such as get, export, and get-header return captured request header values requested by the user, so avoid logging their output when headers contain credentials.
For continuous human-facing monitoring, use captures watch --watch with NDJSON output:
whistle-cli --format ndjson captures watch \
--backend whistle-web \
--host app.example.com \
--path /api/ \
--fields capture_id,method,status_code,path,x_tt_logid,request_id,referer \
--watch--watch keeps the process running until Ctrl-C or SIGTERM. It performs process-local in-memory de-duplication from the startup baseline and does not persist history across restarts. It still reads Whistle Web's recent capture window, so high-volume traffic can rotate old records out before they are observed.
For a single exact header, get-header remains available. Add --redact, --save-env, --save-json, or --save-value when the value should not appear in stdout.
If direct Whistle Web API fallback is unavoidable, use dumpCount to widen the returned session window, for example: /cgi-bin/get-data?startTime=0&dumpCount=1000.
Error Handling Pattern
result = run("whistle-cli rules patch --apply")
if result.status == "error":
match result.error.code:
case "INSTANCE_NOT_RUNNING":
run("whistle-cli instance start")
# retry
case "CERT_NOT_TRUSTED":
tell_user(result.error.suggested_fix)
case "PROXY_NOT_ACTIVE":
run("whistle-cli proxy set")
case _:
tell_user(result.error.message)
elif result.status == "blocked":
tell_user(result.next_actions)
elif result.status == "warning":
log(result.warnings)Development
# Build
npm run build
# Dev mode (tsx)
npm run dev -- raw w2 status
# Built binary
node dist/cli/index.js --help
# Test
npm run test
# Lint
npm run lintImplementation Status
| Command | Status |
| --------------- | --------- |
| raw w2 [args] | Available |
| instance/* | Available |
| rules/* | Available |
| values/* | Available |
| captures/* | Available |
| composer/* | Available |
| frames/* | Available |
| runtime serve | Available |
| certs/* | Available |
| proxy/* | Available |
| plugins/* | Available |
| doctor/* | Available |
| shortcuts/* | Available |
Current Limitations (v1)
captures diffexists in command surface but currently returnsUNSUPPORTED_OPERATION.captures tailrequires--format ndjson.- Runtime backend frame routes return
UNSUPPORTED_OPERATION; capture and composer runtime routes are implemented. - Certificate trust and some proxy setup steps may return
blockedorUSER_ACTION_REQUIREDand require manual OS actions.
License
MIT
