katman-mcp 0.1.0 → 0.3.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 (43) hide show
  1. package/README.md +56 -44
  2. package/dist/cli.js +27 -14
  3. package/dist/license.js +331 -98
  4. package/dist/meta.js +29 -7
  5. package/dist/plans.js +54 -0
  6. package/dist/tools/account/account.js +60 -30
  7. package/dist/tools/account/cli.js +5 -2
  8. package/dist/tools/account/index.js +7 -7
  9. package/dist/tools/account/sync.js +2 -2
  10. package/dist/tools/account/upsell.js +423 -118
  11. package/dist/tools/crawl/audit/report.js +2 -2
  12. package/dist/tools/crawl/cli.js +17 -5
  13. package/dist/tools/crawl/index.js +52 -18
  14. package/dist/tools/crawl/scan/framework.js +4 -1
  15. package/dist/tools/method/core/lint.js +15 -1
  16. package/dist/tools/method/core/prompt.js +2 -1
  17. package/dist/tools/method/core/start.js +1 -1
  18. package/dist/tools/method/data/_store.js +17 -0
  19. package/dist/tools/method/data/anatomy.js +12 -141
  20. package/dist/tools/method/data/appendices.js +22 -202
  21. package/dist/tools/method/data/cloudflare.js +28 -192
  22. package/dist/tools/method/data/evidence.js +18 -137
  23. package/dist/tools/method/data/geo-jobs.js +8 -128
  24. package/dist/tools/method/data/landing.js +14 -67
  25. package/dist/tools/method/data/lessons.js +16 -127
  26. package/dist/tools/method/data/measurement.js +38 -142
  27. package/dist/tools/method/data/offsite.js +16 -148
  28. package/dist/tools/method/data/pages.js +16 -167
  29. package/dist/tools/method/data/prompts.js +8 -633
  30. package/dist/tools/method/data/publish.js +14 -113
  31. package/dist/tools/method/data/research.js +14 -131
  32. package/dist/tools/method/data/roadmap.js +12 -105
  33. package/dist/tools/method/data/traps.js +6 -74
  34. package/dist/tools/method/data/verify.js +12 -88
  35. package/dist/tools/method/data/viral-list.js +12 -39
  36. package/dist/tools/method/index.js +27 -17
  37. package/dist/tools/method/lib/prompt-lookup.js +18 -0
  38. package/dist/tools/method/mcp/prompts.js +6 -6
  39. package/dist/tools/method/mcp/resources.js +21 -17
  40. package/dist/tools/visibility/index.js +10 -10
  41. package/dist/tools/visibility/monitoring.js +6 -3
  42. package/package.json +5 -3
  43. package/server.json +4 -4
package/README.md CHANGED
@@ -11,13 +11,22 @@ Katman is an MCP server that works inside your AI coding tool (Cursor, Claude Co
11
11
 
12
12
  ## Pricing
13
13
 
14
- | Plan | Price | What you get |
14
+ Katman needs a licence key (`KATMAN_KEY`) with an active plan. Every tool except `katman_account` needs it. Katman Pro comes in two sizes, monthly, and both include every tool:
15
+
16
+ | Plan | Price | Each calendar month |
15
17
  |---|---|---|
16
- | **Free** | $0, no account, no key | The diagnosis: `katman_start`, `katman_research`, `katman_scan_code`, `katman_audit_site`, `katman_keywords`, `katman_account`. Katman shows what keeps assistants from reading, quoting and recommending your site. |
17
- | **7-day trial** | $0, no card | Everything in Katman Pro. Starts when you create your account at https://katman.pro/app. |
18
- | **Katman Pro** | **$29/month founding price** (first 100 customers, locked in) | The treatment: the plan, prompts P0–P14 with acceptance checks, page briefs, generators, content lint, AI-visibility runs, manual checks, IndexNow, reports, monitoring and the katman.pro dashboard sync. |
18
+ | **Katman Pro, 1 site** | **$49/month** | 1 site, 5 audits |
19
+ | **Katman Pro, 3 sites** | **$88/month** | 3 sites, 30 audits |
20
+
21
+ Every tool is in both plans, and so is the full course and the private community: `katman_start`, `katman_research`, `katman_scan_code`, `katman_audit_site`, `katman_keywords`, `katman_plan`, `katman_lint_content`, `katman_visibility_run`, `katman_manual_check`, `katman_report`, the prompts P0–P14 with acceptance checks (`katman_prompt` and the `katman://prompts/*` resources), `katman_page_brief`, `katman_generate`, `katman_indexnow`, `katman_setup_monitoring` and the katman.pro dashboard sync (`katman_sync`).
22
+
23
+ **What counts.** An audit is one run of `katman_audit_site` on a live site (or the CLI `audit`). Sites and audits are counted per calendar month (UTC): a site is a domain you audited that month. Re-reading earlier results, the other tools and visibility runs are not counted. Counts start again on the 1st. When the month's audits or sites are used up, `katman_audit_site` says so, shows when the counts start again and does not run; every other tool keeps working. `katman_account` shows what you have used this month.
19
24
 
20
- Pro tools need `KATMAN_KEY` in your MCP config: sign in at https://katman.pro/app → **MCP → Create key**. Without a key, a Pro tool tells you what it would do for your project and how to start the trial, instead of running. `katman_account` shows your plan at any time.
25
+ Choose a plan at https://katman.pro/pricing, then sign in at https://katman.pro/app → **MCP → Create key** and add the key to your MCP config (below). Without a key, or without an active plan, a tool tells you what it would do for your project and how to get the plan, instead of running. `katman_account` always works and shows your plan, this month's audits and sites, and how to upgrade.
26
+
27
+ Accounts that bought an older plan keep what they bought: an Audit Week (no longer sold) until it ends, with the audit and recommendation tools, and an earlier Katman Pro subscription as it was, without these monthly limits.
28
+
29
+ The Katman book and workbook PDFs are sold separately at https://katman.pro/guide; the MCP plans don't include them.
21
30
 
22
31
  ---
23
32
 
@@ -31,20 +40,20 @@ AI assistants recommend a site only when three gates are open:
31
40
  | **Quote** | The first 1–3 sentences answer the question on their own, with the same one sentence everywhere | Pages that open with "Welcome to…", llms.txt contradicting the pricing page |
32
41
  | **Fit** | There's a page for the situation the customer describes to the assistant | Pages named after the product instead of the customer's problem |
33
42
 
34
- Our own sample site, an AI-powered consumer web app we launched on 21 September 2026, went through these gates in its first week. It got **333 real ChatGPT visitors in 7 days**, and **11 of its 17 paying customers** came from ChatGPT. Source: the site's own analytics, human sessions only. The site is our own product, not a client. The full story is at https://katman.pro/case-studies/sample-site-first-7-days.
43
+ Our own sample site, an AI-powered consumer web app we launched on 21 September 2026, went through these gates in its first week. It got **333 real ChatGPT visitors in 7 days**, and **11 of its 17 paying customers** came from ChatGPT (the site's own analytics, human sessions only, 21–27 September 2026). By 1 October 2026, **503 distinct visitors** had come from ChatGPT, about 416 after removing bots, with 40–90 a day since 23 September. The site is our own product, not a client. The full story is at https://katman.pro/case-studies/sample-site-first-7-days.
35
44
 
36
45
  ## Install
37
46
 
38
- Katman runs locally with `npx`. Both keys are optional:
47
+ Katman runs locally with `npx`. It reads two keys from its environment:
39
48
 
40
- - `KATMAN_KEY` (`km_live_…`) unlocks the Pro tools. Get it at https://katman.pro/app → **MCP → Create key** (7-day free trial, no card). The free tools work without it.
41
- - `OPENROUTER_API_KEY` is only for AI-visibility runs through APIs, paid with your own OpenRouter credits.
49
+ - `KATMAN_KEY` (`km_live_…`), **required**: your licence key. Get it at https://katman.pro/app → **MCP → Create key** once you have a plan (https://katman.pro/pricing). Step by step for each editor: https://katman.pro/docs/getting-started.
50
+ - `OPENROUTER_API_KEY`, optional: only for AI-visibility runs through APIs, paid with your own OpenRouter credits.
42
51
 
43
52
  **Claude Code**
44
53
  ```bash
45
54
  claude mcp add katman --scope user -e KATMAN_KEY=km_live_... -e OPENROUTER_API_KEY=sk-or-... -- npx -y katman-mcp
46
55
  ```
47
- Already added without a key? Run `claude mcp remove katman --scope user` first. With the Katman Claude Code plugin, set its `katman_key` and `openrouter_api_key` options instead.
56
+ Already added without a key? Run `claude mcp remove katman --scope user` first. With the Katman Claude Code plugin, set its `katman_key` and `openrouter_api_key` options instead (`/plugin configure katman@katman`).
48
57
 
49
58
  **Cursor**: add this to `~/.cursor/mcp.json` (your user file, so the key never lands in a repository), or use the "Add to Cursor" button on https://katman.pro/mcp.
50
59
  ```json
@@ -55,7 +64,7 @@ Already added without a key? Run `claude mcp remove katman --scope user` first.
55
64
  ```json
56
65
  {
57
66
  "inputs": [
58
- { "type": "promptString", "id": "katman_key", "description": "Katman key from katman.pro/app (optional)", "password": true },
67
+ { "type": "promptString", "id": "katman_key", "description": "Katman key from katman.pro/app/mcp", "password": true },
59
68
  { "type": "promptString", "id": "openrouter_api_key", "description": "OpenRouter API key (optional)", "password": true }
60
69
  ],
61
70
  "servers": { "katman": { "type": "stdio", "command": "npx", "args": ["-y", "katman-mcp"], "env": { "KATMAN_KEY": "${input:katman_key}", "OPENROUTER_API_KEY": "${input:openrouter_api_key}" } } }
@@ -82,7 +91,7 @@ Open your project in your editor and tell your AI:
82
91
 
83
92
  > Use Katman to make this site recommendable by ChatGPT. Start with katman_start.
84
93
 
85
- Katman then walks your agent through four steps. Step 1 and the diagnosis in step 2 (scan and audit) are free; the rest is Katman Pro:
94
+ Katman then walks your agent through four steps:
86
95
 
87
96
  1. **Research** (`katman_research`): your one sentence (what the customer brings, what you do, what they get, which fear is unnecessary), a not-X note, 10–12 customer situations written without your brand name, competitors (with source and date), proof and a question set.
88
97
  2. **Plan** (`katman_scan_code`, `katman_audit_site`, `katman_plan`): a report of what's broken, with no code changes. Then a page plan and a task list ordered like a 30-day plan.
@@ -93,40 +102,42 @@ Measure every 14 days with `katman_visibility_run` (API) or `katman_manual_check
93
102
 
94
103
  ## Tools
95
104
 
105
+ Every tool is in both Katman Pro plans. Only `katman_audit_site` is counted: each run uses one audit of the month.
106
+
96
107
  | Tool | Plan | What it does | Writes |
97
108
  |---|---|---|---|
98
- | `katman_start` | Free | Shows where you are in the method and the exact next call (plus a one-line plan status when `KATMAN_KEY` is set) | `config.json` (site URL) |
99
- | `katman_research` | Free | Research template, merge and validation, 12+2 question set | `research.json`, `research.md` |
100
- | `katman_keywords` | Free | Google autocomplete expansion into situation and single-question page ideas (≤40 throttled requests) | `research.json` (optional) |
101
- | `katman_scan_code` | Free | Framework, rendering (SSR/SSG/CSR), routes, head tags, robots/sitemap/llms.txt, JSON-LD, links, images, analytics | `scan.json` |
102
- | `katman_audit_site` | Free | Live audit as AI crawlers see it: bot access through your CDN, JS-off text, 404s, canonicals, sitemap, hreflang, JSON-LD, internal links | `audits/`, `audit.md` |
103
- | `katman_account` | Free | Your plan (free, trial days left, Pro), features, masked account email, last key check, how to connect or upgrade | — |
104
- | `katman_plan` | Pro | Page plan and task list with P-codes and acceptance criteria (keeps your checkboxes) | `plan.json`, `plan.md` |
105
- | `katman_prompt` | Pro | Prompt P0–P14 filled with your data, plus Accept / Why / How Katman verifies | — |
106
- | `katman_page_brief` | Pro | Brief for a situation, comparison, pricing, FAQ or about page, and where the file goes in your framework | — |
107
- | `katman_generate` | Pro | robots.txt, llms.txt, Organization/WebSite/SoftwareApplication/FAQ/Breadcrumb JSON-LD, AI-channel analytics snippet, server-side bot counter, IndexNow key | only with `write: true`, never overwrites without `overwrite: true` |
108
- | `katman_lint_content` | Pro | Checks a page against the content rules: answer-first, same one sentence, no hype, sourced numbers, FAQ, not-for, links | — |
109
- | `katman_visibility_run` | Pro | Asks your question set to ChatGPT, Claude, Gemini, Perplexity and Grok models with live web search via OpenRouter (API answers are a proxy for the consumer apps). Dry run and cost estimate first; presets economy/full/probe; `samples` for stability | `runs/`, `measurements.md` |
110
- | `katman_manual_check` | Pro | Records an answer you paste from a consumer app (logged out, search on); no API cost | `runs/`, `measurements.md` |
111
- | `katman_indexnow` | Pro | Submits only new or changed URLs to IndexNow, plus a Search Console / Bing / Brave checklist | `indexnow.json` |
112
- | `katman_setup_monitoring` | Pro | GitHub Actions workflow that re-measures weekly with your own keys | `.github/workflows/katman.yml` only with `write: true` |
113
- | `katman_report` | Pro | Shareable report: gates, visibility deltas, competitors, cited domains, next 7 days | `report.md` |
114
- | `katman_sync` | Pro | Sends your progress to your katman.pro dashboard: gate pass counts, visibility rates by assistant and language, plan progress, top 10 issue titles, dates, Katman version. Never code, file contents, answers, questions or prompts. Dry run (the exact JSON) by default | — |
115
-
116
- Slash-command prompts: `katman-start`, `katman-audit`, `katman-situation-page`, `katman-measure`.
109
+ | `katman_account` | Always | Your plan (none, Katman Pro 1 site or 3 sites with this month's audits and sites used, or an older Audit Week with the days left), the tools it unlocks, masked account email, last key check, how to get a key or upgrade. Works without a key | — |
110
+ | `katman_start` | Katman Pro | Shows where you are in the method and the exact next call, with a one-line plan status. Without a plan: what Katman does, the two plans and how to set the key | `config.json` (site URL) |
111
+ | `katman_research` | Katman Pro | Research template, merge and validation, 12+2 question set | `research.json`, `research.md` |
112
+ | `katman_keywords` | Katman Pro | Google autocomplete expansion into situation and single-question page ideas (≤40 throttled requests) | `research.json` (optional) |
113
+ | `katman_scan_code` | Katman Pro | Framework, rendering (SSR/SSG/CSR), routes, head tags, robots/sitemap/llms.txt, JSON-LD, links, images, analytics | `scan.json` |
114
+ | `katman_audit_site` | Katman Pro | Live audit as AI crawlers see it: bot access through your CDN, JS-off text, 404s, canonicals, sitemap, hreflang, JSON-LD, internal links. Counted: one run = one audit of the month. Re-read the last result in `audit.md` for free | `audits/`, `audit.md` |
115
+ | `katman_plan` | Katman Pro | Page plan and task list with P-codes and acceptance criteria (keeps your checkboxes) | `plan.json`, `plan.md` |
116
+ | `katman_lint_content` | Katman Pro | Checks a page against the content rules: answer-first, same one sentence, no hype, sourced numbers, FAQ, not-for, links | — |
117
+ | `katman_visibility_run` | Katman Pro | Asks your question set to ChatGPT, Claude, Gemini, Perplexity and Grok models with live web search via OpenRouter and your own key (API answers are a proxy for the consumer apps). Dry run and cost estimate first; presets economy/full/probe; `samples` for stability | `runs/`, `measurements.md` |
118
+ | `katman_manual_check` | Katman Pro | Records an answer you paste from a consumer app (logged out, search on); no API cost | `runs/`, `measurements.md` |
119
+ | `katman_report` | Katman Pro | Shareable report: gates, visibility deltas, competitors, cited domains, next 7 days | `report.md` |
120
+ | `katman_prompt` | Katman Pro | Prompt P0–P14 filled with your data, plus Accept / Why / How Katman verifies | — |
121
+ | `katman_page_brief` | Katman Pro | Brief for a situation, comparison, pricing, FAQ or about page, and where the file goes in your framework | — |
122
+ | `katman_generate` | Katman Pro | robots.txt, llms.txt, Organization/WebSite/SoftwareApplication/FAQ/Breadcrumb JSON-LD, AI-channel analytics snippet, server-side bot counter, IndexNow key | only with `write: true`, never overwrites without `overwrite: true` |
123
+ | `katman_indexnow` | Katman Pro | Submits only new or changed URLs to IndexNow, plus a Search Console / Bing / Brave checklist | `indexnow.json` |
124
+ | `katman_setup_monitoring` | Katman Pro | GitHub Actions workflow that re-measures weekly with your own keys | `.github/workflows/katman.yml` only with `write: true` |
125
+ | `katman_sync` | Katman Pro | Sends your progress to your katman.pro dashboard: gate pass counts, visibility rates by assistant and language, plan progress, top 10 issue titles, dates, Katman version. Never code, file contents, answers, questions or prompts. Dry run (the exact JSON) by default | — |
126
+
127
+ Slash-command prompts: `katman-start`, `katman-audit`, `katman-situation-page`, `katman-measure` (each tool they call checks the plan). Resources: the method, the checklists and the content rules, this project's `research.md` and the raw prompts `katman://prompts/P0`…`P14`.
117
128
 
118
129
  ## What Katman can and can't do
119
130
 
120
131
  - **Reads** files in your project, but skips `node_modules`, `.git` and build output, and **never** reads `.env*`, `.dev.vars*`, keys, certificates or credential files.
121
132
  - **Writes** only to `.katman/` in your project, except `katman_generate` and `katman_setup_monitoring` when you pass `write: true`.
122
- - **Network**: your own site (audits), `openrouter.ai` (visibility runs, with your key, after a dry run), `api.indexnow.org` (only when you submit), `suggestqueries.google.com` (only `katman_keywords`), and `katman.pro` only for two things: checking your `KATMAN_KEY` (at most once a day, only when the key is set) and `katman_sync` (only with `dry_run: false`). **No telemetry**: without a key, nothing is sent to Katman; the key check sends only the key and the Katman version.
123
- - **Your keys** (`KATMAN_KEY`, `OPENROUTER_API_KEY`) are read from the environment and are never printed or written to disk. The license check is cached in `~/.katman/license.json` under the key's SHA-256 hash (never the key); if katman.pro can't be reached, Pro keeps working for 7 days after the last successful check.
133
+ - **Network**: your own site (audits), `openrouter.ai` (visibility runs, with your key, after a dry run), `api.indexnow.org` (only when you submit), `suggestqueries.google.com` (only `katman_keywords`), and `katman.pro` only for four things: checking your `KATMAN_KEY` (at most once a day, and again when a plan ends; only when the key is set), loading Katman's method (the prompts, page briefs and checklists; once per session, before the first tool your plan includes; it sends the key and the Katman version, and the method stays in memory, never on disk), counting an audit (right before each `katman_audit_site` run or CLI `audit`: it sends the key, the domain being audited and the Katman version, and nothing else) and `katman_sync` (only with `dry_run: false`). **No telemetry**: without a key, nothing is sent to Katman; the key check sends only the key and the Katman version. If katman.pro can't be reached when an audit is about to be counted, the audit runs anyway and its result says the count wasn't checked. The method itself needs katman.pro once per session: if it can't be reached then, the tool says so and you can try again.
134
+ - **Your keys** (`KATMAN_KEY`, `OPENROUTER_API_KEY`) are read from the environment and are never printed or written to disk. The licence check is cached in `~/.katman/license.json` under the key's SHA-256 hash (never the key); if katman.pro can't be reached, your plan keeps working for 7 days after the last successful check, never past the end of an older Audit Week.
124
135
  - **No automation of consumer chat apps.** Katman doesn't drive chatgpt.com, claude.ai or perplexity.ai with a headless browser: their terms forbid programmatic extraction, and it gets accounts banned. It uses the providers' own web-search models through OpenRouter. For the consumer apps, you paste answers into `katman_manual_check`.
125
136
  - **No ranking guarantees.** A single measurement run is a small sample, so re-run the same questions every 14 days.
126
137
 
127
138
  ## Costs
128
139
 
129
- Katman itself: the diagnosis is free; Katman Pro is $29/month (founding price) after a 7-day free trial. On top of that, API visibility runs use your own OpenRouter credits; search results are billed as input tokens, so they're not pennies:
140
+ Katman itself: Katman Pro, 1 site is $49/month and Katman Pro, 3 sites is $88/month. On top of that, API visibility runs use your own OpenRouter credits (the same with either plan, and not counted as audits); search results are billed as input tokens, so they're not pennies:
130
141
 
131
142
  | Panel | What | Typical cost per run (14 questions) |
132
143
  |---|---|---|
@@ -139,21 +150,22 @@ The exact estimate is shown before anything runs, and `max_cost_usd` (default $3
139
150
  ## CLI
140
151
 
141
152
  ```bash
142
- npx -y katman-mcp scan [path] # free
143
- npx -y katman-mcp audit https://your.site --max 50 # free
144
- npx -y katman-mcp keywords "invoice software" --lang en # free
145
- npx -y katman-mcp account [--refresh] # free: your plan
146
- npx -y katman-mcp indexnow --root . [--submit] # dry run free; --submit is Pro
147
- npx -y katman-mcp check --root . [--yes] [--max-cost 2] # Pro: visibility run; dry run without --yes
148
- npx -y katman-mcp plan --root . # Pro
149
- npx -y katman-mcp report --root . # Pro
153
+ npx -y katman-mcp account [--refresh] # always: your plan, this month's audits and sites, how to get a key
154
+ npx -y katman-mcp scan [path]
155
+ npx -y katman-mcp audit https://your.site --max 50 # counted: one run = one audit of the month
156
+ npx -y katman-mcp keywords "invoice software" --lang en
157
+ npx -y katman-mcp check --root . [--yes] [--max-cost 2] # visibility run; dry run without --yes
158
+ npx -y katman-mcp models # the default visibility models and prices
159
+ npx -y katman-mcp plan --root .
160
+ npx -y katman-mcp report --root .
161
+ npx -y katman-mcp indexnow --root . [--submit]
150
162
  ```
151
163
 
152
- Pro commands read `KATMAN_KEY` from the environment (`KATMAN_KEY=km_live_... npx -y katman-mcp report --root .`; in GitHub Actions, a repository secret) and exit with code 4 and a short explanation without it.
164
+ Every command except `account`, `--help` and `--version` reads `KATMAN_KEY` from the environment (`KATMAN_KEY=km_live_... npx -y katman-mcp report --root .`; in GitHub Actions, a repository secret) and, without an active plan (or when `audit` finds the month's audits or sites used up), exits with code 4 and a short explanation. A scheduled `audit` (a CI job, the workflow from `katman_setup_monitoring`) uses one audit per run: weekly is 4–5 a month.
153
165
 
154
166
  ## Files
155
167
 
156
- Everything Katman learns about your project lives in `.katman/`: `research.json`/`.md`, `scan.json`, `audits/`, `runs/`, `measurements.md`, `plan.md`, `report.md`, `log.md`. It contains no secrets, and it's worth committing, because it's the history of what you changed and what happened. The only file outside the project is the license cache `~/.katman/license.json` (key hash, plan, last check).
168
+ Everything Katman learns about your project lives in `.katman/`: `research.json`/`.md`, `scan.json`, `audits/`, `runs/`, `measurements.md`, `plan.md`, `report.md`, `log.md`. It contains no secrets, and it's worth committing, because it's the history of what you changed and what happened. The only file outside the project is the licence cache `~/.katman/license.json` (key hash, plan, plan end, last check).
157
169
 
158
170
  ---
159
171
 
package/dist/cli.js CHANGED
@@ -5,35 +5,48 @@ import * as method from "./tools/method/cli.js";
5
5
  import * as crawl from "./tools/crawl/cli.js";
6
6
  import * as visibility from "./tools/visibility/cli.js";
7
7
  import * as account from "./tools/account/cli.js";
8
- import { EXIT_NEEDS_PRO, cliFeature, defaultLicense, requirePro, toolForFeature } from "./license.js";
8
+ import { EXIT_NEEDS_PLAN, OPEN_COMMANDS, cliFeature, defaultLicense, requireFeature, toolForFeature } from "./license.js";
9
9
  import { projectFacts, renderUpsell } from "./tools/account/upsell.js";
10
+ /** Every CLI command by name (built on call: the module CLIs import this file). */
11
+ export function cliCommands() {
12
+ return { ...method.commands, ...crawl.commands, ...visibility.commands, ...account.commands };
13
+ }
10
14
  export async function runCli(args, deps = {}) {
11
15
  const [cmd, ...rest] = args;
12
16
  if (cmd === "--version" || cmd === "-v" || cmd === "version") {
13
17
  console.log(VERSION);
14
18
  return 0;
15
19
  }
16
- const all = { ...method.commands, ...crawl.commands, ...visibility.commands, ...account.commands };
17
- const fn = all[cmd];
18
- if (!fn) {
20
+ const all = cliCommands();
21
+ const fn = cmd !== undefined && Object.hasOwn(all, cmd) ? all[cmd] : undefined;
22
+ // --help anywhere only prints the help: it never runs a command, so it can't get past the gate.
23
+ if (!fn || rest.includes("--help") || rest.includes("-h")) {
19
24
  printHelp();
20
- return cmd === "help" || cmd === "--help" || cmd === "-h" ? 0 : 1;
25
+ return fn || cmd === "help" || cmd === "--help" || cmd === "-h" ? 0 : 1;
21
26
  }
22
- // Katman Pro commands (plan, report, check, indexnow --submit): same gate as the MCP tools.
23
- const feature = cliFeature(cmd, rest);
24
- if (feature) {
25
- const gate = await requirePro(feature, deps.license ?? defaultLicense());
27
+ // Every command except account needs a plan with its feature: the same gate as the MCP tools.
28
+ if (!OPEN_COMMANDS.includes(cmd)) {
29
+ const feature = cliFeature(cmd);
30
+ if (!feature) {
31
+ console.error(`katman-mcp ${cmd}: no licence rule for this command.`);
32
+ return EXIT_NEEDS_PLAN;
33
+ }
34
+ const gate = await requireFeature(feature, deps.license ?? defaultLicense());
26
35
  if (!gate.allowed) {
27
36
  const { _, flags } = parseArgs(rest);
28
- const root = path.resolve(typeof flags.root === "string" ? flags.root : cmd === "plan" || cmd === "report" ? (_[0] ?? process.cwd()) : process.cwd());
29
- const facts = await projectFacts(root).catch(() => undefined);
30
- const command = `katman-mcp ${cmd}${cmd === "indexnow" ? " --submit" : ""}`;
31
- console.error(renderUpsell({ tool: toolForFeature(feature), feature, status: gate.status, facts, surface: "cli", command }));
32
- return EXIT_NEEDS_PRO;
37
+ const rootArg = typeof flags.root === "string" ? flags.root : cmd === "scan" || cmd === "plan" || cmd === "report" ? _[0] : undefined;
38
+ const facts = await projectFacts(path.resolve(rootArg ?? process.cwd())).catch(() => undefined);
39
+ const example = ["katman-mcp", cmd, ...rest].map(shellWord).join(" ");
40
+ console.error(renderUpsell({ tool: toolForFeature(feature), feature, status: gate.status, facts, surface: "cli", command: `katman-mcp ${cmd}`, example }));
41
+ return EXIT_NEEDS_PLAN;
33
42
  }
34
43
  }
35
44
  return fn(rest, deps);
36
45
  }
46
+ /** Quote an argument for the "run it again with the key" example when the shell would split or expand it. */
47
+ function shellWord(a) {
48
+ return /^[\w./:@%+,=-]+$/.test(a) ? a : `'${a.replace(/'/g, `'\\''`)}'`;
49
+ }
37
50
  function printHelp() {
38
51
  const lines = [
39
52
  `katman-mcp ${VERSION} — make your site readable, quotable and recommendable by AI assistants`,