@gscdump/cli 3.4.4 → 3.6.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 (57) hide show
  1. package/README.md +217 -54
  2. package/bin/gscdump.mjs +6 -1
  3. package/dist/analysis-local.mjs +1 -1
  4. package/dist/auth-state.mjs +112 -0
  5. package/dist/auth.mjs +109 -122
  6. package/dist/bing-auth.mjs +200 -0
  7. package/dist/bing-data.mjs +160 -0
  8. package/dist/bing-hosted.mjs +121 -0
  9. package/dist/cli.d.mts +4 -4
  10. package/dist/cli.mjs +20 -21
  11. package/dist/cloud-google.mjs +92 -0
  12. package/dist/command-meta.mjs +13 -1
  13. package/dist/command-registry.mjs +5 -2
  14. package/dist/commands/analyze.mjs +34 -177
  15. package/dist/commands/auth.mjs +161 -7
  16. package/dist/commands/bing.mjs +337 -0
  17. package/dist/commands/config.mjs +36 -43
  18. package/dist/commands/doctor.mjs +73 -24
  19. package/dist/commands/dump.mjs +1 -1
  20. package/dist/commands/entities.mjs +4 -4
  21. package/dist/commands/indexing.mjs +11 -14
  22. package/dist/commands/init.mjs +1 -1
  23. package/dist/commands/inspect.mjs +3 -3
  24. package/dist/commands/mcp.mjs +16 -2
  25. package/dist/commands/papercut.mjs +76 -0
  26. package/dist/commands/profile-selection.mjs +2 -2
  27. package/dist/commands/profile.mjs +8 -3
  28. package/dist/commands/query.mjs +86 -40
  29. package/dist/commands/report.mjs +5 -3
  30. package/dist/commands/sitemaps.mjs +24 -18
  31. package/dist/commands/skill.mjs +52 -0
  32. package/dist/commands/stats.mjs +58 -32
  33. package/dist/commands/sync.mjs +58 -25
  34. package/dist/config.mjs +39 -4
  35. package/dist/context.mjs +13 -8
  36. package/dist/env-file.mjs +1 -1
  37. package/dist/local-store.mjs +2 -2
  38. package/dist/mcp/errors.mjs +8 -0
  39. package/dist/mcp/handlers/diagnostics.mjs +31 -0
  40. package/dist/mcp/handlers/reports.mjs +38 -11
  41. package/dist/mcp/server/index.mjs +9 -10
  42. package/dist/mcp/types.mjs +8 -3
  43. package/dist/package.mjs +1 -1
  44. package/dist/papercut.mjs +99 -0
  45. package/dist/render/analysis.mjs +98 -0
  46. package/dist/render/charts.mjs +170 -0
  47. package/dist/render/layout.mjs +87 -0
  48. package/dist/render/metrics.mjs +163 -0
  49. package/dist/render/query.mjs +30 -0
  50. package/dist/render/report.mjs +69 -0
  51. package/dist/render/terminal.mjs +25 -0
  52. package/dist/runtime.d.mts +5 -5
  53. package/dist/runtime.mjs +1 -1
  54. package/dist/skill.mjs +45 -0
  55. package/dist/utils.mjs +10 -38
  56. package/package.json +14 -12
  57. package/skills/gscdump/SKILL.md +287 -0
package/dist/skill.mjs ADDED
@@ -0,0 +1,45 @@
1
+ import { cp, mkdir, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const SKILL_NAME = "gscdump";
5
+ const SKILL_AGENTS = ["claude", "codex"];
6
+ const AGENT_DIRECTORIES = {
7
+ claude: ".claude",
8
+ codex: ".codex"
9
+ };
10
+ function skillSourceDirectory(moduleUrl = import.meta.url) {
11
+ return path.join(path.dirname(fileURLToPath(moduleUrl)), "..", "skills", SKILL_NAME);
12
+ }
13
+ function skillDestination(homeDirectory, agent) {
14
+ return path.join(homeDirectory, AGENT_DIRECTORIES[agent], "skills", SKILL_NAME);
15
+ }
16
+ async function installSkill(options) {
17
+ const source = options.sourceDirectory ?? skillSourceDirectory();
18
+ if (!(await stat(source).catch(() => {
19
+ return null;
20
+ }))?.isDirectory()) return {
21
+ _tag: "Err",
22
+ reason: "source_missing",
23
+ message: `The packaged skill is missing at ${source}. Reinstall @gscdump/cli, then run the command again.`
24
+ };
25
+ const destination = options.target ? path.join(options.target, SKILL_NAME) : skillDestination(options.homeDirectory, options.agent);
26
+ return mkdir(path.dirname(destination), { recursive: true }).then(() => cp(source, destination, {
27
+ recursive: true,
28
+ force: true
29
+ })).then(() => ({
30
+ _tag: "Ok",
31
+ installation: {
32
+ agent: options.agent,
33
+ source,
34
+ destination
35
+ }
36
+ })).catch((cause) => {
37
+ const detail = cause instanceof Error ? cause.message : String(cause);
38
+ return {
39
+ _tag: "Err",
40
+ reason: "write_failed",
41
+ message: `Could not write the skill to ${destination}: ${detail}`
42
+ };
43
+ });
44
+ }
45
+ export { SKILL_AGENTS, SKILL_NAME, installSkill, skillDestination, skillSourceDirectory };
package/dist/utils.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { useCliRuntime } from "./runtime.mjs";
2
2
  import { version } from "./package.mjs";
3
3
  import process from "node:process";
4
- import os from "node:os";
5
4
  import fs from "node:fs/promises";
6
- import { Buffer } from "node:buffer";
5
+ import os from "node:os";
7
6
  import { SearchTypes } from "gscdump/query";
7
+ import { Buffer } from "node:buffer";
8
8
  const ALL_SEARCH_TYPES = Object.values(SearchTypes);
9
9
  const VERSION = version;
10
10
  function noSubcommandSelected(parent, subNames) {
@@ -65,13 +65,17 @@ function parseSearchType(value, flag = "--search-type") {
65
65
  }
66
66
  return v;
67
67
  }
68
+ function parseIntegerOption(value, flag, minimum = 1) {
69
+ if (value === void 0 || value === null) return void 0;
70
+ const text = typeof value === "number" || typeof value === "string" ? String(value).trim() : "";
71
+ const parsed = Number(text);
72
+ if (!/^\d+$/.test(text) || !Number.isSafeInteger(parsed) || parsed < minimum) throw new Error(`${flag} must be ${minimum === 0 ? "a non-negative integer" : "a positive integer"}.`);
73
+ return parsed;
74
+ }
68
75
  const ANSI_RE = /\x1B\[[0-9;]*m/g;
69
76
  function setNoColor(disable) {
70
77
  if (disable) useCliRuntime().colorEnabled = false;
71
78
  }
72
- function configureColor(opts) {
73
- if (opts.noColor || !opts.forceColor && !opts.stderrIsTTY) setNoColor(true);
74
- }
75
79
  function isColorEnabled() {
76
80
  return useCliRuntime().colorEnabled;
77
81
  }
@@ -180,36 +184,4 @@ async function readUrlList(args) {
180
184
  }
181
185
  return [];
182
186
  }
183
- function exportToCSV(output) {
184
- const sections = [];
185
- if (output.pages?.data) sections.push(`# Pages\n${toCSV(output.pages.data, [
186
- "url",
187
- "clicks",
188
- "impressions",
189
- "ctr",
190
- "position"
191
- ])}`);
192
- if (output.keywords?.current) sections.push(`# Keywords (Current Period)\n${toCSV(output.keywords.current, [
193
- "query",
194
- "clicks",
195
- "impressions",
196
- "ctr",
197
- "position"
198
- ])}`);
199
- if (output.countries?.current) sections.push(`# Countries (Current Period)\n${toCSV(output.countries.current, [
200
- "country",
201
- "clicks",
202
- "impressions",
203
- "ctr",
204
- "position"
205
- ])}`);
206
- if (output.devices?.current) sections.push(`# Devices (Current Period)\n${toCSV(output.devices.current, [
207
- "device",
208
- "clicks",
209
- "impressions",
210
- "ctr",
211
- "position"
212
- ])}`);
213
- return sections.join("\n\n");
214
- }
215
- export { ALL_SEARCH_TYPES, OUTPUT_ARGS, VERSION, applyOutputMode, clearLine, color, configureColor, cyan, dim, displayPath, exportToCSV, formatAge, isColorEnabled, logger, noSubcommandSelected, parseSearchType, progressBar, readUrlList, runWithConcurrency, setNoColor, setQuiet, showSplash, toCSV, withConfiguredOutput };
187
+ export { ALL_SEARCH_TYPES, OUTPUT_ARGS, VERSION, applyOutputMode, clearLine, color, cyan, dim, displayPath, formatAge, isColorEnabled, logger, noSubcommandSelected, parseIntegerOption, parseSearchType, progressBar, readUrlList, runWithConcurrency, setNoColor, setQuiet, showSplash, toCSV, withConfiguredOutput };
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@gscdump/cli",
3
3
  "type": "module",
4
- "version": "3.4.4",
5
- "description": "CLI for Google Search Console - dump, query, and run MCP server",
4
+ "version": "3.6.0",
5
+ "description": "CLI for Google Search Console and Bing with hosted or local authentication, data exports, and an MCP server",
6
6
  "author": {
7
7
  "name": "Harlan Wilton",
8
8
  "email": "harlan@harlanzw.com",
@@ -35,30 +35,32 @@
35
35
  },
36
36
  "files": [
37
37
  "bin",
38
- "dist"
38
+ "dist",
39
+ "skills"
39
40
  ],
40
41
  "engines": {
41
42
  "node": ">=22"
42
43
  },
43
44
  "dependencies": {
44
- "@clack/prompts": "^1.7.0",
45
- "@duckdb/node-api": "1.5.1-r.2",
46
- "@gscdump/analysis": "^3.4.4",
47
- "@gscdump/engine": "^3.4.4",
48
- "@gscdump/engine-gsc-api": "^3.4.4",
49
- "@gscdump/sdk": "^3.4.4",
45
+ "@clack/prompts": "^1.8.0",
46
+ "@duckdb/node-api": "1.5.5-r.4",
47
+ "@gscdump/analysis": "^3.6.0",
48
+ "@gscdump/engine": "^3.6.0",
49
+ "@gscdump/engine-gsc-api": "^3.6.0",
50
+ "@gscdump/sdk": "^3.6.0",
50
51
  "@modelcontextprotocol/sdk": "^1.30.0",
51
52
  "citty": "^0.2.2",
52
53
  "consola": "^3.4.2",
53
54
  "google-auth-library": "^11.0.2",
54
- "gscdump": "^3.4.4",
55
+ "gscdump": "^3.6.0",
55
56
  "ofetch": "^1.5.1",
56
57
  "open": "^11.0.2",
57
58
  "sitemapd": "^0.2.2",
58
- "zod": "^4.5.4"
59
+ "string-width": "^8.2.2",
60
+ "zod": "^4.6.1"
59
61
  },
60
62
  "devDependencies": {
61
- "vitest": "^4.1.11"
63
+ "vitest": "^5.0.0"
62
64
  },
63
65
  "scripts": {
64
66
  "build": "obuild",
@@ -0,0 +1,287 @@
1
+ ---
2
+ name: gscdump
3
+ description: Drive the `gscdump` CLI for Google Search Console and Bing with cloud or local authentication. Sync Google rows to a local Store, export Bing datasets, run SEO Analyzers and Reports, inspect Indexing Evidence, and manage sitemaps. Use when the user mentions gscdump, Search Console data, Bing Webmaster data, or GSC automation.
4
+ ---
5
+
6
+ # gscdump CLI
7
+
8
+ `gscdump` reads Google Search Console and Bing with hosted or local authentication.
9
+ It keeps a local Parquet Store for Google rows. Every command has `--help`.
10
+
11
+ ## Authentication mode
12
+
13
+ Check `gscdump auth status --json` before queries. Reuse the user's selected mode.
14
+
15
+ | Mode | Credentials | Query path |
16
+ | --- | --- | --- |
17
+ | `cloud` | gscdump user API key | `https://gscdump.com/api` uses saved Search Engine connections |
18
+ | `local` | Google OAuth/service account or Bing API key/OAuth | Calls the Search Engine directly |
19
+
20
+ `--mode cloud|local` overrides one invocation. `GSCDUMP_AUTH_MODE` also overrides the saved mode.
21
+ A successful login saves the mode per profile.
22
+ If no mode is saved, `GSCDUMP_API_KEY` selects cloud mode.
23
+ With neither source, the CLI defaults to local mode.
24
+ When a saved mode exists, it remains selected unless an explicit override applies.
25
+ Never switch modes to bypass an authentication failure.
26
+ `GSCDUMP_API_ROOT` defaults to `https://gscdump.com/api`. Supply the API key explicitly when changing a saved API root.
27
+
28
+ ```sh
29
+ # The user supplies a user API key from gscdump.com settings.
30
+ gscdump auth login --mode cloud
31
+ gscdump bing sites --json
32
+ gscdump bing login --site s_SITE_ID
33
+ gscdump bing dump --site s_SITE_ID --out ./bing-export --format json
34
+
35
+ # Local Google and Bing credentials stay separate.
36
+ gscdump auth login --mode local
37
+ gscdump bing login --mode local
38
+ gscdump bing dump --site https://example.com/ --out ./bing-export
39
+ ```
40
+
41
+ Hosted Bing login opens the existing connection flow on gscdump.com.
42
+ Local Bing login uses `BING_API_KEY` or a password prompt.
43
+ Local `--oauth` uses `BING_CLIENT_ID`, `BING_CLIENT_SECRET`, and a registered loopback callback.
44
+ The default callback is `http://127.0.0.1:53683/oauth/bing`. `BING_ACCESS_TOKEN` accepts an existing OAuth access token.
45
+ After cloud Bing login opens a browser, use `bing status --site s_SITE_ID` to confirm the connection.
46
+
47
+ `auth logout` removes the saved mode and saved Google and Bing credentials.
48
+ `bing logout --mode local` removes only saved Bing credentials. Environment credentials remain active until unset.
49
+
50
+ Hosted Bing commands use the API's plan and preview access rules.
51
+ Hosted connection verification uses `bing verify --site s_SITE_ID`.
52
+ Google Indexing API and Site Verification commands require local mode.
53
+ Hosted sitemap membership and history require hosted credentials.
54
+
55
+ ## Data boundaries
56
+
57
+ - `sync`, `query --live`, `analyze --live`, `report --live`, `sites`,
58
+ `sitemaps`, and `inspect` use the selected authentication mode.
59
+ - Google Indexing API requests require local credentials. `indexing quota` only prints documented limits and needs no authentication.
60
+ - `query`, `analyze`, `report`, `dump`, and `store` read the local Store by
61
+ default. If the Store has no rows for the Site, sync first or pass `--live`.
62
+ - Google returns a 2 to 3 day data delay. Default windows end three days ago.
63
+ - Google omits low-volume rows. Pagination cannot recover them.
64
+ - URL Inspection is limited to 2,000 requests per Site per day.
65
+ - `indexing submit` and `indexing remove` are only for job posting and
66
+ livestream pages. Google rejects other content.
67
+
68
+ ## Get the binary
69
+
70
+ ```sh
71
+ npx -y @gscdump/cli --version # no install
72
+ npm install -g @gscdump/cli # or pnpm add -g
73
+ ```
74
+
75
+ Use Node 22.13 or later in the 22 release line, or Node 24 or later.
76
+ `gscdump` alone is the library; `@gscdump/cli`
77
+ provides the command.
78
+
79
+ ## Install this skill
80
+
81
+ ```sh
82
+ gscdump skill install --agent claude # Codex: --agent codex
83
+ ```
84
+
85
+ After upgrading the CLI, run this command again to update the installed skill.
86
+ The command prints where it wrote the skill. Clients without a skill
87
+ directory can read `gscdump --help` and `gscdump <command> --help` instead.
88
+
89
+ ## Local Google authentication
90
+
91
+ Check first. Never run `init` when credentials already work.
92
+
93
+ ```sh
94
+ gscdump auth status
95
+ gscdump doctor --json
96
+ ```
97
+
98
+ If local Google credentials are missing, use one of these paths:
99
+
100
+ | Path | When | Command |
101
+ | --- | --- | --- |
102
+ | Environment token | The user already has an OAuth access token | `export GSC_ACCESS_TOKEN=ya29...` |
103
+ | Refresh token | CI or a headless machine with OAuth client credentials | `export GSC_CLIENT_ID=... GSC_CLIENT_SECRET=... GSC_REFRESH_TOKEN=...` |
104
+ | Service account | CI with a service-account key that has Site access | `export GOOGLE_APPLICATION_CREDENTIALS=/abs/path/key.json` |
105
+ | Interactive OAuth | A person is present | `gscdump init --mode local` |
106
+
107
+ `init` needs a Google Cloud OAuth client of type Desktop app. Ask the user to
108
+ run it; do not guess client credentials. Use `gscdump auth login --mode local --no-browser`
109
+ when a browser cannot open.
110
+ Run `gscdump auth login --mode local` to save local mode after configuring credentials.
111
+
112
+ `--profile <name>` or `GSCDUMP_PROFILE` isolates the selected mode and Google, Bing, and cloud credentials.
113
+
114
+ ## Site identifiers
115
+
116
+ For Google, use the exact value that `gscdump sites` prints.
117
+
118
+ - Domain property: `sc-domain:example.com`
119
+ - URL-prefix property: `https://example.com/` (trailing slash included)
120
+
121
+ For cloud Bing commands, use a Site ID from `gscdump bing sites`, such as `s_SITE_ID`.
122
+ For local Bing commands, use the full verified Site URL from `gscdump bing sites --mode local`.
123
+ Bing commands require their own explicit `--site`; the Google `defaultSite` setting does not select a Bing Site.
124
+
125
+ Set a default once to drop `--site` from later commands:
126
+
127
+ ```sh
128
+ gscdump config set defaultSite sc-domain:example.com
129
+ ```
130
+
131
+ ## Output
132
+
133
+ Pass `--json` on every command that supports it. `query` uses
134
+ `--format json` and prints rows to stdout. Progress goes to stderr, so stdout
135
+ stays parseable. `--quiet` drops progress lines.
136
+
137
+ Parse JSON. Never scrape human output.
138
+
139
+ ## Commands
140
+
141
+ | Command | Use it for |
142
+ | --- | --- |
143
+ | `gscdump sites` | List Google Sites and permission levels |
144
+ | `gscdump bing login`, `status`, `logout` | Manage Bing authentication and check connections |
145
+ | `gscdump bing sites` | List Bing Sites and connection details |
146
+ | `gscdump bing dump` | Export Bing traffic, pages, keywords, and crawl data |
147
+ | `gscdump bing inspect` | Read Bing Indexing Evidence for one URL |
148
+ | `gscdump bing verify` | Check and activate a cloud Bing connection |
149
+ | `gscdump sync` | Copy Search Console rows into the local Store |
150
+ | `gscdump query` | Rows by page, query, date, country, or device |
151
+ | `gscdump analyze <id>` | One Analyzer over the Store or live rows |
152
+ | `gscdump report <id>` | A Report that composes several Analyzers |
153
+ | `gscdump inspect <url>` | URL Inspection with Indexing Evidence |
154
+ | `gscdump sitemaps` | List, submit, delete, and probe sitemaps |
155
+ | `gscdump indexing` | Indexing API notifications and quota |
156
+ | `gscdump dump` | Export Store tables to Parquet, CSV, JSON, or NDJSON |
157
+ | `gscdump store` | Store stats, compaction, garbage collection, resets |
158
+ | `gscdump entities` | Snapshot URL inspections into the entity store |
159
+ | `gscdump config` | Defaults such as `defaultSite`, `dataDir`, `defaultLimit` |
160
+ | `gscdump profile` | Separate credential and config directories |
161
+ | `gscdump auth` | `status`, `login`, `logout`, `refresh` |
162
+ | `gscdump doctor` | Health checks for auth, scopes, Store, and reachability |
163
+ | `gscdump init` | Interactive first-time setup |
164
+ | `gscdump mcp` | Start Google MCP tools with the selected authentication |
165
+ | `gscdump skill install` | Copy this skill into an agent skill directory |
166
+ | `gscdump papercut` | Report a CLI problem to gscdump.com |
167
+
168
+ `gscdump login`, `gscdump logout`, and `gscdump status` are top-level aliases of
169
+ the matching `auth` subcommands.
170
+ The MCP server does not expose Bing tools. Use `gscdump bing` commands through this skill.
171
+
172
+ ## Sync before local analysis
173
+
174
+ ```sh
175
+ gscdump sync --site sc-domain:example.com --days 90 \
176
+ --tables pages,queries,page_queries,countries
177
+ gscdump sync --site sc-domain:example.com --status
178
+ ```
179
+
180
+ - Pass an explicit `--tables` list. The default list has a known daily-totals
181
+ limitation.
182
+ - `--full` backfills the 450 days Google keeps.
183
+ - Sync skips completed dates. `--force` refreshes them. `--retry-failed`
184
+ reruns only failed dates.
185
+ - `--dry-run` prints the planned work without calling Google.
186
+
187
+ ## Query rows
188
+
189
+ ```sh
190
+ gscdump query --site sc-domain:example.com --dimensions page,query \
191
+ --start 2026-08-01 --end 2026-08-28 --limit 1000 --format json
192
+ ```
193
+
194
+ - Dimension names are singular: `page`, `query`, `date`, `country`, `device`.
195
+ - Filters: `--query`, `--page`, `--country`, `--device`,
196
+ `--search-appearance`. Prefixes: bare equals, `~` contains, `!~` not
197
+ contains, `re:` regex, `!re:` not regex, `!` not equals.
198
+ - `--live` bypasses the Store. `--search-type`, `--data-state`, and
199
+ `--aggregation-type` apply to live mode only.
200
+ - `--explain` prints the request body or planned SQL without executing.
201
+ - `--sql` runs raw DuckDB SQL over the Store with `{{FILES}}` as the file list.
202
+
203
+ ## Analyze and report
204
+
205
+ ```sh
206
+ gscdump report list --json
207
+ gscdump report opportunities --site sc-domain:example.com --json
208
+ gscdump report movers --site sc-domain:example.com --period 28d --vs prev-period --json
209
+ gscdump analyze list --json
210
+ gscdump analyze striking-distance --site sc-domain:example.com --json
211
+ ```
212
+
213
+ - Report ids: `brand`, `growth`, `health`, `movers`, `opportunities`,
214
+ `pre-publish`, `risks`, `triage`.
215
+ - `--period` takes `7d`, `28d`, `90d`, `mtd`, `ytd`, or `custom` with
216
+ `--start` and `--end`. `--vs` takes `none`, `prev-period`, or `yoy`.
217
+ - `report <id> --explain` prints the plan without credentials or data.
218
+ - `triage` needs `--target <page-or-query> --target-kind page|query`.
219
+ `pre-publish` needs `--topic`. `brand` needs `--brand-terms 'a,b'`.
220
+ - Analyzers take `--start` and `--end`. `movers` and `decay` also take
221
+ `--prev-start` and `--prev-end`. `--period` and `--vs` belong to `report`.
222
+ - SQL-only Analyzers need Store rows. `--live` runs row-based Analyzers
223
+ against Google.
224
+ - Results name candidates for review. They do not prove why traffic changed.
225
+
226
+ ## Inspect and index
227
+
228
+ ```sh
229
+ gscdump inspect https://example.com/page --site sc-domain:example.com --json
230
+ gscdump inspect batch --site sc-domain:example.com --file urls.txt --json
231
+ gscdump indexing quota --json
232
+ ```
233
+
234
+ Inspection spends Google's separate 2,000 requests per Site per day quota.
235
+ `indexing quota` describes Indexing API limits. It does not report remaining URL Inspection requests.
236
+ Report the Indexing Evidence fields as Google returned them.
237
+
238
+ ## Report a papercut
239
+
240
+ If CLI behavior blocks or slows your work, report it once per distinct
241
+ problem, then continue the user's task. Report confusing output, missing
242
+ context, wrong help text, unexpected failures, and useful workarounds.
243
+
244
+ ```sh
245
+ gscdump papercut --command "report triage" --agent "Claude Code" \
246
+ --comment "Agent report by Claude Code. Expected --target-kind in --help. Received an unknown flag error. Used --explain to find the flag." \
247
+ --yes --json
248
+ ```
249
+
250
+ - Use your real agent name. Start the comment with an agent disclosure.
251
+ - Include what you ran, what you expected, what happened, and any workaround.
252
+ - `--intent improvement` marks a suggestion. The default is `bug`.
253
+ - The CLI adds its version, Node version, and platform.
254
+ - Send sanitized details only. Remove tokens, cookies, personal data, private
255
+ URLs, and customer rows. Use placeholder arguments.
256
+
257
+ Self-reporting sanitized papercuts is authorized by this skill. No separate
258
+ confirmation is needed. This permission covers papercuts only. Respect any
259
+ user instruction that forbids reporting.
260
+
261
+ The endpoint is anonymous and allows ten reports per network address each
262
+ hour. Success returns `id` and `status: "new"`. If reporting fails, mention
263
+ the failure and continue. Never retry an uncertain submission.
264
+
265
+ ## Guardrails
266
+
267
+ - **Get consent before a mutation.** `sites add`, `sites delete`,
268
+ `sites verify`, `sitemaps submit`, `sitemaps delete`, `indexing submit`,
269
+ `indexing remove`, `store reset`, and `store rm-site` change Google or
270
+ delete local data. `--yes` is consent you borrow from the user.
271
+ - **Never loop unattended.** One `sync` per Site per task. Inspection batches
272
+ spend a daily pool. Use `--dry-run` and `--explain` to plan first.
273
+ - **Report the result as the CLI gave it.** An empty result is not a clean
274
+ Site. Check `sync --status` for the covered date range before reading zero
275
+ rows as zero traffic.
276
+ - **Do not widen the Site.** A `sc-domain:` property includes every
277
+ subdomain. Filter with `--page` when the user means one host.
278
+
279
+ ## Bing exports
280
+
281
+ `bing dump` writes JSON, NDJSON, or CSV under one directory per Site.
282
+ `--datasets` selects `traffic`, `pages`, `keywords`, or `crawl`.
283
+ Local mode also supports `crawl-issues`.
284
+ Hosted exports follow pagination and reject missing, unavailable, or changing datasets.
285
+ Hosted date ranges span at most 366 days. The default range is the last 366 days.
286
+ Local date filters only narrow data currently returned by Bing.
287
+ Do not treat Bing crawl evidence as proof that a URL is indexed.