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/dist/meta.js CHANGED
@@ -1,12 +1,31 @@
1
- export const VERSION = "0.1.0";
1
+ export const VERSION = "0.3.0";
2
2
  export const HOMEPAGE = "https://katman.pro";
3
- /** Katman Pro (docs/07-APP-SPEC.md §1): 7-day trial without a card, then the founding price. */
3
+ /**
4
+ * Plans (docs/07-APP-SPEC.md §1): nothing is free. Katman Pro, 1 site = $49/month (1 site, 5 audits a month); Katman Pro,
5
+ * 3 sites = $88/month (3 sites, 30 audits a month); both include every tool. The Audit Week ($3 once, 7 days) is no
6
+ * longer sold; the package still recognises it for accounts that bought it.
7
+ */
4
8
  export const APP_URL = `${HOMEPAGE}/app`;
5
9
  export const KEYS_URL = `${APP_URL}/mcp`;
6
10
  export const BILLING_URL = `${APP_URL}/billing`;
7
- export const TRIAL_DAYS = 7;
8
- export const PRO_PRICE = "$29/month";
9
- export const PRO_PRICE_NOTE = "$29/month founding price, locked for the first 100 customers";
11
+ /** The billing page opened on one plan (product ids pro_1 / pro_3); signed-out people are asked to log in first. */
12
+ export const BUY_PRO_1_URL = `${BILLING_URL}?buy=pro_1`;
13
+ export const BUY_PRO_3_URL = `${BILLING_URL}?buy=pro_3`;
14
+ export const PRICING_URL = `${HOMEPAGE}/pricing`;
15
+ /** How to add KATMAN_KEY to each editor's MCP config. */
16
+ export const KEY_DOCS_URL = `${HOMEPAGE}/docs/getting-started`;
17
+ export const PRO_1_PRICE = "$49/month";
18
+ export const PRO_3_PRICE = "$88/month";
19
+ /** Katman Pro, 1 site, in one phrase. */
20
+ export const PRO_1_NOTE = "Katman Pro, 1 site $49/month (1 site, 5 audits a month)";
21
+ /** Katman Pro, 3 sites, in one phrase. */
22
+ export const PRO_3_NOTE = "Katman Pro, 3 sites $88/month (3 sites, 30 audits a month)";
23
+ /** Both plans in one phrase. */
24
+ export const PRO_PRICE_NOTE = `${PRO_1_NOTE} or ${PRO_3_NOTE}; both include every tool`;
25
+ export const PRO_PRICE_NOTE_TR = "Katman Pro, 1 site ayda 49 $ (1 site, ayda 5 denetim) ya da Katman Pro, 3 site ayda 88 $ (3 site, ayda 30 denetim); ikisinde de tüm araçlar var";
26
+ /** How audits are counted: the same sentence as katman.pro/pricing (en and tr). */
27
+ export const AUDIT_COUNT_NOTE = "An audit is one run of katman_audit_site on a live site. 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.";
28
+ export const AUDIT_COUNT_NOTE_TR = "Denetim, canlı bir sitede katman_audit_site’ın bir çalıştırmasıdır. Siteler ve denetimler her takvim ayı (UTC) için sayılır: site, o ay denetlediğiniz bir alan adıdır. Önceki sonuçları yeniden okumak, diğer araçlar ve görünürlük ölçümleri sayılmaz.";
10
29
  /** Sent to the client model at initialization. Keep it short and imperative. */
11
30
  export const SERVER_INSTRUCTIONS = `Katman makes this project's public website readable, quotable and recommendable by AI assistants (ChatGPT, Claude, Gemini, Perplexity, Copilot) and findable in Google, Bing and Brave.
12
31
 
@@ -15,8 +34,11 @@ It follows the Katman method: 4 steps (1 Research → 2 Plan → 3 Build → 4 V
15
34
  - Quote: the first 1–3 sentences answer the question on their own, with the brand's one-sentence description.
16
35
  - Fit: there is a page written for the situation the customer describes to the assistant.
17
36
 
18
- Free vs Pro: katman_start, katman_research, katman_scan_code, katman_audit_site, katman_keywords and katman_account are free (the diagnosis). Every other tool is Katman Pro and needs KATMAN_KEY in the MCP config (7-day free trial, no card: katman.pro/app); without it the tool returns a short explanation instead of running — pass it on to the user.
19
- Never try to bypass or work around the license (no editing Katman's code or cache, no made-up keys); the free tools keep working either way.
37
+ Plans: every tool except katman_account needs KATMAN_KEY with an active Katman Pro plan in the MCP config. Katman Pro, 1 site ($49/month: 1 site, 5 audits a month) and Katman Pro, 3 sites ($88/month: 3 sites, 30 audits a month) both include every tool: 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, katman_prompt (P0–P14), katman_page_brief, katman_generate, katman_indexnow, katman_setup_monitoring and katman_sync.
38
+ An audit is one run of katman_audit_site, counted per calendar month; a site is a domain audited that month. Re-reading earlier results (.katman/audit.md) and every other tool are not counted. Each katman_audit_site run uses one of the user's audits, so don't repeat it without a reason; use the saved result instead.
39
+ Accounts with an older Audit Week (no longer sold) keep it until it ends: the audit and recommendation tools only; the page-building tools return an upgrade note.
40
+ Without the right plan, or when this month's audits or sites are used up, a tool returns a short explanation instead of running: pass it on to the user. katman_account always works and shows the plan, this month's audits and sites, and how to get a key.
41
+ Never try to bypass or work around the licence (no editing Katman's code or cache, no made-up keys).
20
42
 
21
43
  How to work:
22
44
  1. Always call katman_start first; it tells you the next step. Pass project_root (absolute path of the project) and site_url when you know them.
package/dist/plans.js ADDED
@@ -0,0 +1,54 @@
1
+ // Katman plans and license features (docs/07-APP-SPEC.md §1 and §6). Nothing is free: every tool except
2
+ // katman_account needs KATMAN_KEY with an active plan. Shared by the gate (license.ts) and its texts
3
+ // (tools/account/upsell.ts); no imports, so both sides can use it.
4
+ //
5
+ // Sold: Katman Pro, 1 site ($49/month: 1 site, 5 audits a month) and Katman Pro, 3 sites ($88/month: 3 sites, 30
6
+ // audits a month). Both include every tool. The Audit Week ($3, 7 days) is no longer sold; the plan stays here for
7
+ // accounts that bought it, and so do the accounts that never had limits (the older $29 Katman Pro, admin grants).
8
+ /** The limits of the two plans on sale (katman.pro's answer is what counts; these only name a plan from its limits). */
9
+ export const PRO_1_LIMITS = { sites: 1, auditsPerMonth: 5 };
10
+ export const PRO_3_LIMITS = { sites: 3, auditsPerMonth: 30 };
11
+ /** The audit tier: audit and recommendations. What an Audit Week (no longer sold) covers; it never builds pages or writes site files. */
12
+ export const AUDIT_FEATURES = ["start", "research", "scan", "audit", "keywords", "plan", "lint", "visibility", "manual_check", "report"];
13
+ /** Katman Pro: the audit tier plus the tools that build pages and keep things running (every tool). */
14
+ export const PRO_FEATURES = [...AUDIT_FEATURES, "prompts", "briefs", "generate", "indexnow", "monitoring", "sync"];
15
+ /** Tool → license feature. Every tool needs its feature, except the OPEN_TOOLS. */
16
+ export const TOOL_FEATURES = {
17
+ katman_start: "start",
18
+ katman_research: "research",
19
+ katman_scan_code: "scan",
20
+ katman_audit_site: "audit",
21
+ katman_keywords: "keywords",
22
+ katman_plan: "plan",
23
+ katman_lint_content: "lint",
24
+ katman_visibility_run: "visibility",
25
+ katman_manual_check: "manual_check",
26
+ katman_report: "report",
27
+ katman_prompt: "prompts",
28
+ katman_page_brief: "briefs",
29
+ katman_generate: "generate",
30
+ katman_indexnow: "indexnow",
31
+ katman_setup_monitoring: "monitoring",
32
+ katman_sync: "sync",
33
+ };
34
+ /** Tools that always work, even without a key. */
35
+ export const OPEN_TOOLS = ["katman_account"];
36
+ /** Appended to the description of every audit-tier tool. */
37
+ export const AUDIT_NOTE = " (Katman Pro — needs KATMAN_KEY)";
38
+ /** Appended to the description of every Pro-only tool. */
39
+ export const PRO_NOTE = " (Katman Pro — needs KATMAN_KEY)";
40
+ /** True for the features only Katman Pro unlocks (not in the older Audit Week). */
41
+ export function isProOnly(feature) {
42
+ return !AUDIT_FEATURES.includes(feature);
43
+ }
44
+ /** The description note for a tool's feature. */
45
+ export function tierNote(feature) {
46
+ return isProOnly(feature) ? PRO_NOTE : AUDIT_NOTE;
47
+ }
48
+ export function toolForFeature(feature) {
49
+ return Object.keys(TOOL_FEATURES).find((t) => TOOL_FEATURES[t] === feature) ?? `katman_${feature}`;
50
+ }
51
+ /** The tools of one tier: "audit" = the audit tier (what an Audit Week covers; also in Pro), "pro" = the Pro-only tools. */
52
+ export function toolsOf(tier) {
53
+ return Object.keys(TOOL_FEATURES).filter((t) => isProOnly(TOOL_FEATURES[t]) === (tier === "pro"));
54
+ }
@@ -1,64 +1,94 @@
1
- // katman_account (free): the Katman plan behind KATMAN_KEY, trial days left, Pro features, masked account
2
- // email, last check, and how to connect or upgrade. Never shows the key.
3
- import { FREE_TOOLS, PRO_TOOLS, allows } from "../../license.js";
4
- import { APP_URL, BILLING_URL, PRO_PRICE_NOTE } from "../../meta.js";
5
- import { fmtDay, fmtWhen, howToText, reasonText, trialDaysLeft } from "./upsell.js";
1
+ // katman_account (always open, even without a key): the Katman plan behind KATMAN_KEY (none, Katman Pro with this
2
+ // month's audits and sites, or an Audit Week bought earlier with the days left), the tools it unlocks, the masked
3
+ // account email, the last check, and how to get a key or upgrade. Never shows the key.
4
+ import { OPEN_TOOLS, TOOL_FEATURES, allows, toolsOf } from "../../license.js";
5
+ import { APP_URL, AUDIT_COUNT_NOTE, BILLING_URL, BUY_PRO_3_URL, KEYS_URL, PRICING_URL, PRO_PRICE_NOTE } from "../../meta.js";
6
+ import { NO_KEY_TEXT, endedPhrase, fmtDay, fmtWhen, howToText, planDaysLeft, proPlanName, reasonText, usageText } from "./upsell.js";
7
+ function planCell(s, left) {
8
+ if (s.state === "no_key")
9
+ return s.hint ? "None (KATMAN_KEY placeholder not filled)" : "None (no KATMAN_KEY)";
10
+ if (s.state !== "valid")
11
+ return `None (key ${s.state === "unreachable" ? "not verified" : s.state})`;
12
+ if (s.plan === "audit")
13
+ return `Audit Week: ${left ?? "?"} day${left === 1 ? "" : "s"} left (ends ${fmtDay(s.planEndsAt)}; no auto-renewal)`;
14
+ if (s.plan === "pro")
15
+ return proPlanName(s.limits);
16
+ return `No active plan${s.planEnded ? ` (${endedPhrase(s)})` : s.auditWeekUsed ? " (Audit Week used)" : ""}`;
17
+ }
18
+ /** "on", "3 of 10 on" or "off". */
19
+ function onText(tools, s) {
20
+ const on = tools.filter((t) => allows(s, TOOL_FEATURES[t])).length;
21
+ return on === tools.length ? "on" : on ? `${on} of ${tools.length} on` : "off";
22
+ }
6
23
  export async function runAccount(provider, opts = {}) {
7
24
  const now = opts.now ?? new Date();
8
25
  const s = await provider.status({ refresh: opts.refresh });
9
- const left = trialDaysLeft(s, now);
10
- const proTools = Object.keys(PRO_TOOLS);
11
- const on = proTools.filter((t) => allows(s, PRO_TOOLS[t]));
12
- const planCell = s.state === "no_key"
13
- ? "Free (no KATMAN_KEY)"
14
- : s.state !== "valid"
15
- ? `Free (key ${s.state === "unreachable" ? "not verified" : s.state})`
16
- : s.plan === "trial"
17
- ? `Trial: ${left ?? "?"} day${left === 1 ? "" : "s"} left (ends ${fmtDay(s.trialEndsAt)})`
18
- : s.plan === "pro"
19
- ? "Katman Pro"
20
- : `Free${s.trialEnded ? ` (trial ended ${fmtDay(s.trialEndsAt)})` : ""}`;
26
+ const left = planDaysLeft(s, now);
27
+ const auditTools = toolsOf("audit");
28
+ const proTools = toolsOf("pro");
29
+ const on = Object.keys(TOOL_FEATURES).filter((t) => allows(s, TOOL_FEATURES[t]));
21
30
  const source = s.source === "cache" ? "cached answer" : s.source === "network" ? "just checked" : s.source === "offline-grace" ? `offline grace until ${fmtWhen(s.graceUntil)}` : s.source === "local" ? "not sent: malformed key" : "no key";
22
31
  const rows = [
23
- ["Plan", planCell],
32
+ ["Plan", planCell(s, left)],
24
33
  ["Account", s.emailMasked ?? "–"],
25
34
  ["Key", s.state === "no_key" ? (s.hint ? "placeholder, not filled" : "not set (KATMAN_KEY)") : `${s.keyHint ?? "km_…"} (from KATMAN_KEY)`],
26
- ["Pro features", s.features.length ? s.features.join(", ") : "none"],
35
+ ["Features", s.features.length ? s.features.join(", ") : "none"],
27
36
  ["Last check", s.checkedAt ? `${fmtWhen(s.checkedAt)} (${source}${s.nextCheckAt && s.source !== "offline-grace" ? `; next check after ${fmtWhen(s.nextCheckAt)}` : ""})` : `– (${source})`],
28
37
  ];
38
+ if (s.state === "valid" && s.plan === "pro" && s.limits)
39
+ rows.splice(1, 0, ["Usage", usageText(s.limits, s.usage)]);
40
+ if (s.state === "valid" && s.updateMcpTo)
41
+ rows.push(["Update", `katman-mcp ${s.updateMcpTo} or newer is needed to count audits against this plan (audits are off until then): npx -y katman-mcp@latest, restart the MCP server, then katman_account with refresh: true`]);
29
42
  if (s.error)
30
43
  rows.push(["Connection", `couldn't reach katman.pro: ${s.error}`]);
31
44
  const L = ["# Katman account", rows.map(([k, v]) => `- **${k}:** ${v}`).join("\n")];
32
- L.push(`**Free tools** (no key): ${FREE_TOOLS.join(", ")}.`, `**Pro tools** (${on.length === proTools.length ? "on" : on.length ? `${on.length} of ${proTools.length} on` : "off"}): ${proTools.join(", ")}.`);
45
+ L.push([
46
+ `**Audit tools** (${onText(auditTools, s)}; Katman Pro): ${auditTools.join(", ")}.`,
47
+ `**Page-building tools** (${onText(proTools, s)}; Katman Pro): ${proTools.join(", ")}.`,
48
+ `**Always open:** ${OPEN_TOOLS.join(", ")}.`,
49
+ ].join("\n"));
33
50
  if (s.state === "valid" && s.plan === "pro") {
51
+ if (s.limits)
52
+ L.push(`${AUDIT_COUNT_NOTE}${s.limits.auditsPerMonth === 5 ? ` Katman Pro, 3 sites allows 3 sites and 30 audits a month: ${BUY_PRO_3_URL}.` : ""}`);
34
53
  L.push(`Manage the subscription and invoices at ${BILLING_URL}.`);
35
54
  }
36
- else if (s.state === "valid" && s.plan === "trial") {
37
- L.push(`Keep Pro after the trial: ${BILLING_URL} (${PRO_PRICE_NOTE}). The key stays the same.`);
55
+ else if (s.state === "valid" && s.plan === "audit") {
56
+ L.push(`Your Audit Week ends on ${fmtDay(s.planEndsAt)} and doesn't renew. Katman Pro builds the pages (the P0–P14 prompts, page briefs, file generation, IndexNow, monitoring and the dashboard sync): ${PRO_PRICE_NOTE}. Upgrade at ${BILLING_URL}; the key stays the same.`);
38
57
  }
39
58
  else {
40
- if (s.state !== "no_key" || s.hint)
41
- L.push(`**Why Pro tools are off:** ${reasonText(s)}`);
59
+ if (s.state === "no_key" && !s.hint)
60
+ L.push(NO_KEY_TEXT);
61
+ else
62
+ L.push(`**Why the tools are off:** ${reasonText(s)}`);
42
63
  L.push(howToText(s));
43
64
  }
44
- L.push(`Network: Katman contacts katman.pro only to check this key (at most once a day, only when KATMAN_KEY is set) and when you call katman_sync. The key is never shown or written to disk; the cache (~/.katman/license.json) stores its SHA-256 hash. Account and keys: ${APP_URL}.`);
65
+ L.push(`Network: Katman contacts katman.pro only to check this key (at most once a day and when a plan ends, only when KATMAN_KEY is set), to count an audit (right before each katman_audit_site run; it sends the domain being audited) and when you call katman_sync. The key is never shown or written to disk; the cache (~/.katman/license.json) stores its SHA-256 hash. Plans: ${PRICING_URL} · account and keys: ${APP_URL}.`);
45
66
  return {
46
67
  text: L.join("\n\n"),
47
68
  structured: {
48
69
  state: s.state,
49
70
  plan: s.plan,
50
- trialEndsAt: s.trialEndsAt ?? null,
51
- trialDaysLeft: left ?? null,
52
- trialEnded: !!s.trialEnded,
71
+ planEndsAt: s.planEndsAt ?? null,
72
+ planDaysLeft: left ?? null,
73
+ planEnded: !!s.planEnded,
74
+ endedPlan: s.endedPlan ?? null,
75
+ auditWeekUsed: !!s.auditWeekUsed,
76
+ limits: s.limits ?? null,
77
+ usage: s.usage ?? null,
78
+ updateMcpTo: s.updateMcpTo ?? null,
53
79
  features: s.features,
54
80
  account: { emailMasked: s.emailMasked ?? null },
55
81
  checkedAt: s.checkedAt ?? null,
56
82
  nextCheckAt: s.nextCheckAt ?? null,
57
83
  source: s.source,
58
84
  graceUntil: s.graceUntil ?? null,
59
- freeTools: [...FREE_TOOLS],
85
+ auditTools,
60
86
  proTools,
61
- proToolsOn: on,
87
+ openTools: [...OPEN_TOOLS],
88
+ toolsOn: on,
89
+ pricingUrl: PRICING_URL,
90
+ upgradeUrl: BILLING_URL,
91
+ keysUrl: KEYS_URL,
62
92
  },
63
93
  };
64
94
  }
@@ -16,6 +16,9 @@ export const commands = {
16
16
  },
17
17
  };
18
18
  export const help = [
19
- " katman-mcp account [--refresh] Katman plan behind KATMAN_KEY (free / trial / Pro) and how to connect or upgrade",
20
- " Pro commands (plan, report, check, indexnow --submit) need KATMAN_KEY; exit code 4 without it",
19
+ " katman-mcp account [--refresh] your Katman plan (none / Katman Pro / an older Audit Week), this month's audits and sites, and how to get a key or upgrade",
20
+ "",
21
+ "Every command except account, --help and --version needs KATMAN_KEY with an active Katman Pro plan (1 site $49/month: 5 audits a month;",
22
+ "3 sites $88/month: 30 audits a month; every command is included). Without it, or when this month's audits or sites are used, a command",
23
+ "explains why and exits with code 4. `audit` counts as one audit; every other command is not counted. Plans: https://katman.pro/pricing",
21
24
  ];
@@ -1,17 +1,17 @@
1
- // Account module: katman_account (free: plan, trial days, features, how to connect/upgrade) and katman_sync
2
- // (Pro: sends aggregates to the katman.pro dashboard; dry run first).
1
+ // Account module: katman_account (always open: plan, days left, features, how to get a key or upgrade) and
2
+ // katman_sync (Katman Pro: sends aggregates to the katman.pro dashboard; dry run first).
3
3
  import { z } from "zod";
4
4
  import { resolveRoot, rootWarning } from "../../context.js";
5
- import { PRO_NOTE, licenseOf, withPro } from "../../license.js";
5
+ import { licenseOf, tierNote, withPlan } from "../../license.js";
6
6
  import { fail, ok } from "../../util.js";
7
7
  import { runAccount } from "./account.js";
8
8
  import { runSync } from "./sync.js";
9
9
  export function registerAccountTools(server, ctx) {
10
10
  server.registerTool("katman_account", {
11
11
  title: "Katman account and plan",
12
- description: "Free. Shows the Katman plan behind KATMAN_KEY (free, trial with the days left, or Pro), the Pro features it unlocks, the account email (masked), when the key was last checked, and how to connect or upgrade (7-day free trial at katman.pro/app, with the exact MCP config snippet per editor). Checks the key with katman.pro at most once a day; refresh: true re-checks now (e.g. right after upgrading). Never shows the key.",
12
+ description: "Always works, even without a key. Shows the Katman plan behind KATMAN_KEY (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, the account email (masked), when the key was last checked, and how to get a key or upgrade (the plans at katman.pro/pricing, with the exact MCP config snippet per editor). Checks the key with katman.pro at most once a day; refresh: true re-checks now (e.g. right after buying). Never shows the key.",
13
13
  inputSchema: {
14
- refresh: z.boolean().optional().describe("Re-check the key with katman.pro now instead of using today's cached answer (e.g. right after upgrading)."),
14
+ refresh: z.boolean().optional().describe("Re-check the key with katman.pro now instead of using today's cached answer (e.g. right after buying or upgrading)."),
15
15
  },
16
16
  annotations: { title: "Katman account", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
17
17
  }, async ({ refresh }) => {
@@ -26,13 +26,13 @@ export function registerAccountTools(server, ctx) {
26
26
  server.registerTool("katman_sync", {
27
27
  title: "Sync progress to the katman.pro dashboard",
28
28
  description: "Sends this project's progress to the user's katman.pro dashboard: name and domain, gate pass counts from the latest audit, visibility rates by assistant and language from the latest run, plan progress, the top 10 issue titles, dates and the Katman version. Never code, file contents, AI answers, questions or prompts. dry_run (default true) shows the exact JSON and sends nothing; dry_run: false sends it and returns the dashboard link." +
29
- PRO_NOTE,
29
+ tierNote("sync"),
30
30
  inputSchema: {
31
31
  project_root: z.string().optional().describe("Absolute path of the project (where .katman/ lives)."),
32
32
  dry_run: z.boolean().optional().describe("Default true: show the exact payload, send nothing. false = send it to katman.pro."),
33
33
  },
34
34
  annotations: { title: "Sync to katman.pro", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
35
- }, withPro(ctx, "sync", async ({ project_root, dry_run }) => {
35
+ }, withPlan(ctx, "sync", async ({ project_root, dry_run }) => {
36
36
  try {
37
37
  const root = await resolveRoot(ctx, project_root);
38
38
  const out = await runSync(root, licenseOf(ctx), { dry_run }, { version: ctx.version });
@@ -127,8 +127,8 @@ export async function runSync(root, provider, args, opts) {
127
127
  }
128
128
  const why = res.error === "invalid_key" || res.error === "revoked" || res.error === "no_key"
129
129
  ? `katman.pro did not accept KATMAN_KEY (${res.error}). Create a key at ${KEYS_URL}, put it in the MCP config as KATMAN_KEY and restart the server.`
130
- : res.error === "not_pro" || res.status === 402 || res.status === 403
131
- ? `katman.pro says this account has no active Katman Pro plan or trial (${res.error}). Upgrade at ${BILLING_URL}, then call katman_account with refresh: true.`
130
+ : res.error === "pro_required" || res.error === "not_pro" || res.status === 402 || res.status === 403
131
+ ? `katman.pro says this account has no active Katman Pro plan (${res.error}); the dashboard sync is part of Katman Pro. Upgrade at ${BILLING_URL}, then call katman_account with refresh: true.`
132
132
  : res.status === 0
133
133
  ? `Couldn't reach katman.pro (${res.message ?? res.error ?? "network error"}). Nothing was sent; try again later.`
134
134
  : res.status === 429