@squadbase/vantage 0.2.1 → 0.2.2

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,7 +7,7 @@ You write `index.tsx`. Vantage owns routing, React, TanStack Query, Tailwind v4,
7
7
  the UI kit, the dev server, the optional API server, and the build. There is no
8
8
  config file.
9
9
 
10
- > **Status: prototype (v0.2.1).** APIs may still change between releases.
10
+ > **Status: prototype (v0.2.2).** APIs may still change between releases.
11
11
 
12
12
  ## Install
13
13
 
@@ -100,9 +100,13 @@ npx vantage docs # every guide + component page, offline
100
100
  npx vantage docs button --json # one page, machine-readable
101
101
  npx vantage search "date range" # find the right component by meaning
102
102
  npx vantage add agents # drop an AGENTS.md map into your project
103
+ npx vantage add skill # list the bundled skills and where they sit
103
104
  npx vantage add skill --all --dir .claude/skills # install the Claude Code skills for Vantage
104
105
  ```
105
106
 
107
+ `add skill` scans the project first, so skills that are already placed — wherever they live — are
108
+ skipped with their location reported instead of copied a second time.
109
+
106
110
  `vantage upgrade` re-syncs `AGENTS.md` when you update the package.
107
111
 
108
112
  ## Documentation
package/dist/cli.js CHANGED
@@ -147,30 +147,75 @@ function resolvePackageDir(root, sub) {
147
147
  function resolveRegistryDir(root) {
148
148
  return resolvePackageDir(root, "registry");
149
149
  }
150
+ var SKILL_FILE = "SKILL.md";
151
+ var SKILL_SCAN_SKIP = /* @__PURE__ */ new Set([
152
+ "node_modules",
153
+ ".git",
154
+ ".vantage",
155
+ "dist",
156
+ "build",
157
+ "out",
158
+ "coverage",
159
+ ".next",
160
+ ".turbo",
161
+ ".cache",
162
+ ".vercel"
163
+ ]);
164
+ var SKILL_SCAN_DEPTH = 4;
150
165
  function listBundledSkills(skillsDir) {
151
166
  try {
152
- return fs2.readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && fs2.existsSync(path2.join(skillsDir, e.name, "SKILL.md"))).map((e) => e.name).sort();
167
+ return fs2.readdirSync(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory() && fs2.existsSync(path2.join(skillsDir, e.name, SKILL_FILE))).map((e) => e.name).sort();
153
168
  } catch {
154
169
  return [];
155
170
  }
156
171
  }
157
- function copySkill(root, skillsDir, name, force, destDir) {
158
- const src = path2.join(skillsDir, name);
159
- if (!fs2.existsSync(path2.join(src, "SKILL.md"))) {
160
- const available = listBundledSkills(skillsDir);
161
- log.error(`Unknown skill "${name}". Available: ${available.join(", ") || "(none)"}`);
162
- return 1;
163
- }
164
- const dest = path2.join(destDir, name);
165
- const rel2 = path2.relative(root, dest);
166
- const label = !rel2 ? name : rel2.startsWith("..") ? dest : rel2;
167
- if (fs2.existsSync(dest) && !force) {
168
- log.error(`${label} already exists. Use --force to overwrite.`);
169
- return 1;
170
- }
172
+ function displayPath(root, target) {
173
+ const rel2 = path2.relative(root, target);
174
+ return !rel2 ? "." : rel2.startsWith("..") ? target : rel2;
175
+ }
176
+ function findPlacedSkills(root, names, skillsDir) {
177
+ const wanted = new Set(names);
178
+ const found = /* @__PURE__ */ new Map();
179
+ const isSource = (p) => !path2.relative(skillsDir, p).startsWith("..");
180
+ const walk = (dir, depth) => {
181
+ let entries;
182
+ try {
183
+ entries = fs2.readdirSync(dir, { withFileTypes: true });
184
+ } catch {
185
+ return;
186
+ }
187
+ for (const entry of entries) {
188
+ if (!entry.isDirectory() || SKILL_SCAN_SKIP.has(entry.name)) continue;
189
+ const abs = path2.join(dir, entry.name);
190
+ if (wanted.has(entry.name) && fs2.existsSync(path2.join(abs, SKILL_FILE))) {
191
+ if (!isSource(abs)) found.set(entry.name, [...found.get(entry.name) ?? [], abs]);
192
+ continue;
193
+ }
194
+ if (depth < SKILL_SCAN_DEPTH) walk(abs, depth + 1);
195
+ }
196
+ };
197
+ walk(root, 1);
198
+ for (const list of found.values()) list.sort();
199
+ return found;
200
+ }
201
+ function writeSkill(root, skillsDir, name, dest, verb) {
171
202
  fs2.mkdirSync(path2.dirname(dest), { recursive: true });
172
- fs2.cpSync(src, dest, { recursive: true, force: true });
173
- log.ok(`Added skill ${label}/`);
203
+ fs2.cpSync(path2.join(skillsDir, name), dest, { recursive: true, force: true });
204
+ log.ok(`${verb} skill ${displayPath(root, dest)}/`);
205
+ }
206
+ function printSkillList(root, available, placed) {
207
+ const width = Math.max(...available.map((n) => n.length));
208
+ log.info("Bundled skills:");
209
+ for (const name of available) {
210
+ const where = placed.get(name);
211
+ const status = where?.length ? where.map((p) => displayPath(root, p) + "/").join(", ") : "not placed";
212
+ log.info(` ${name.padEnd(width)} ${status}`);
213
+ }
214
+ const missing = available.filter((n) => !placed.get(n)?.length);
215
+ if (missing.length) {
216
+ log.info("");
217
+ log.info("Place the missing ones with: vantage add skill --all [--dir <path>]");
218
+ }
174
219
  return 0;
175
220
  }
176
221
  function addSkill(root, name, all, force, dir) {
@@ -184,15 +229,34 @@ function addSkill(root, name, all, force, dir) {
184
229
  log.error("No skills are bundled with this version of Vantage.");
185
230
  return 1;
186
231
  }
187
- const targets = all ? available : name ? [name] : [];
188
- if (targets.length === 0) {
189
- log.error(`Usage: vantage add skill <name>|--all. Available: ${available.join(", ")}`);
190
- return 1;
191
- }
232
+ const placed = findPlacedSkills(root, available, skillsDir);
233
+ if (!all && !name) return printSkillList(root, available, placed);
192
234
  const destDir = path2.resolve(root, dir ?? ".");
235
+ const targets = all ? available : [name];
193
236
  let failed = 0;
194
237
  for (const target of targets) {
195
- if (copySkill(root, skillsDir, target, force, destDir) !== 0) failed++;
238
+ if (!available.includes(target)) {
239
+ log.error(`Unknown skill "${target}". Available: ${available.join(", ")}`);
240
+ failed++;
241
+ continue;
242
+ }
243
+ const existing = placed.get(target) ?? [];
244
+ if (existing.length > 0 && !force) {
245
+ const where = existing.map((p) => displayPath(root, p) + "/").join(", ");
246
+ log.info(`Skill ${target} is already placed at ${where} \u2014 skipped (--force to refresh).`);
247
+ continue;
248
+ }
249
+ const inDestDir = existing.filter((p) => path2.dirname(p) === destDir);
250
+ const refresh = dir === void 0 ? existing : inDestDir;
251
+ if (refresh.length > 0) {
252
+ for (const dest of refresh) writeSkill(root, skillsDir, target, dest, "Updated");
253
+ continue;
254
+ }
255
+ if (existing.length > 0) {
256
+ const where = existing.map((p) => displayPath(root, p) + "/").join(", ");
257
+ log.warn(`Skill ${target} is also placed at ${where} \u2014 left untouched.`);
258
+ }
259
+ writeSkill(root, skillsDir, target, path2.join(destDir, target), "Added");
196
260
  }
197
261
  return failed === 0 ? 0 : 1;
198
262
  }
@@ -1260,6 +1324,7 @@ ${pc3.bold("Commands")}
1260
1324
  check Static verification (routes, boundaries, forbidden files)
1261
1325
  routes Show page and API URL map
1262
1326
  add <kind> <name> Scaffold a page | api | ui | block | skill | agents
1327
+ (add skill with no name lists the skills and where they sit)
1263
1328
  docs [name] Show the bundled guide and component reference
1264
1329
  search <query> Find components and docs by meaning, or by regex
1265
1330
  doctor Environment and installation health checks
@@ -1275,7 +1340,7 @@ ${pc3.bold("Options")}
1275
1340
  --regex Treat the query as a regular expression (search)
1276
1341
  --limit <n> Max results (search, default: 10)
1277
1342
  --all Add every bundled skill (add skill --all) | show every page (docs)
1278
- --dir <path> Destination for skills (add skill, default: project root)
1343
+ --dir <path> Where to place skills when none is found (add skill, default: project root)
1279
1344
  -v, --version Print version
1280
1345
  -h, --help Print this help
1281
1346
  `;