@anysiteio/agent-skills 1.4.0 → 2.0.1

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 (37) hide show
  1. package/.claude-plugin/marketplace.json +49 -1
  2. package/.claude-plugin/plugin.json +5 -1
  3. package/README.md +27 -33
  4. package/bin/install.js +196 -135
  5. package/bundles.json +19 -0
  6. package/package.json +3 -2
  7. package/skills/anysite-audience-analysis/SKILL.md +110 -38
  8. package/skills/anysite-audience-analysis/references/PLATFORM_COVERAGE.md +38 -19
  9. package/skills/anysite-audience-analysis/references/TOOL_MAPPING.md +16 -11
  10. package/skills/anysite-brand-reputation/SKILL.md +105 -43
  11. package/skills/anysite-competitor-analyzer/SKILL.md +170 -111
  12. package/skills/anysite-competitor-intelligence/SKILL.md +201 -116
  13. package/skills/anysite-competitor-intelligence/references/ANALYSIS_PATTERNS.md +17 -13
  14. package/skills/anysite-content-analytics/SKILL.md +101 -33
  15. package/skills/anysite-crm-account-brief/SKILL.md +71 -0
  16. package/skills/anysite-crm-audit/SKILL.md +59 -0
  17. package/skills/anysite-crm-champions/SKILL.md +76 -0
  18. package/skills/anysite-crm-competitor-intel/SKILL.md +74 -0
  19. package/skills/anysite-crm-enrich/SKILL.md +84 -0
  20. package/skills/anysite-crm-lookalikes/SKILL.md +64 -0
  21. package/skills/anysite-crm-prospect/SKILL.md +90 -0
  22. package/skills/anysite-crm-score/SKILL.md +72 -0
  23. package/skills/anysite-crm-setup/SKILL.md +147 -0
  24. package/skills/anysite-crm-signals/SKILL.md +96 -0
  25. package/skills/anysite-influencer-discovery/SKILL.md +123 -71
  26. package/skills/anysite-lead-generation/SKILL.md +288 -256
  27. package/skills/anysite-lead-generation/references/LINKEDIN_STRATEGIES.md +79 -71
  28. package/skills/anysite-lead-generation/references/WEB_SCRAPING.md +121 -87
  29. package/skills/anysite-market-research/SKILL.md +117 -68
  30. package/skills/anysite-mcp/SKILL.md +128 -0
  31. package/skills/anysite-mcp-migration/SKILL.md +19 -8
  32. package/skills/anysite-person-analyzer/SKILL.md +86 -53
  33. package/skills/anysite-trend-analysis/SKILL.md +119 -55
  34. package/skills/anysite-vc-analyst/SKILL.md +12 -2
  35. package/skills/competitor-discovery/SKILL.md +350 -0
  36. package/skills/customer-pain-mining/SKILL.md +318 -0
  37. package/skills/positioning-map/SKILL.md +314 -0
@@ -10,7 +10,7 @@
10
10
  "plugins": [
11
11
  {
12
12
  "name": "anysite-skills",
13
- "description": "Complete suite of 13 professional skills for social media analysis, lead generation, market research, competitive intelligence, person intelligence, VC analysis, competitor research, security auditing, and CLI automation using anysite MCP server. Supports LinkedIn, Instagram, Twitter/X, Reddit, YouTube, Y Combinator, SEC, GitHub, and web scraping. Zero configuration required - no API tokens or external tools needed.",
13
+ "description": "Complete suite of 18 professional skills for social media analysis, lead generation, CRM enrichment setup, market research, competitive intelligence, competitor discovery, customer pain mining, positioning mapping, person intelligence, VC analysis, competitor research, security auditing, and CLI automation using anysite MCP server. Supports LinkedIn, Instagram, Twitter/X, Reddit, YouTube, Y Combinator, SEC, GitHub, and web scraping. Zero configuration required - no API tokens or external tools needed.",
14
14
  "version": "1.1.0",
15
15
  "author": {
16
16
  "name": "Anysite Skills Contributors",
@@ -144,6 +144,54 @@
144
144
  "source": "./",
145
145
  "category": "productivity",
146
146
  "skills": ["./skills/anysite-mcp-migration"]
147
+ },
148
+ {
149
+ "name": "competitor-discovery",
150
+ "description": "Find a startup's real competitors — the alternatives customers actually compare them to, not just the names on the pitch deck. Maps direct competitors, substitutes, \"doing nothing\" workarounds, and convergence threats using Anysite MCP (LinkedIn, Reddit, YouTube, Twitter, YC, SEC) and Exa MCP semantic web search. Supports top5 and landscape modes. Run before customer-pain-mining or positioning-map.",
151
+ "version": "1.0.0",
152
+ "author": {
153
+ "name": "Anysite Skills Contributors",
154
+ "email": "support@anysite.io"
155
+ },
156
+ "source": "./",
157
+ "category": "productivity",
158
+ "skills": ["./skills/competitor-discovery"]
159
+ },
160
+ {
161
+ "name": "customer-pain-mining",
162
+ "description": "Extract verbatim customer complaints about competitors — the exact wording a founder's product copy should steal, in customers' own words. Combines Anysite MCP (Reddit, LinkedIn, YouTube comments, Twitter) with Exa MCP semantic search for review posts and comparison articles. Returns 3–5 pain clusters with verbatim quotes plus a white-space section of unmet feature requests.",
163
+ "version": "1.0.0",
164
+ "author": {
165
+ "name": "Anysite Skills Contributors",
166
+ "email": "support@anysite.io"
167
+ },
168
+ "source": "./",
169
+ "category": "productivity",
170
+ "skills": ["./skills/customer-pain-mining"]
171
+ },
172
+ {
173
+ "name": "positioning-map",
174
+ "description": "Build a positioning map for 3–5 competitors and identify the empty quadrant a founder could own. Maps competitors across 5 signal axes (hero, pricing, specialities, recent shipping, hiring) using Anysite MCP (LinkedIn, SEC) and Exa MCP. Returns a comparison table, 3 candidate positioning moves with choice criteria, and a one-sentence positioning statement.",
175
+ "version": "1.0.0",
176
+ "author": {
177
+ "name": "Anysite Skills Contributors",
178
+ "email": "support@anysite.io"
179
+ },
180
+ "source": "./",
181
+ "category": "productivity",
182
+ "skills": ["./skills/positioning-map"]
183
+ },
184
+ {
185
+ "name": "anysite-crm-setup",
186
+ "description": "Connect and configure the user's CRM (HubSpot) for safe AI-driven enrichment via anysite MCP crm_* tools: guided discovery, deterministic field mapping saved as a local profile, and mandatory writing rules (dry-run previews, fill-blank policy, undo).",
187
+ "version": "1.0.0",
188
+ "author": {
189
+ "name": "Anysite Skills Contributors",
190
+ "email": "support@anysite.io"
191
+ },
192
+ "source": "./",
193
+ "category": "productivity",
194
+ "skills": ["./skills/anysite-crm-setup"]
147
195
  }
148
196
  ]
149
197
  }
@@ -42,6 +42,10 @@
42
42
  "./skills/anysite-vc-analyst",
43
43
  "./skills/anysite-competitor-analyzer",
44
44
  "./skills/skill-audit",
45
- "./skills/anysite-cli"
45
+ "./skills/anysite-cli",
46
+ "./skills/competitor-discovery",
47
+ "./skills/customer-pain-mining",
48
+ "./skills/positioning-map",
49
+ "./skills/anysite-crm-setup"
46
50
  ]
47
51
  }
package/README.md CHANGED
@@ -28,55 +28,49 @@ Get unlimited requests through Remote MCP Server with no request limits. Ideal f
28
28
  | `anysite-competitor-analyzer` | Comprehensive competitive intelligence combining web scraping, LinkedIn analysis, social media monitoring, leadership profiling, GitHub review, and community sentiment tracking. | [SKILL.md](skills/anysite-competitor-analyzer/SKILL.md) |
29
29
  | `skill-audit` | Static security auditor for Claude Code skills. Detects hooks, prompt injection, and dangerous permissions. | [SKILL.md](skills/skill-audit/SKILL.md) |
30
30
  | `anysite-cli` | Command-line tool operator for anysite CLI. Execute data extraction, batch processing, dataset pipelines, scheduling, and database operations. | [SKILL.md](skills/anysite-cli/SKILL.md) |
31
+ | `competitor-discovery` | Find a startup's real competitors — the alternatives customers actually compare them to. Maps direct competitors, substitutes, workarounds, and convergence threats across LinkedIn, Reddit, YouTube, Twitter, YC, and SEC. | [SKILL.md](skills/competitor-discovery/SKILL.md) |
32
+ | `customer-pain-mining` | Extract verbatim customer complaints about competitors for landing-page copy, custdev prep, and product strategy. Returns pain clusters with exact quotes plus a white-space section of unmet feature requests. | [SKILL.md](skills/customer-pain-mining/SKILL.md) |
33
+ | `positioning-map` | Build a positioning map for 3–5 competitors and identify the empty quadrant to own. Maps 5 signal axes and returns a comparison table, candidate positioning moves, and a one-sentence positioning statement. | [SKILL.md](skills/positioning-map/SKILL.md) |
34
+ | `anysite-crm-setup` | Connect the user's CRM (HubSpot) and configure safe AI enrichment: guided discovery, deterministic local field mapping, dry-run previews, fill-blank policy and undo. | [SKILL.md](skills/anysite-crm-setup/SKILL.md) |
35
+ | `anysite-mcp` | Usage guide for the anysite MCP: meta-tools, GTM source map (funding, hiring, tech stack, reviews, news), email cascades, and cost-aware calling patterns. | [SKILL.md](skills/anysite-mcp/SKILL.md) |
36
+ | `anysite-crm-enrich` | Enrich existing CRM records with fresh data - titles, LinkedIn profiles, firmographics, emails. Fill-blank policy, dry-run previews, undo. | [SKILL.md](skills/anysite-crm-enrich/SKILL.md) |
37
+ | `anysite-crm-signals` | Sweep CRM target accounts for buying signals - funding, exec hires, hiring surges, news, mentions - and prioritize who to reach out to today. | [SKILL.md](skills/anysite-crm-signals/SKILL.md) |
38
+ | `anysite-crm-champions` | Detect job changes among CRM contacts, flag past champions at new accounts, propose re-engagement plays. | [SKILL.md](skills/anysite-crm-champions/SKILL.md) |
39
+ | `anysite-crm-prospect` | Find net-new leads and push them into the CRM deduplicated - companies first, then contacts with associations. | [SKILL.md](skills/anysite-crm-prospect/SKILL.md) |
40
+ | `anysite-crm-audit` | Read-only CRM data quality audit: field completeness, duplicate candidates, stale records, enrichability estimate. | [SKILL.md](skills/anysite-crm-audit/SKILL.md) |
41
+ | `anysite-crm-score` | Score CRM companies against your ICP with an explicit rubric and write the score into the mapped field. | [SKILL.md](skills/anysite-crm-score/SKILL.md) |
42
+ | `anysite-crm-competitor-intel` | Displacement hunting: who uses a competitor (technographics), what their users complain about (review mining), tagged into the CRM. | [SKILL.md](skills/anysite-crm-competitor-intel/SKILL.md) |
43
+ | `anysite-crm-account-brief` | Pre-meeting one-pager for a CRM account: CRM context + funding, exec changes, news, key people's recent activity. | [SKILL.md](skills/anysite-crm-account-brief/SKILL.md) |
44
+ | `anysite-crm-lookalikes` | Derive your real ICP from closed-won customers and find lookalike companies across 70M+ company records. | [SKILL.md](skills/anysite-crm-lookalikes/SKILL.md) |
31
45
  <!-- END_SKILLS_TABLE -->
32
46
 
33
47
  ## Installation
34
48
 
35
- ### Quick Start
49
+ One line — installs skills into Claude Code / Codex and registers the anysite remote MCP server (sign-in happens in your browser on first use):
36
50
 
37
51
  ```bash
38
- npx @anysiteio/agent-skills
39
- ```
40
-
41
- This will display installation instructions and list all available skills.
42
-
43
- ### Step 1: Install anysite MCP Server
44
-
45
- First, install the anysite MCP server following the instructions at [docs.anysite.io/mcp-server](https://docs.anysite.io/mcp-server).
46
-
47
- ### Step 2: Add Skills Marketplace
48
-
49
- #### Option 1: Using npx (Recommended)
52
+ # GTM package (recommended for sales/growth teams): CRM workflows + MCP
53
+ npx @anysiteio/agent-skills gtm
50
54
 
51
- ```bash
55
+ # Everything: all skills + MCP
52
56
  npx @anysiteio/agent-skills
53
57
  ```
54
58
 
55
- Then in Claude Code, run:
56
- ```bash
57
- /plugin marketplace add https://github.com/anysiteio/agent-skills
58
- ```
59
+ You can also just send this line to your agent (Claude Code / Codex) — it will run it for you.
59
60
 
60
- #### Option 2: Manual Installation
61
+ Other commands:
61
62
 
62
- In Claude Code:
63
63
  ```bash
64
- # Add the marketplace
65
- /plugin marketplace add https://github.com/anysiteio/agent-skills
66
-
67
- # Install a skill
68
- /plugin install anysite-lead-generation@anysite-skills
64
+ npx @anysiteio/agent-skills --list # list bundles and skills
65
+ npx @anysiteio/agent-skills --status # what is installed
66
+ npx @anysiteio/agent-skills --skill NAME # install specific skill(s)
67
+ npx @anysiteio/agent-skills --uninstall # remove anysite skills
68
+ npx @anysiteio/agent-skills --no-mcp # skills only, skip MCP registration
69
69
  ```
70
70
 
71
- #### Cursor / Windsurf
72
-
73
- Add to your project's `.cursor/settings.json` or use the same Claude Code plugin format.
74
-
75
- #### Other AI Tools
71
+ After installing the GTM package, restart your agent session and say `/anysite-crm-setup` — it connects your HubSpot and configures safe field mapping.
76
72
 
77
- Any AI tool that supports markdown context can use the skills by pointing to:
78
- - `skills/*/SKILL.md` - Individual skill documentation
79
- - `.claude-plugin/marketplace.json` - Skill metadata
73
+ To update, re-run the same command: `npx` always fetches the latest published version.
80
74
 
81
75
  ## Prerequisites
82
76
 
package/bin/install.js CHANGED
@@ -1,43 +1,64 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Anysite Agent Skills installer for Claude Code
4
+ * Anysite agent setup: installs skills into Claude Code / Codex and registers
5
+ * the anysite remote MCP server (https://mcp.anysite.io/mcp, OAuth on first use).
5
6
  *
6
7
  * Usage:
7
- * npx @anysiteio/agent-skills # Install all skills
8
- * npx @anysiteio/agent-skills --list # List available skills
9
- * npx @anysiteio/agent-skills --skill lead-generation --skill person-analyzer
10
- * npx @anysiteio/agent-skills --uninstall # Remove all installed skills
8
+ * npx @anysiteio/agent-skills Install ALL skills + register MCP
9
+ * npx @anysiteio/agent-skills gtm Install the GTM bundle + register MCP
10
+ * npx @anysiteio/agent-skills --list List skills and bundles
11
+ * npx @anysiteio/agent-skills --status Show what is installed
12
+ * npx @anysiteio/agent-skills --skill N Install specific skill(s), no MCP
13
+ * npx @anysiteio/agent-skills --uninstall Remove anysite skills (MCP entry is kept)
14
+ *
15
+ * Flags: --no-mcp | --target claude|codex | --help
11
16
  */
12
17
 
13
- import { existsSync, mkdirSync, cpSync, rmSync, readdirSync, readFileSync } from "fs";
14
- import { join, resolve } from "path";
15
- import { fileURLToPath } from "url";
16
- import { homedir } from "os";
18
+ import { execFileSync } from "node:child_process";
19
+ import {
20
+ cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync,
21
+ } from "node:fs";
22
+ import { homedir } from "node:os";
23
+ import { dirname, join, resolve } from "node:path";
24
+ import { fileURLToPath } from "node:url";
17
25
 
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = resolve(fileURLToPath(import.meta.url), "..");
20
- const SKILLS_SRC = resolve(__dirname, "..", "skills");
21
- const CLAUDE_SKILLS_DIR = join(homedir(), ".claude", "skills");
26
+ const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
27
+ const SKILLS_SRC = join(PKG_ROOT, "skills");
28
+ const BUNDLES = JSON.parse(readFileSync(join(PKG_ROOT, "bundles.json"), "utf8"));
29
+ const PKG_VERSION = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8")).version;
22
30
 
23
- // ── Parse args ──────────────────────────────────────────────────────────────
31
+ const HOME = process.env.HOME || homedir();
32
+ const CLAUDE_DIR = join(HOME, ".claude");
33
+ const CODEX_DIR = join(HOME, ".codex");
34
+ const CODEX_CONFIG = join(CODEX_DIR, "config.toml");
35
+ // Both agents use the same skills convention: <dir>/skills/<name>/SKILL.md
36
+ const SKILLS_DST = { claude: join(CLAUDE_DIR, "skills"), codex: join(CODEX_DIR, "skills") };
37
+ const manifestPath = (dstRoot) => join(dstRoot, ".anysite-skills.json");
24
38
 
25
- const args = process.argv.slice(2);
26
- const flags = { list: false, uninstall: false, skills: [], help: false };
39
+ const MCP_NAME = "anysite";
40
+ const MCP_URL = "https://mcp.anysite.io/mcp";
41
+
42
+ // ── args ────────────────────────────────────────────────────────────────────
27
43
 
44
+ const args = process.argv.slice(2);
45
+ const flags = { bundle: null, list: false, status: false, uninstall: false, help: false, mcp: true, skills: [], targets: [] };
28
46
  for (let i = 0; i < args.length; i++) {
29
- if (args[i] === "--list" || args[i] === "-l") flags.list = true;
30
- else if (args[i] === "--uninstall" || args[i] === "--remove") flags.uninstall = true;
31
- else if (args[i] === "--help" || args[i] === "-h") flags.help = true;
32
- else if (args[i] === "--skill" || args[i] === "-s") {
33
- i++;
34
- if (i < args.length) flags.skills.push(args[i]);
35
- }
47
+ const a = args[i];
48
+ if (a === "--list" || a === "-l") flags.list = true;
49
+ else if (a === "--status") flags.status = true;
50
+ else if (a === "--uninstall" || a === "--remove") flags.uninstall = true;
51
+ else if (a === "--help" || a === "-h") flags.help = true;
52
+ else if (a === "--no-mcp") flags.mcp = false;
53
+ else if (a === "--skill" || a === "-s") { if (args[++i]) flags.skills.push(args[i]); }
54
+ else if (a === "--target") { if (args[++i]) flags.targets.push(args[i]); }
55
+ else if (!a.startsWith("-") && BUNDLES[a]) flags.bundle = a;
56
+ else { console.error(`Unknown argument: ${a} (see --help)`); process.exit(1); }
36
57
  }
37
58
 
38
- // ── Helpers ─────────────────────────────────────────────────────────────────
59
+ // ── helpers ─────────────────────────────────────────────────────────────────
39
60
 
40
- function getAvailableSkills() {
61
+ function availableSkills() {
41
62
  if (!existsSync(SKILLS_SRC)) return [];
42
63
  return readdirSync(SKILLS_SRC, { withFileTypes: true })
43
64
  .filter((d) => d.isDirectory() && existsSync(join(SKILLS_SRC, d.name, "SKILL.md")))
@@ -45,142 +66,182 @@ function getAvailableSkills() {
45
66
  .sort();
46
67
  }
47
68
 
48
- function getSkillDescription(name) {
49
- const skillPath = join(SKILLS_SRC, name, "SKILL.md");
50
- if (!existsSync(skillPath)) return "";
51
- const content = readFileSync(skillPath, "utf-8");
52
- const match = content.match(/^---\s*\n[\s\S]*?description:\s*(.+)\n[\s\S]*?^---/m);
53
- return match ? match[1].trim().slice(0, 80) : "";
69
+ function skillDescription(name) {
70
+ try {
71
+ const m = readFileSync(join(SKILLS_SRC, name, "SKILL.md"), "utf8")
72
+ .match(/^description:\s*(.+)$/m);
73
+ return m ? m[1].trim().replace(/\s+/g, " ").slice(0, 96) : "";
74
+ } catch { return ""; }
54
75
  }
55
76
 
56
- function getInstalledSkills() {
57
- if (!existsSync(CLAUDE_SKILLS_DIR)) return [];
58
- return readdirSync(CLAUDE_SKILLS_DIR, { withFileTypes: true })
59
- .filter(
60
- (d) =>
61
- d.isDirectory() &&
62
- d.name.startsWith("anysite-") &&
63
- existsSync(join(CLAUDE_SKILLS_DIR, d.name, "SKILL.md"))
64
- )
65
- .map((d) => d.name)
66
- .sort();
77
+ function readManifest(dstRoot) {
78
+ try { return JSON.parse(readFileSync(manifestPath(dstRoot), "utf8")); } catch { return null; }
67
79
  }
68
80
 
69
- // ── Commands ────────────────────────────────────────────────────────────────
81
+ function detectTargets() {
82
+ if (flags.targets.length) return flags.targets;
83
+ const t = [];
84
+ if (existsSync(CLAUDE_DIR)) t.push("claude");
85
+ if (existsSync(CODEX_DIR)) t.push("codex");
86
+ return t;
87
+ }
70
88
 
71
- if (flags.help) {
72
- console.log(`
73
- Anysite Agent Skills — install skills for Claude Code
74
-
75
- Usage:
76
- npx @anysiteio/agent-skills Install all skills
77
- npx @anysiteio/agent-skills --list List available skills
78
- npx @anysiteio/agent-skills --skill NAME Install specific skill(s)
79
- npx @anysiteio/agent-skills --uninstall Remove all anysite skills
80
-
81
- Options:
82
- --skill, -s NAME Install specific skill (repeatable)
83
- --list, -l List available skills
84
- --uninstall Remove installed anysite skills
85
- --help, -h Show this help
86
- `);
87
- process.exit(0);
89
+ function hasClaudeCli() {
90
+ try { execFileSync("claude", ["--version"], { stdio: "ignore" }); return true; } catch { return false; }
88
91
  }
89
92
 
90
- if (flags.list) {
91
- const skills = getAvailableSkills();
92
- const installed = new Set(getInstalledSkills());
93
- console.log(`\nAvailable skills (${skills.length}):\n`);
94
- for (const name of skills) {
95
- const status = installed.has(name) ? " ✓" : " ";
96
- const desc = getSkillDescription(name);
97
- console.log(`${status} ${name}`);
98
- if (desc) console.log(` ${desc}`);
93
+ // ── skills install / uninstall ──────────────────────────────────────────────
94
+
95
+ function installSkills(names, dstRoot) {
96
+ mkdirSync(dstRoot, { recursive: true });
97
+ const installed = [];
98
+ const missing = [];
99
+ for (const name of names) {
100
+ const src = join(SKILLS_SRC, name);
101
+ if (!existsSync(join(src, "SKILL.md"))) { missing.push(name); continue; }
102
+ const dst = join(dstRoot, name);
103
+ rmSync(dst, { recursive: true, force: true });
104
+ cpSync(src, dst, { recursive: true });
105
+ installed.push(name);
99
106
  }
100
- console.log();
101
- process.exit(0);
107
+ const prev = readManifest(dstRoot);
108
+ const all = [...new Set([...(prev?.skills ?? []), ...installed])].sort();
109
+ writeFileSync(manifestPath(dstRoot), JSON.stringify({
110
+ version: PKG_VERSION,
111
+ bundle: flags.bundle ?? prev?.bundle ?? null,
112
+ installedAt: new Date().toISOString(),
113
+ skills: all,
114
+ }, null, 2));
115
+ return { installed, missing };
102
116
  }
103
117
 
104
- if (flags.uninstall) {
105
- const installed = getInstalledSkills();
106
- // Also check for non-prefixed skills like skill-audit
107
- const allInstalled = existsSync(CLAUDE_SKILLS_DIR)
108
- ? readdirSync(CLAUDE_SKILLS_DIR, { withFileTypes: true })
109
- .filter((d) => d.isDirectory())
110
- .map((d) => d.name)
111
- .filter((n) => getAvailableSkills().includes(n))
112
- : [];
113
-
114
- if (allInstalled.length === 0) {
115
- console.log("\nNo anysite skills installed.\n");
116
- process.exit(0);
118
+ function uninstallSkills(dstRoot) {
119
+ const manifest = readManifest(dstRoot);
120
+ const tracked = new Set(manifest?.skills ?? []);
121
+ const removed = [];
122
+ if (existsSync(dstRoot)) {
123
+ for (const d of readdirSync(dstRoot, { withFileTypes: true })) {
124
+ if (!d.isDirectory()) continue;
125
+ // remove tracked skills plus legacy anysite-* installs; never touch anything else
126
+ if (tracked.has(d.name) || d.name.startsWith("anysite-")) {
127
+ rmSync(join(dstRoot, d.name), { recursive: true, force: true });
128
+ removed.push(d.name);
129
+ }
130
+ }
117
131
  }
132
+ rmSync(manifestPath(dstRoot), { force: true });
133
+ return removed;
134
+ }
118
135
 
119
- for (const name of allInstalled) {
120
- const target = join(CLAUDE_SKILLS_DIR, name);
121
- rmSync(target, { recursive: true, force: true });
122
- console.log(` Removed ${name}`);
136
+ // ── MCP registration ────────────────────────────────────────────────────────
137
+
138
+ function registerMcpClaude() {
139
+ if (!hasClaudeCli()) {
140
+ return { ok: false, note: `claude CLI not found — run manually:\n claude mcp add --scope user --transport http ${MCP_NAME} ${MCP_URL}` };
141
+ }
142
+ try {
143
+ execFileSync("claude", ["mcp", "get", MCP_NAME], { stdio: "ignore" });
144
+ return { ok: true, note: `MCP "${MCP_NAME}" already registered in Claude Code — kept as is.` };
145
+ } catch { /* not registered yet */ }
146
+ try {
147
+ execFileSync("claude", ["mcp", "add", "--scope", "user", "--transport", "http", MCP_NAME, MCP_URL], { stdio: "ignore" });
148
+ return { ok: true, note: `MCP "${MCP_NAME}" registered in Claude Code (user scope). Sign-in happens in the browser on first use.` };
149
+ } catch (e) {
150
+ return { ok: false, note: `Could not register MCP automatically (${e.message}). Run manually:\n claude mcp add --scope user --transport http ${MCP_NAME} ${MCP_URL}` };
123
151
  }
124
- console.log(`\nUninstalled ${allInstalled.length} skill(s).\n`);
125
- process.exit(0);
126
152
  }
127
153
 
128
- // ── Install ─────────────────────────────────────────────────────────────────
154
+ function registerMcpCodex() {
155
+ mkdirSync(CODEX_DIR, { recursive: true });
156
+ let cfg = "";
157
+ try { cfg = readFileSync(CODEX_CONFIG, "utf8"); } catch { /* new file */ }
158
+ if (cfg.includes(`[mcp_servers.${MCP_NAME}]`)) {
159
+ return { ok: true, note: `MCP "${MCP_NAME}" already present in Codex config — kept as is.` };
160
+ }
161
+ const block = `\n[mcp_servers.${MCP_NAME}]\ncommand = "npx"\nargs = ["-y", "mcp-remote", "${MCP_URL}"]\n`;
162
+ writeFileSync(CODEX_CONFIG, cfg + block);
163
+ return { ok: true, note: `MCP "${MCP_NAME}" added to ${CODEX_CONFIG} (via mcp-remote, OAuth in browser on first use).` };
164
+ }
129
165
 
130
- const available = getAvailableSkills();
166
+ // ── commands ────────────────────────────────────────────────────────────────
131
167
 
132
- if (available.length === 0) {
133
- console.error("Error: no skills found in package. Please reinstall.");
134
- process.exit(1);
168
+ if (flags.help) {
169
+ console.log(readFileSync(fileURLToPath(import.meta.url), "utf8").match(/\/\*\*([\s\S]*?)\*\//)[1].replace(/^ \* ?/gm, ""));
170
+ process.exit(0);
135
171
  }
136
172
 
137
- // Resolve which skills to install
138
- let toInstall = available;
139
-
140
- if (flags.skills.length > 0) {
141
- toInstall = [];
142
- for (const input of flags.skills) {
143
- // Allow short names: "lead-generation" -> "anysite-lead-generation"
144
- const candidates = [input, `anysite-${input}`];
145
- const match = candidates.find((c) => available.includes(c));
146
- if (match) {
147
- toInstall.push(match);
148
- } else {
149
- console.error(`Unknown skill: ${input}`);
150
- console.error(`Available: ${available.join(", ")}`);
151
- process.exit(1);
152
- }
173
+ if (flags.list) {
174
+ const installed = new Set(detectTargets().flatMap((t) => readManifest(SKILLS_DST[t])?.skills ?? []));
175
+ console.log("\nBundles:");
176
+ for (const [name, b] of Object.entries(BUNDLES)) {
177
+ console.log(` ${name} (${b.skills.length} skills) — ${b.description}`);
153
178
  }
179
+ const skills = availableSkills();
180
+ console.log(`\nSkills (${skills.length}):`);
181
+ for (const name of skills) {
182
+ console.log(` ${installed.has(name) ? "✓" : " "} ${name.padEnd(34)} ${skillDescription(name)}`);
183
+ }
184
+ console.log("");
185
+ process.exit(0);
154
186
  }
155
187
 
156
- console.log(`\nInstalling ${toInstall.length} skill(s) to ${CLAUDE_SKILLS_DIR}\n`);
188
+ if (flags.status) {
189
+ let any = false;
190
+ for (const t of detectTargets()) {
191
+ const manifest = readManifest(SKILLS_DST[t]);
192
+ if (!manifest) { console.log(`\n[${t}] no anysite skills installed.`); continue; }
193
+ any = true;
194
+ console.log(`\n[${t}] ${manifest.skills.length} skills (package v${manifest.version}, ${manifest.installedAt})${manifest.bundle ? `, bundle: ${manifest.bundle}` : ""}`);
195
+ for (const s of manifest.skills) console.log(` ✓ ${s}`);
196
+ if (any) console.log(`\nUpdate: npx @anysiteio/agent-skills@latest ${manifest.bundle ?? ""}`);
197
+ }
198
+ console.log("");
199
+ process.exit(0);
200
+ }
157
201
 
158
- // Ensure target dir exists
159
- mkdirSync(CLAUDE_SKILLS_DIR, { recursive: true });
202
+ if (flags.uninstall) {
203
+ for (const t of detectTargets()) {
204
+ const removed = uninstallSkills(SKILLS_DST[t]);
205
+ console.log(removed.length
206
+ ? `\n[${t}] removed ${removed.length} skills from ${SKILLS_DST[t]}`
207
+ : `\n[${t}] nothing to remove.`);
208
+ }
209
+ console.log(`\nThe MCP entries are kept. To remove: claude mcp remove ${MCP_NAME} / edit ~/.codex/config.toml\n`);
210
+ process.exit(0);
211
+ }
160
212
 
161
- let installed = 0;
162
- let updated = 0;
213
+ // install (default: all skills; `gtm`: bundle; --skill: explicit list)
214
+ const names = flags.skills.length ? flags.skills
215
+ : flags.bundle ? BUNDLES[flags.bundle].skills
216
+ : availableSkills();
217
+ const withMcp = flags.mcp && !flags.skills.length;
218
+ const targets = detectTargets();
219
+
220
+ console.log(`\nanysite setup v${PKG_VERSION} — ${flags.bundle ? `bundle "${flags.bundle}"` : flags.skills.length ? "selected skills" : "all skills"}`);
221
+ if (!targets.length) {
222
+ console.log("\nNo supported agents detected (~/.claude or ~/.codex not found).");
223
+ console.log("Install Claude Code or Codex first, then re-run this command.\n");
224
+ process.exit(1);
225
+ }
163
226
 
164
- for (const name of toInstall) {
165
- const src = join(SKILLS_SRC, name);
166
- const dest = join(CLAUDE_SKILLS_DIR, name);
167
- const exists = existsSync(dest);
227
+ let installedTotal = 0;
228
+ for (const t of targets) {
229
+ const { installed, missing } = installSkills(names, SKILLS_DST[t]);
230
+ installedTotal += installed.length;
231
+ console.log(`\nSkills [${t}] → ${SKILLS_DST[t]}: ${installed.length} installed${missing.length ? `, unknown: ${missing.join(", ")}` : ""}`);
232
+ }
233
+ if (!installedTotal) {
234
+ console.error("Nothing was installed — check skill names with --list.");
235
+ process.exit(1);
236
+ }
168
237
 
169
- if (exists) {
170
- rmSync(dest, { recursive: true, force: true });
171
- updated++;
172
- } else {
173
- installed++;
238
+ if (withMcp) {
239
+ for (const t of targets) {
240
+ const res = t === "claude" ? registerMcpClaude() : registerMcpCodex();
241
+ console.log(`MCP [${t}]: ${res.note}`);
174
242
  }
175
-
176
- cpSync(src, dest, { recursive: true });
177
- console.log(` ${exists ? "↻" : "+"} ${name}`);
178
243
  }
179
244
 
180
- console.log();
181
- if (installed > 0) console.log(` Installed: ${installed}`);
182
- if (updated > 0) console.log(` Updated: ${updated}`);
183
- console.log(` Location: ${CLAUDE_SKILLS_DIR}`);
184
- console.log();
185
- console.log("Skills are now available in Claude Code.");
186
- console.log("Use /skill-name to invoke, or Claude will use them automatically.\n");
245
+ const next = flags.bundle ? BUNDLES[flags.bundle].next_step
246
+ : "Restart your agent session to pick up the new skills.";
247
+ console.log(`\nDone. Next step: ${next}\n`);
package/bundles.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "gtm": {
3
+ "description": "GTM package: CRM enrichment, signals, prospecting and account intelligence workflows for the anysite MCP + CRM integration",
4
+ "next_step": "Restart your agent session, then say: /anysite-crm-setup — it connects your CRM and configures field mapping.",
5
+ "skills": [
6
+ "anysite-mcp",
7
+ "anysite-crm-setup",
8
+ "anysite-crm-enrich",
9
+ "anysite-crm-signals",
10
+ "anysite-crm-champions",
11
+ "anysite-crm-prospect",
12
+ "anysite-crm-audit",
13
+ "anysite-crm-score",
14
+ "anysite-crm-competitor-intel",
15
+ "anysite-crm-account-brief",
16
+ "anysite-crm-lookalikes"
17
+ ]
18
+ }
19
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@anysiteio/agent-skills",
3
- "version": "1.4.0",
4
- "description": "Official anysite agent skills for LinkedIn intelligence, social media analysis, data extraction, and security auditing",
3
+ "version": "2.0.1",
4
+ "description": "Official anysite agent skills + one-line setup: installs skills into Claude Code / Codex and registers the anysite remote MCP server. Includes the GTM bundle (CRM enrichment, signals, prospecting).",
5
5
  "keywords": [
6
6
  "mcp",
7
7
  "claude-code",
@@ -32,6 +32,7 @@
32
32
  "skills/",
33
33
  ".claude-plugin/",
34
34
  "bin/",
35
+ "bundles.json",
35
36
  "README.md",
36
37
  "LICENSE"
37
38
  ],