skills-atlas-cli 0.13.0 → 0.15.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.
package/README.md CHANGED
@@ -7,6 +7,11 @@
7
7
  Code.** Stop guessing which skill fits or copy-pasting from random repos. Search a
8
8
  curated catalog of **800+ skills** and drop the right one into `.claude/skills/` in seconds.
9
9
 
10
+ > 🧩 **Using Claude Code? The easiest way is the [Skills Atlas plugin](./plugin).** It runs
11
+ > on this CLI and brings everything into the conversation — an **autopilot that's on by
12
+ > default** (the right skill finds you as you work) plus slash commands. Install this CLI as
13
+ > the engine, then add the plugin (two lines). → [**plugin docs**](./plugin)
14
+
10
15
  > **New to "skills"?** A skill is a reusable `SKILL.md` instruction pack that teaches
11
16
  > Claude Code a specialized workflow: systematic debugging, pre-mortems, SEO audits,
12
17
  > PDF translation, and hundreds more. This tool finds and installs them for you.
@@ -129,17 +134,24 @@ skills-atlas registry remove https://skills.acme.internal/data.json
129
134
 
130
135
  Private skills merge with the public catalog (your own wins a name clash) and are cached locally.
131
136
 
132
- ## In Claude Code
137
+ ## In Claude Code — the plugin (recommended)
133
138
 
134
- A thin [Claude Code plugin](./plugin) lets Claude do all of this in-conversation.
135
- Just describe what you need, or use `/skills-atlas:skill-search`, `:skill-info`,
136
- `:skill-install`:
139
+ The **[Skills Atlas plugin](./plugin)** wraps this CLI so Claude does it all
140
+ in-conversation: an **autopilot on by default** that surfaces the fitting skill as you
141
+ work, plus slash commands (`/skills-atlas:skill-search`, `:skill-install`, `:skill-kit`,
142
+ `:skill-craft`, …). Install this CLI first (the engine), then add the plugin:
137
143
 
138
144
  ```text
139
- /plugin marketplace add Zita-Go/Skills-Atlas
145
+ npm i -g skills-atlas-cli # the engine (Node 18+)
146
+ /plugin marketplace add Zita-Go/Skills-Atlas # then, inside Claude Code:
140
147
  /plugin install skills-atlas@skills-atlas
141
148
  ```
142
149
 
150
+ Restart Claude Code, run `/skills-atlas:setup`, and you're set. → [**plugin docs**](./plugin)
151
+
152
+ <img src="https://raw.githubusercontent.com/Zita-Go/Skills-Atlas/main/docs/plugin-demo.png" alt="Skills Atlas plugin — the autopilot surfaces a fitting skill in-conversation" width="820">
153
+
154
+
143
155
  ## In any MCP client
144
156
 
145
157
  `skills-atlas mcp` runs an [MCP](https://modelcontextprotocol.io) server so any
package/bin/skills.js CHANGED
@@ -22,12 +22,14 @@ const setup = require('../src/commands/setup');
22
22
  const feedback = require('../src/commands/feedback');
23
23
  const update = require('../src/commands/update');
24
24
  const mcp = require('../src/commands/mcp');
25
+ const telemetry = require('../src/telemetry');
26
+ const telemetryCmd = require('../src/commands/telemetry');
25
27
  const { categories, list } = require('../src/commands/categories');
26
28
 
27
29
  const VERSION = require('../package.json').version;
28
30
  // `use` = install + activate inline (emit the SKILL.md so an agent follows it now).
29
31
  const use = argv => install([...argv, '--inline']);
30
- const commands = { search, info, install, use, kit, sync, installed, upgrade, remove, outdated, doctor, suggest, hook, gaps, 'gap-analyze': gapAnalyze, craft, prune, feedback, setup, update, categories, list, registry, mcp };
32
+ const commands = { search, info, install, use, kit, sync, installed, upgrade, remove, outdated, doctor, suggest, hook, gaps, 'gap-analyze': gapAnalyze, craft, prune, feedback, setup, update, categories, list, registry, mcp, telemetry: telemetryCmd };
31
33
 
32
34
  const HELP = `skills-atlas — search, install & manage AI agent skills
33
35
 
@@ -57,6 +59,7 @@ autopilot (opt-in):
57
59
  craft codify a workflow you keep repeating into a new local skill (Claude drafts it)
58
60
  prune installed skills you no longer use — Claude suggests removing them
59
61
  feedback what the autopilot learned from your installs/removes (sharpens it)
62
+ telemetry on|off|status anonymous opt-out usage telemetry (no prompts/paths/identity)
60
63
 
61
64
  catalog:
62
65
  update refresh the catalog from the public data feed
@@ -87,7 +90,13 @@ async function main() {
87
90
  if (sub !== 'update' && sub !== 'gap-analyze' && sub !== 'setup' && !process.env.SKILLS_ATLAS_SUBCALL) {
88
91
  try { require('../src/data').maybeBackgroundRefresh(); } catch { /* ignore */ }
89
92
  }
90
- await cmd(rest);
93
+ if (sub !== 'telemetry' && !process.env.SKILLS_ATLAS_SUBCALL) telemetry.emit('cli_cmd', { target: sub });
94
+ try {
95
+ await cmd(rest);
96
+ } catch (e) {
97
+ telemetry.emit('cli_err', { target: sub, detail: String(e && e.message || e).slice(0, 200) });
98
+ throw e;
99
+ }
91
100
  }
92
101
 
93
102
  main().catch(err => {
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ // Detached sender. Reads {endpoint, client, events} from the temp file in argv[2], POSTs once
4
+ // with a short timeout, then deletes the file. Fully fail-silent — telemetry must never matter.
5
+ const fs = require('fs');
6
+ const file = process.argv[2];
7
+ const cleanup = () => { try { fs.unlinkSync(file); } catch { /* ignore */ } };
8
+ if (!file) process.exit(0);
9
+ let p; try { p = JSON.parse(fs.readFileSync(file, 'utf8')); } catch { cleanup(); process.exit(0); }
10
+ if (!p || !p.endpoint || !Array.isArray(p.events) || !p.events.length) { cleanup(); process.exit(0); }
11
+ try {
12
+ const ac = new AbortController();
13
+ const timer = setTimeout(() => ac.abort(), 2000);
14
+ fetch(p.endpoint, {
15
+ method: 'POST',
16
+ headers: { 'Content-Type': 'application/json' },
17
+ body: JSON.stringify({ client: p.client, events: p.events }),
18
+ signal: ac.signal,
19
+ }).catch(() => {}).finally(() => { clearTimeout(timer); cleanup(); });
20
+ } catch { cleanup(); }