@whereamimentioned/cli 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +318 -2
  2. package/dist/index.js +5468 -0
  3. package/package.json +56 -3
package/README.md CHANGED
@@ -1,3 +1,319 @@
1
- # Temporary Holding Version
1
+ # @whereamimentioned/cli
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ `wam`: track and score your brand's visibility in AI answers, from the terminal and from CI.
4
+
5
+ whereamimentioned asks AI assistants the questions your buyers ask, checks whether your brand is in
6
+ the answers, and scores how often you show up against the competitors that appear instead. The CLI
7
+ is the same product from a shell: free site checks that need no account, sign-in, scans and reports,
8
+ a gate for CI, and the installer for the MCP server.
9
+
10
+ Full documentation: https://whereamimentioned.com/docs/cli
11
+
12
+ ## Install
13
+
14
+ ```
15
+ npx @whereamimentioned/cli --help
16
+ ```
17
+
18
+ Or install it once:
19
+
20
+ ```
21
+ npm install -g @whereamimentioned/cli
22
+ wam --help
23
+ ```
24
+
25
+ Always install or run it by the scoped package name. The unscoped `wam` on npm is an unrelated
26
+ package. The binary is `wam`, with `wamctl` as an alias for machines where `wam` is already taken on
27
+ the PATH. Requires Node 20.19 or newer.
28
+
29
+ ## Free site checks, no account needed
30
+
31
+ Seven commands work with no account, no key and no config, from a cold `npx`. They spend no credits.
32
+
33
+ ```
34
+ wam site check-crawlers <url> which AI crawlers your robots.txt lets in
35
+ wam site validate-llms-txt <url> score and findings for an existing llms.txt
36
+ wam site generate-llms-txt <url> [--full] [-o <file>] crawl the site and write an llms.txt
37
+ wam site generate-sitemap <url> [-o <file>] crawl the site and write a sitemap.xml
38
+ wam site validate-schema <url> validate the page's structured data
39
+ wam site check-meta <url> [--keyword <keyword>] check the page's meta description
40
+ wam site analyze-chunks <url> how the page's content chunks for retrieval
41
+ ```
42
+
43
+ ```
44
+ npx @whereamimentioned/cli site check-crawlers example.com
45
+ ```
46
+
47
+ Every URL is fetched by the server, never by the CLI, so the checks see your site from the public
48
+ internet and not from inside your network. `generate-llms-txt` and `generate-sitemap` write the
49
+ generated file to stdout, so `> llms.txt` works, and put every count and notice on stderr; with `-o`
50
+ they write the file and print a summary to stderr. Add `--json` to any of them for the full
51
+ structured result.
52
+
53
+ ## Sign in
54
+
55
+ ```
56
+ wam auth login
57
+ ```
58
+
59
+ The default flow opens your browser at whereamimentioned.com. You pick an organization and approve,
60
+ and the key comes back to the CLI over a loopback port on your own machine (a PKCE code exchange, no
61
+ client secret, nothing to paste). Two alternatives:
62
+
63
+ - `wam auth login --device` for SSH sessions, containers, WSL and Codespaces, where no browser can
64
+ reach back to the machine. It prints a URL and a short code; you enter the code in a browser
65
+ anywhere.
66
+ - `wam auth login --token` reads a key you already minted in the dashboard, from stdin or a prompt.
67
+
68
+ By default the key is an organization key, bound to the organization you picked.
69
+ `wam auth login --account-wide` mints a key that reaches every organization your account belongs
70
+ to; the CLI spells out what that means and asks before the browser opens. An account-wide key gives
71
+ you no more permission anywhere, only more places to use it: in each organization it acts at your
72
+ own role there.
73
+
74
+ `wam auth status` (alias `wam whoami`) shows the key, the organization, the credit balance and where
75
+ the credential is stored. `wam auth logout` revokes the key on the server, then clears it locally.
76
+
77
+ **CI never calls `wam auth login`.** It sets `WAM_TOKEN` and nothing else. Mint that key with a
78
+ plain `wam auth login` on your own machine or in the dashboard, and keep it an organization key: a
79
+ CI secret that reaches every organization you belong to has a blast radius the job never needed.
80
+
81
+ ## Scans, reports and the rest
82
+
83
+ ```
84
+ wam scan estimate
85
+ wam scan run [--wait] [--yes] [--fail-under <n>] [--timeout <seconds>]
86
+ [--poll <seconds>] [--no-follow] [--idempotency-key <key>]
87
+ wam scan status <scanId> [--wait] [--timeout <seconds>] [--poll <seconds>]
88
+ wam scan list [--limit <n>] [--cursor <c>] [--status <queued|running|done|failed>]
89
+ wam scan evidence <scanId> [--limit <1..100>] [--cursor <c>] [--model <id>]
90
+ wam report get [--scan <scanId>] [--format json|csv|pdf] [-o <file>] [--fail-under <n>]
91
+ wam org list
92
+ wam org create <name> [--type brand|agency] [--yes] [--idempotency-key <key>]
93
+ wam workspace list
94
+ wam workspace use <org/workspace>
95
+ wam workspace create <name> [--yes]
96
+ wam competitor list
97
+ wam competitor add <name> [--domain <domain>] [--alias <alias>]...
98
+ wam prompt list [--enabled true|false] [--source generated|template|custom] [--stage <stage>]
99
+ wam prompt add <text> [--stage <awareness|research|comparison|purchase|branded>]
100
+ wam prompt enable <id>
101
+ wam prompt disable <id>
102
+ wam prompt remove <id>
103
+ wam config list | get <key> | set <key> <value> | unset <key> | path
104
+ wam mcp url [--readonly] [--scope org|workspace|none]
105
+ wam mcp install --client <client> [--readonly] [--scope org|workspace|none] [--global] [--print] [--yes]
106
+ wam completion bash | zsh | fish | powershell
107
+ ```
108
+
109
+ `wam <group> --help` lists the subcommands and every command's help ends with a copy-pasteable
110
+ example.
111
+
112
+ ### What spends credits, and what does not
113
+
114
+ `wam scan run` is the one command that spends credits. It always estimates first and prints the cost
115
+ before anything is charged, then asks; the default answer is no. In a non-interactive context (a
116
+ pipe, CI, `--json`) it will not prompt: pass `--yes`, or it exits 2 without spending anything. There
117
+ is no retry and no automatic rescan anywhere in the CLI. Every scan is started by exactly one
118
+ explicit command.
119
+
120
+ Everything else is free: `scan estimate`, `scan status`, `scan list`, `scan evidence`,
121
+ `report get`, `prompt list`, `competitor list`, `org list`, `workspace list` and every `wam site`
122
+ command spend zero credits. `wam org create` and `wam workspace create` spend nothing either; they
123
+ still ask for confirmation because neither can be undone from the CLI.
124
+
125
+ ### Output
126
+
127
+ stdout is data, stderr is chatter. `--json` prints a single JSON document on stdout (NDJSON under
128
+ `--wait`) and is a stability contract, so `wam report get --json | jq .score` works with no
129
+ `2>/dev/null`. Under `--json` an error is itself the data: it goes to stdout as a JSON object, with
130
+ the same exit code.
131
+
132
+ ## In CI
133
+
134
+ ```yaml
135
+ # .github/workflows/ai-visibility.yml
136
+ name: AI visibility
137
+
138
+ on:
139
+ schedule:
140
+ # Weekly, Monday 07:00 UTC. See the cost note below before making this more frequent.
141
+ - cron: "0 7 * * 1"
142
+ workflow_dispatch:
143
+
144
+ # Prevents two scheduled runs overlapping. The API would 409 anyway, but this is cheaper.
145
+ concurrency:
146
+ group: ai-visibility
147
+ cancel-in-progress: false
148
+
149
+ jobs:
150
+ scan:
151
+ runs-on: ubuntu-latest
152
+ timeout-minutes: 45
153
+ permissions:
154
+ contents: read
155
+ steps:
156
+ - uses: actions/setup-node@v7
157
+ with:
158
+ node-version: 22
159
+
160
+ # Fail early and cheaply if the balance cannot cover a scan. Costs nothing.
161
+ - name: Check the balance
162
+ env:
163
+ WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
164
+ WAM_ORG: acme
165
+ WAM_WORKSPACE: acme-eu
166
+ run: npx --yes @whereamimentioned/cli@0.1 scan estimate --json
167
+
168
+ - name: Run the scan
169
+ id: scan
170
+ env:
171
+ WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
172
+ WAM_ORG: acme
173
+ WAM_WORKSPACE: acme-eu
174
+ run: |
175
+ npx --yes @whereamimentioned/cli@0.1 scan run \
176
+ --wait --yes \
177
+ --fail-under 55 \
178
+ --timeout 2400 \
179
+ --json | tee scan.ndjson
180
+ tail -n 1 scan.ndjson > scan-result.json
181
+
182
+ - name: Fetch the full report
183
+ if: always() && steps.scan.outcome != 'skipped'
184
+ env:
185
+ WAM_TOKEN: ${{ secrets.WAM_TOKEN }}
186
+ WAM_ORG: acme
187
+ WAM_WORKSPACE: acme-eu
188
+ run: npx --yes @whereamimentioned/cli@0.1 report get --json -o report.json
189
+
190
+ - uses: actions/upload-artifact@v4
191
+ if: always()
192
+ with:
193
+ name: ai-visibility
194
+ path: |
195
+ scan.ndjson
196
+ report.json
197
+ ```
198
+
199
+ What that workflow does on purpose:
200
+
201
+ - `WAM_TOKEN` is an organization key, not an account-wide one. Nothing on the server can enforce
202
+ that; it is a rule for whoever mints the secret.
203
+ - `@0.1` pins the minor. While the package is `0.x`, a breaking change to the output lands in the
204
+ minor, so `@0` would protect nothing. Move the pins to `@1` on the day `1.0.0` ships.
205
+ - `--yes` is mandatory. Without it, `scan run` refuses in a non-interactive context and exits 2, so
206
+ no workflow spends credits by accident.
207
+ - The estimate step runs first and exits 4 when the balance is short, before anything is charged.
208
+ - `--timeout 2400` is below the job's `timeout-minutes`. On timeout the CLI exits 1 with the scan id
209
+ and the scan keeps running server side, so the next run can still read the report.
210
+ - `--fail-under 55` is an example threshold. Put yours on the flag or in `wam.json` as `failUnder`.
211
+ It compares the AI visibility score and exits 7 when the score is below it.
212
+ - A retried step does not start a second scan. The idempotency key is derived from the organization,
213
+ the workspace, the date and the CI run id, so a re-run follows the scan that already exists.
214
+
215
+ ## Exit codes
216
+
217
+ Nothing above 125 is used, because the shell reserves 126, 127 and 128 and above.
218
+
219
+ | Code | Meaning | Typical cause |
220
+ |---|---|---|
221
+ | 0 | Success | |
222
+ | 1 | Generic failure | Unexpected server 500, unhandled condition |
223
+ | 2 | Usage error | Unknown flag, missing argument, bad value, no workspace resolved, no org resolved on an account-wide key |
224
+ | 3 | Auth required or expired | No credential, a credential the server no longer accepts (revoked or expired), insufficient scope, insufficient role, tier gate |
225
+ | 4 | Insufficient credits | HTTP 402 from the scan-create route |
226
+ | 5 | Rate limited | HTTP 429 |
227
+ | 6 | Scan failed | The scan reached `status: "failed"` while being followed |
228
+ | 7 | Threshold not met | `--fail-under` was set and the score was below it |
229
+ | 8 | Scan already running | A 409 `scan_already_running` and `--no-follow` was passed |
230
+ | 9 | Conflict | The server rejected the request as conflicting (409 `conflict`): the priced terms moved, or an `Idempotency-Key` was reused with different terms |
231
+ | 10 | Ceiling reached | A 409 `conflict` at a limit that waiting does not clear: the plan's workspace cap, or the 25 organizations one account may own |
232
+ | 11 | No paid organization | A 403 `feature_not_available` from `wam org create`, because the account owns no organization on a paid plan |
233
+
234
+ ## Telemetry
235
+
236
+ This CLI sends no telemetry. It transmits nothing beyond the API calls needed to serve the command
237
+ you ran: no usage pings, no crash reporting, no anonymous metrics, no first-run beacon. The one other
238
+ network request is the update check against the npm registry, at most once a day, on stderr and never
239
+ blocking; it is off under `--json`, `--quiet`, in a pipe, when `CI` is set, or when
240
+ `WAM_NO_UPDATE_NOTIFIER` is set. The CLI never self-updates.
241
+
242
+ ## Credential storage
243
+
244
+ Keys are stored in the operating system's credential store, one entry per profile (the default
245
+ profile is `default`): the macOS Keychain, the Windows Credential Manager, or Secret Service (GNOME
246
+ Keyring, KWallet) on Linux, under the service name `whereamimentioned`. A profile holds one
247
+ credential, so you can keep one key per organization and switch with `--profile`, or hold one
248
+ account-wide key and switch organizations with `--org`. Both patterns work.
249
+
250
+ Where the credential store is not available (headless Linux, containers, no D-Bus session), the CLI
251
+ falls back to a file: `${XDG_CONFIG_HOME:-~/.config}/whereamimentioned/credentials.json` on Linux and
252
+ macOS, `%APPDATA%\whereamimentioned\credentials.json` on Windows. On Linux and macOS the file is
253
+ written with mode `0600` inside a `0700` directory, and if it is later found with looser permissions
254
+ the CLI refuses to read it and prints the `chmod` that fixes it. `wam auth status` always says which
255
+ of the two backends is in use, because a silently failing keyring is the usual reason for "why does
256
+ it keep asking me to log in". The CLI never prints the token, not under `--debug` and not in an error.
257
+
258
+ ## Configuration
259
+
260
+ Precedence, highest first: the command-line flag (`--org`, `--workspace`, `--api-url`,
261
+ `--profile`), the environment variable, the nearest `wam.json` found by walking up from the current
262
+ directory, the user config (`${XDG_CONFIG_HOME:-~/.config}/whereamimentioned/config.json`, or
263
+ `%APPDATA%\whereamimentioned\config.json` on Windows), then the built-in default. `wam config list`
264
+ prints the winning source for each key.
265
+
266
+ A committed `wam.json` pins the organization and workspace for a repo, so every checkout and every CI
267
+ run agree:
268
+
269
+ ```json
270
+ {
271
+ "$schema": "https://whereamimentioned.com/schema/wam.config.json",
272
+ "org": "acme",
273
+ "workspace": "acme-eu",
274
+ "failUnder": 55
275
+ }
276
+ ```
277
+
278
+ An unknown key in that file is a usage error (exit 2), not a silent ignore, and it has no field for a
279
+ token: a token in `wam.json` is a parse error. It cannot set `apiUrl` either: a committed file must
280
+ not get to decide where your key is sent, so set the server with `WAM_API_URL`, `--api-url` or
281
+ `wam config set apiUrl` instead, and an `apiUrl` in `wam.json` is refused with exit 2. `wam config set`
282
+ writes to the user config only, never to the project file.
283
+
284
+ ## Environment variables
285
+
286
+ | Variable | Meaning |
287
+ |---|---|
288
+ | `WAM_TOKEN` | The API key. Highest-precedence credential source. |
289
+ | `WAM_API_URL` | API origin override. Default `https://whereamimentioned.com`. |
290
+ | `WAM_ORG` | Org slug override. |
291
+ | `WAM_WORKSPACE` | Workspace slug override. |
292
+ | `WAM_PROFILE` | Credential and config profile name. Default `default`. |
293
+ | `WAM_CONFIG_DIR` | Override the user config and credential directory wholesale. |
294
+ | `WAM_NO_UPDATE_NOTIFIER` | Any non-empty value disables the update check. |
295
+ | `WAM_MCP_URL` | Only read by `wam mcp url` / `wam mcp install`, for staging. |
296
+ | `NO_COLOR` | Standard. Presence disables colour regardless of value. |
297
+ | `CI` | Standard. Presence implies `--non-interactive`. |
298
+
299
+ Credential precedence: the `--token` flag, then `WAM_TOKEN`, then the credential store or file for
300
+ the active profile. Prefer `WAM_TOKEN` over `--token`: arguments leak into shell history and process
301
+ listings.
302
+
303
+ ## Installing the MCP server
304
+
305
+ The CLI is the installer for the whereamimentioned MCP server, because no single config snippet works
306
+ everywhere: the top-level key and the transport name differ per client.
307
+
308
+ ```
309
+ wam mcp install --client cursor
310
+ ```
311
+
312
+ `--client` accepts `claude-code`, `cursor`, `vscode`, `windsurf`, `zed`, `warp`, `opencode`, `amp`
313
+ and `jetbrains`. The command merges the `whereamimentioned` entry into the client's existing config
314
+ and writes a backup next to it first. A project-scoped file never receives the raw token: it gets
315
+ `${WAM_TOKEN}` and a reminder to export it. Only `--global` writes the literal token, and only after
316
+ you confirm. `--print` writes the snippet to stdout and touches nothing. `wam mcp url` prints the
317
+ endpoint URL for the current organization and workspace, and nothing else, so it composes.
318
+
319
+ The server itself is documented at https://whereamimentioned.com/docs/mcp.