skillstogether 0.1.5 → 0.1.7

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 (3) hide show
  1. package/README.md +13 -4
  2. package/dist/index.js +272 -169
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -45,9 +45,7 @@ npx skillstogether add <organization-slug>
45
45
  # Install all skills without prompts
46
46
  npx skillstogether add <organization-slug> -y
47
47
 
48
- # Install a specific skill
49
- npx skillstogether add <organization-slug>/<skill-slug>
50
- # or
48
+ # Install a specific skill (skill slugs already include the org prefix)
51
49
  npx skillstogether add <organization-slug> --skill <skill-slug>
52
50
 
53
51
  # Install globally (in home directory)
@@ -60,6 +58,17 @@ npx skillstogether add <organization-slug> --force
60
58
  npx skillstogether add <organization-slug> --dir ./my-skills
61
59
  ```
62
60
 
61
+ ### Uninstalling Skills
62
+
63
+ ```bash
64
+ # Uninstall all skills from an organization
65
+ npx skillstogether uninstall <organization-slug>
66
+
67
+ # Uninstall a specific skill (skill slug already includes the org prefix)
68
+ npx skillstogether uninstall <organization-slug> --skill <skill-slug>
69
+
70
+ ```
71
+
63
72
  ### Options
64
73
 
65
74
  | Option | Alias | Description |
@@ -67,7 +76,7 @@ npx skillstogether add <organization-slug> --dir ./my-skills
67
76
  | `--dir <path>` | `-d` | Custom installation directory |
68
77
  | `--force` | `-f` | Overwrite existing skill files |
69
78
  | `--yes` | `-y` | Skip interactive prompts, install all |
70
- | `--skill <slug>` | — | Install a specific skill by slug |
79
+ | `--skill <slug>` | — | Install a specific skill by slug (org-prefixed) |
71
80
  | `--global` | — | Install globally (in home directory) |
72
81
 
73
82
  ---
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import { Command as Command8 } from "commander";
4
+ import { Command as Command9 } from "commander";
5
5
 
6
6
  // src/commands/add.ts
7
7
  import * as p2 from "@clack/prompts";
@@ -278,6 +278,13 @@ function trackDownloads(events) {
278
278
  }).catch(() => {
279
279
  });
280
280
  }
281
+ async function submitSkillResult(organizationSlug, skillSlug, result) {
282
+ return apiPost(`/cli/skills/${encodeURIComponent(skillSlug)}/results`, {
283
+ organizationSlug,
284
+ skillSlug,
285
+ body: result
286
+ });
287
+ }
281
288
 
282
289
  // src/lib/errors.ts
283
290
  var DEFAULT_ERROR_MESSAGE = "Unknown error";
@@ -309,9 +316,11 @@ var skillSlugSchema = z.string().min(1, "Skill slug is required").max(100).regex
309
316
  var addTargetSchema = z.string().min(1, "Target is required").refine(
310
317
  (val) => {
311
318
  const parts = val.split("/");
312
- return parts.length >= 1 && parts.length <= 2;
319
+ return parts.length === 1;
313
320
  },
314
- { message: "Target must be 'org-slug' or 'org-slug/skill-slug'" }
321
+ {
322
+ message: "Target must be an organization slug (no '/'). Use --skill to target a specific skill."
323
+ }
315
324
  ).refine(
316
325
  (val) => {
317
326
  const parts = val.split("/");
@@ -330,20 +339,17 @@ var updateTargetSchema = z.string().max(200).optional().refine(
330
339
  var uninstallTargetSchema = z.string().min(1, "Target is required").refine(
331
340
  (val) => {
332
341
  const parts = val.split("/");
333
- return parts.length >= 1 && parts.length <= 2 && parts.every((part) => slugRegex.test(part));
342
+ return parts.length === 1 && parts.every((part) => slugRegex.test(part));
334
343
  },
335
- { message: "Target must be 'org-slug' or 'org-slug/skill-slug'" }
344
+ {
345
+ message: "Target must be an organization slug (no '/'). Use --skill to target a specific skill."
346
+ }
336
347
  );
337
- var agentSchema = z.string().min(1).max(50);
338
348
  var customDirSchema = z.string().min(1).max(4096);
339
349
  function parseAddTarget(target) {
340
350
  const parsed = addTargetSchema.parse(target);
341
- const parts = parsed.split("/");
342
- const organizationSlug = organizationSlugSchema.parse(parts[0]);
343
- return {
344
- organizationSlug,
345
- skillSlug: parts.length === 2 ? parts[1] : void 0
346
- };
351
+ const organizationSlug = organizationSlugSchema.parse(parsed);
352
+ return { organizationSlug };
347
353
  }
348
354
  function parseUpdateTarget(target) {
349
355
  if (target === void 0 || target === "") return {};
@@ -357,10 +363,8 @@ function parseUpdateTarget(target) {
357
363
  }
358
364
  function parseUninstallTarget(target) {
359
365
  const parsed = uninstallTargetSchema.parse(target);
360
- const parts = parsed.split("/");
361
366
  return {
362
- organizationSlug: parts[0],
363
- skillSlug: parts.length === 2 ? parts[1] : void 0
367
+ organizationSlug: parsed
364
368
  };
365
369
  }
366
370
  function isValidSlug(slug) {
@@ -411,7 +415,10 @@ async function downloadFile(url) {
411
415
  timeout: DEFAULT_REQUEST_TIMEOUT_MS
412
416
  });
413
417
  }
414
- var SKILL_FOLDER_PATTERN = (organizationSlug, skillSlug) => `${organizationSlug}-${skillSlug}`;
418
+ var SKILL_FOLDER_PATTERN = (organizationSlug, skillSlug) => {
419
+ const prefix = `${organizationSlug}-`;
420
+ return skillSlug.startsWith(prefix) ? skillSlug : `${prefix}${skillSlug}`;
421
+ };
415
422
  var SKILL_FILENAME = "SKILL.md";
416
423
  async function installSkill(skill, organizationSlug, options) {
417
424
  if (!isValidSlug(organizationSlug)) {
@@ -1213,7 +1220,10 @@ function buildDownloadEvents(allResults, skills, scopeLabel) {
1213
1220
  }
1214
1221
  return events;
1215
1222
  }
1216
- var addCommand = new Command("add").description("Install skills from an organization").argument("<target>", "Organization slug or organization/skill slug").option("-d, --dir <path>", "Custom installation directory").option("-f, --force", "Overwrite existing skill files", false).option("-y, --yes", "Skip interactive prompts and install all skills", false).option("--skill <slug>", "Install a specific skill by slug").option("--global", "Install globally (in home directory)", false).option(
1223
+ var addCommand = new Command("add").description("Install skills from an organization").argument("<target>", "Organization slug").option("-d, --dir <path>", "Custom installation directory").option("-f, --force", "Overwrite existing skill files", false).option("-y, --yes", "Skip interactive prompts and install all skills", false).option(
1224
+ "--skill <slug>",
1225
+ "Install a specific skill by slug (already org-prefixed, e.g. acme-onboarding)"
1226
+ ).option("--global", "Install globally (in home directory)", false).option(
1217
1227
  "--target <agents>",
1218
1228
  "Comma-separated list of agent IDs to install to (e.g., claude-code,cursor)"
1219
1229
  ).action(
@@ -1237,13 +1247,7 @@ var addCommand = new Command("add").description("Install skills from an organiza
1237
1247
  p2.outro(pc3.red("Invalid format"));
1238
1248
  process.exit(1);
1239
1249
  }
1240
- if (parsed.skillSlug !== void 0) {
1241
- await installSingleSkill(
1242
- parsed.organizationSlug,
1243
- parsed.skillSlug,
1244
- options
1245
- );
1246
- } else if (options.skill) {
1250
+ if (options.skill) {
1247
1251
  const skillResult = skillSlugSchema.safeParse(options.skill);
1248
1252
  if (!skillResult.success) {
1249
1253
  const msg = skillResult.error.issues?.[0]?.message ?? skillResult.error.message ?? "Invalid skill slug";
@@ -1251,6 +1255,14 @@ var addCommand = new Command("add").description("Install skills from an organiza
1251
1255
  p2.outro(pc3.red("Invalid format"));
1252
1256
  process.exit(1);
1253
1257
  }
1258
+ const expectedPrefix = `${parsed.organizationSlug}-`;
1259
+ if (!skillResult.data.startsWith(expectedPrefix)) {
1260
+ p2.log.error(
1261
+ `Skill slug must be prefixed with the organization slug (e.g., ${pc3.cyan(`${expectedPrefix}my-skill`)})`
1262
+ );
1263
+ p2.outro(pc3.red("Invalid format"));
1264
+ process.exit(1);
1265
+ }
1254
1266
  await installSingleSkill(
1255
1267
  parsed.organizationSlug,
1256
1268
  skillResult.data,
@@ -2108,33 +2120,115 @@ var doctorCommand = new Command3("doctor").description("Diagnose and fix common
2108
2120
  }
2109
2121
  });
2110
2122
 
2111
- // src/commands/list.ts
2123
+ // src/commands/feedback.ts
2112
2124
  import * as p5 from "@clack/prompts";
2113
2125
  import { Command as Command4 } from "commander";
2114
2126
  import pc6 from "picocolors";
2127
+ var feedbackCommand = new Command4("feedback").description("Submit feedback for a skill after task completion").argument(
2128
+ "<skillSlug>",
2129
+ "Skill slug (already org-prefixed, e.g., 'acme-onboarding')"
2130
+ ).option("-s, --success", "Task completed successfully", true).option("-f, --failed", "Task failed").option("-q, --quality <rating>", "Quality rating 1-5", parseInt).option("-t, --time <seconds>", "Time spent in seconds", parseInt).option("-c, --files-count <count>", "Number of files modified", parseInt).option("-m, --summary <text>", "Brief summary of what was accomplished").option("--challenges <text>", "Difficulties encountered").option("-a, --agent <agent>", "Agent used (e.g., 'cursor', 'claude')").action(async (skillSlug, options) => {
2131
+ printCompactBanner();
2132
+ p5.intro(pc6.bgCyan(pc6.black(" Skill Feedback ")));
2133
+ const token = getToken();
2134
+ if (!token) {
2135
+ p5.log.error("Not authenticated. Run 'auth login' first.");
2136
+ p5.outro(pc6.red("\u2717 Failed"));
2137
+ process.exit(1);
2138
+ }
2139
+ const slugResult = skillSlugSchema.safeParse(skillSlug);
2140
+ if (!slugResult.success) {
2141
+ const msg = slugResult.error.issues?.[0]?.message ?? slugResult.error.message ?? "Invalid skill slug";
2142
+ p5.log.error(msg);
2143
+ p5.outro(pc6.red("\u2717 Failed"));
2144
+ process.exit(1);
2145
+ }
2146
+ const installedSkills = scanInstalledSkills({});
2147
+ const matches = installedSkills.filter((s2) => s2.slug === skillSlug);
2148
+ const organizations = new Set(
2149
+ matches.map((match) => match.organization).filter(Boolean)
2150
+ );
2151
+ if (organizations.size === 0) {
2152
+ p5.log.error(`Skill ${pc6.cyan(skillSlug)} not found in installed skills.`);
2153
+ p5.log.info(
2154
+ `Install it first, then retry. Example: ${pc6.cyan(`npx skillstogether add <org-slug> --skill ${skillSlug}`)}`
2155
+ );
2156
+ p5.outro(pc6.red("\u2717 Failed"));
2157
+ process.exit(1);
2158
+ }
2159
+ if (organizations.size > 1) {
2160
+ p5.log.error(
2161
+ `Multiple organizations found for ${pc6.cyan(skillSlug)}: ${pc6.cyan(
2162
+ Array.from(organizations).join(", ")
2163
+ )}`
2164
+ );
2165
+ p5.log.info("Use the org-prefixed skill slug to disambiguate.");
2166
+ p5.outro(pc6.red("\u2717 Failed"));
2167
+ process.exit(1);
2168
+ }
2169
+ const organizationSlug = Array.from(organizations)[0];
2170
+ if (options.quality !== void 0 && (options.quality < 1 || options.quality > 5)) {
2171
+ p5.log.error("Quality rating must be between 1 and 5");
2172
+ p5.outro(pc6.red("\u2717 Failed"));
2173
+ process.exit(1);
2174
+ }
2175
+ const result = {
2176
+ success: !options.failed,
2177
+ quality: options.quality,
2178
+ timeSeconds: options.time,
2179
+ filesCount: options.filesCount,
2180
+ summary: options.summary,
2181
+ challenges: options.challenges,
2182
+ agent: options.agent
2183
+ };
2184
+ const s = p5.spinner();
2185
+ s.start(
2186
+ `Submitting feedback for ${pc6.cyan(`${organizationSlug}/${skillSlug}`)}`
2187
+ );
2188
+ try {
2189
+ const response = await submitSkillResult(
2190
+ organizationSlug,
2191
+ skillSlug,
2192
+ result
2193
+ );
2194
+ s.stop(`Feedback submitted`);
2195
+ p5.log.success(response.message);
2196
+ p5.outro(pc6.green("\u2713 Feedback recorded!"));
2197
+ } catch (error) {
2198
+ s.stop("Failed to submit feedback");
2199
+ p5.log.error(error instanceof Error ? error.message : "Unknown error");
2200
+ p5.outro(pc6.red("\u2717 Failed"));
2201
+ process.exit(1);
2202
+ }
2203
+ });
2204
+
2205
+ // src/commands/list.ts
2206
+ import * as p6 from "@clack/prompts";
2207
+ import { Command as Command5 } from "commander";
2208
+ import pc7 from "picocolors";
2115
2209
  function displaySkillsTable(skills) {
2116
2210
  if (skills.length === 0) {
2117
- p5.log.info(pc6.dim("No skills installed"));
2211
+ p6.log.info(pc7.dim("No skills installed"));
2118
2212
  return;
2119
2213
  }
2120
2214
  const byOrg = groupSkillsByOrganization(skills);
2121
2215
  for (const [org, orgSkills] of byOrg) {
2122
2216
  console.log();
2123
- console.log(pc6.cyan(` ${org}/`));
2217
+ console.log(pc7.cyan(` ${org}/`));
2124
2218
  for (const skill of orgSkills) {
2125
- const agentBadge = pc6.dim(`[${skill.agent.name}]`);
2126
- const scopeBadge = skill.scope === "global" ? pc6.yellow("(global)") : pc6.dim("(project)");
2127
- const versionStr = skill.version ? pc6.dim(`v${skill.version}`) : "";
2219
+ const agentBadge = pc7.dim(`[${skill.agent.name}]`);
2220
+ const scopeBadge = skill.scope === "global" ? pc7.yellow("(global)") : pc7.dim("(project)");
2221
+ const versionStr = skill.version ? pc7.dim(`v${skill.version}`) : "";
2128
2222
  console.log(
2129
- ` ${pc6.white(skill.name)} ${versionStr} ${agentBadge} ${scopeBadge}`
2223
+ ` ${pc7.white(skill.name)} ${versionStr} ${agentBadge} ${scopeBadge}`
2130
2224
  );
2131
- console.log(pc6.dim(` ${shortenPath(skill.path)}`));
2225
+ console.log(pc7.dim(` ${shortenPath(skill.path)}`));
2132
2226
  }
2133
2227
  }
2134
2228
  }
2135
2229
  function displaySkillsByAgent(skills) {
2136
2230
  if (skills.length === 0) {
2137
- p5.log.info(pc6.dim("No skills installed"));
2231
+ p6.log.info(pc7.dim("No skills installed"));
2138
2232
  return;
2139
2233
  }
2140
2234
  const byAgent = groupSkillsByAgent(skills);
@@ -2142,26 +2236,26 @@ function displaySkillsByAgent(skills) {
2142
2236
  const agentConfig = AGENTS.find((a) => a.id === agent);
2143
2237
  const agentName = agentConfig?.name || agent;
2144
2238
  console.log();
2145
- console.log(pc6.cyan(` ${agentName}`));
2239
+ console.log(pc7.cyan(` ${agentName}`));
2146
2240
  for (const skill of agentSkills) {
2147
- const scopeBadge = skill.scope === "global" ? pc6.yellow("(global)") : pc6.dim("(project)");
2241
+ const scopeBadge = skill.scope === "global" ? pc7.yellow("(global)") : pc7.dim("(project)");
2148
2242
  console.log(
2149
- ` ${pc6.white(`${skill.organization}/${skill.slug}`)} ${scopeBadge}`
2243
+ ` ${pc7.white(`${skill.organization}/${skill.slug}`)} ${scopeBadge}`
2150
2244
  );
2151
2245
  }
2152
2246
  }
2153
2247
  }
2154
- var listCommand = new Command4("list").description("List installed skills").option("--global", "Show only globally installed skills").option("--project", "Show only project-installed skills").option("--agent <id>", "Show only skills for a specific agent").option("--by-agent", "Group output by agent instead of organization").action(
2248
+ var listCommand = new Command5("list").description("List installed skills").option("--global", "Show only globally installed skills").option("--project", "Show only project-installed skills").option("--agent <id>", "Show only skills for a specific agent").option("--by-agent", "Group output by agent instead of organization").action(
2155
2249
  async (options) => {
2156
2250
  printCompactBanner();
2157
- p5.intro(pc6.bgCyan(pc6.black(" Installed Skills ")));
2251
+ p6.intro(pc7.bgCyan(pc7.black(" Installed Skills ")));
2158
2252
  let scope;
2159
2253
  if (options.global && !options.project) {
2160
2254
  scope = "global";
2161
2255
  } else if (options.project && !options.global) {
2162
2256
  scope = "project";
2163
2257
  }
2164
- const s = p5.spinner();
2258
+ const s = p6.spinner();
2165
2259
  s.start("Scanning for installed skills...");
2166
2260
  const skills = scanInstalledSkills({
2167
2261
  scope,
@@ -2170,15 +2264,15 @@ var listCommand = new Command4("list").description("List installed skills").opti
2170
2264
  const uniqueSkills = deduplicateSkills(skills);
2171
2265
  const uniqueCount = uniqueSkills.length;
2172
2266
  const totalInstances = skills.length;
2173
- const countDisplay = uniqueCount === totalInstances ? `${pc6.green(uniqueCount.toString())} skill${uniqueCount !== 1 ? "s" : ""}` : `${pc6.green(uniqueCount.toString())} unique skill${uniqueCount !== 1 ? "s" : ""} (${totalInstances} installations)`;
2267
+ const countDisplay = uniqueCount === totalInstances ? `${pc7.green(uniqueCount.toString())} skill${uniqueCount !== 1 ? "s" : ""}` : `${pc7.green(uniqueCount.toString())} unique skill${uniqueCount !== 1 ? "s" : ""} (${totalInstances} installations)`;
2174
2268
  s.stop(`Found ${countDisplay}`);
2175
2269
  if (skills.length === 0) {
2176
- p5.log.info(
2177
- pc6.dim(
2270
+ p6.log.info(
2271
+ pc7.dim(
2178
2272
  "No skills found. Install skills with: npx skillstogether add <org-slug>"
2179
2273
  )
2180
2274
  );
2181
- p5.outro(pc6.dim("Done"));
2275
+ p6.outro(pc7.dim("Done"));
2182
2276
  return;
2183
2277
  }
2184
2278
  if (options.byAgent) {
@@ -2193,21 +2287,21 @@ var listCommand = new Command4("list").description("List installed skills").opti
2193
2287
  ).length;
2194
2288
  const orgCount = new Set(uniqueSkills.map((s2) => s2.organization)).size;
2195
2289
  const agentCount = new Set(skills.map((s2) => s2.agent.id)).size;
2196
- p5.log.info(
2197
- pc6.dim(
2290
+ p6.log.info(
2291
+ pc7.dim(
2198
2292
  `${uniqueCount} unique skill${uniqueCount !== 1 ? "s" : ""}, ${orgCount} organization${orgCount !== 1 ? "s" : ""}, ${agentCount} agent${agentCount !== 1 ? "s" : ""}, ${globalCount} global, ${projectCount} project`
2199
2293
  )
2200
2294
  );
2201
- p5.outro(pc6.dim("Done"));
2295
+ p6.outro(pc7.dim("Done"));
2202
2296
  }
2203
2297
  );
2204
2298
 
2205
2299
  // src/commands/status.ts
2206
- import * as p6 from "@clack/prompts";
2207
- import { Command as Command5 } from "commander";
2208
- import pc7 from "picocolors";
2300
+ import * as p7 from "@clack/prompts";
2301
+ import { Command as Command6 } from "commander";
2302
+ import pc8 from "picocolors";
2209
2303
  function formatDate(dateStr) {
2210
- if (!dateStr) return pc7.dim("unknown");
2304
+ if (!dateStr) return pc8.dim("unknown");
2211
2305
  try {
2212
2306
  const date = new Date(dateStr);
2213
2307
  return date.toLocaleDateString("en-US", {
@@ -2218,7 +2312,7 @@ function formatDate(dateStr) {
2218
2312
  minute: "2-digit"
2219
2313
  });
2220
2314
  } catch {
2221
- return pc7.dim("invalid");
2315
+ return pc8.dim("invalid");
2222
2316
  }
2223
2317
  }
2224
2318
  function groupByOrganization(skills) {
@@ -2230,16 +2324,16 @@ function groupByOrganization(skills) {
2230
2324
  }
2231
2325
  return groups;
2232
2326
  }
2233
- var statusCommand = new Command5("status").description("Check for skill updates").argument("[org-slug]", "Organization to check (optional)").option("--global", "Check only globally installed skills").option("--project", "Check only project-installed skills").action(
2327
+ var statusCommand = new Command6("status").description("Check for skill updates").argument("[org-slug]", "Organization to check (optional)").option("--global", "Check only globally installed skills").option("--project", "Check only project-installed skills").action(
2234
2328
  async (organizationSlug, options) => {
2235
2329
  printCompactBanner();
2236
- p6.intro(pc7.bgCyan(pc7.black(" Check for Updates ")));
2330
+ p7.intro(pc8.bgCyan(pc8.black(" Check for Updates ")));
2237
2331
  const token = getToken();
2238
2332
  if (!token) {
2239
- p6.log.error(
2240
- `Not authenticated. Run ${pc7.cyan("npx skillstogether auth login")} first.`
2333
+ p7.log.error(
2334
+ `Not authenticated. Run ${pc8.cyan("npx skillstogether auth login")} first.`
2241
2335
  );
2242
- p6.outro(pc7.red("Authentication required"));
2336
+ p7.outro(pc8.red("Authentication required"));
2243
2337
  process.exit(1);
2244
2338
  }
2245
2339
  let scope;
@@ -2248,7 +2342,7 @@ var statusCommand = new Command5("status").description("Check for skill updates"
2248
2342
  } else if (options.project && !options.global) {
2249
2343
  scope = "project";
2250
2344
  }
2251
- const s = p6.spinner();
2345
+ const s = p7.spinner();
2252
2346
  s.start("Scanning installed skills...");
2253
2347
  const installedSkills = scanUniqueSkills({
2254
2348
  scope,
@@ -2256,17 +2350,17 @@ var statusCommand = new Command5("status").description("Check for skill updates"
2256
2350
  });
2257
2351
  if (installedSkills.length === 0) {
2258
2352
  s.stop("No installed skills found");
2259
- p6.log.info(
2260
- pc7.dim("Install skills with: npx skillstogether add <org-slug>")
2353
+ p7.log.info(
2354
+ pc8.dim("Install skills with: npx skillstogether add <org-slug>")
2261
2355
  );
2262
- p6.outro(pc7.dim("Done"));
2356
+ p7.outro(pc8.dim("Done"));
2263
2357
  return;
2264
2358
  }
2265
2359
  s.stop(
2266
- `Found ${pc7.green(installedSkills.length.toString())} installed skill${installedSkills.length !== 1 ? "s" : ""}`
2360
+ `Found ${pc8.green(installedSkills.length.toString())} installed skill${installedSkills.length !== 1 ? "s" : ""}`
2267
2361
  );
2268
2362
  const byOrg = groupByOrganization(installedSkills);
2269
- const checkSpinner = p6.spinner();
2363
+ const checkSpinner = p7.spinner();
2270
2364
  checkSpinner.start("Checking for updates...");
2271
2365
  const allUpdates = [];
2272
2366
  const errors = [];
@@ -2291,57 +2385,57 @@ var statusCommand = new Command5("status").description("Check for skill updates"
2291
2385
  );
2292
2386
  if (outdatedSkills.length > 0) {
2293
2387
  console.log();
2294
- p6.log.warn(
2295
- `${pc7.yellow(outdatedSkills.length.toString())} skill${outdatedSkills.length !== 1 ? "s" : ""} ${outdatedSkills.length !== 1 ? "have" : "has"} updates available:`
2388
+ p7.log.warn(
2389
+ `${pc8.yellow(outdatedSkills.length.toString())} skill${outdatedSkills.length !== 1 ? "s" : ""} ${outdatedSkills.length !== 1 ? "have" : "has"} updates available:`
2296
2390
  );
2297
2391
  for (const { org, updates } of allUpdates) {
2298
2392
  const orgOutdated = updates.filter((u) => u.hasUpdate);
2299
2393
  if (orgOutdated.length === 0) continue;
2300
2394
  console.log();
2301
- console.log(pc7.cyan(` ${org}/`));
2395
+ console.log(pc8.cyan(` ${org}/`));
2302
2396
  for (const update of orgOutdated) {
2303
- console.log(` ${pc7.yellow("\u2191")} ${pc7.white(update.name)}`);
2397
+ console.log(` ${pc8.yellow("\u2191")} ${pc8.white(update.name)}`);
2304
2398
  console.log(
2305
- ` Installed: ${pc7.dim(formatDate(update.installedAt))}`
2399
+ ` Installed: ${pc8.dim(formatDate(update.installedAt))}`
2306
2400
  );
2307
2401
  console.log(
2308
- ` Available: ${pc7.green(formatDate(update.updatedAt))} ${pc7.dim(`(v${update.currentVersion})`)}`
2402
+ ` Available: ${pc8.green(formatDate(update.updatedAt))} ${pc8.dim(`(v${update.currentVersion})`)}`
2309
2403
  );
2310
2404
  }
2311
2405
  }
2312
2406
  console.log();
2313
- p6.log.info(
2314
- `Run ${pc7.cyan("npx skillstogether update")} to update all skills`
2407
+ p7.log.info(
2408
+ `Run ${pc8.cyan("npx skillstogether update")} to update all skills`
2315
2409
  );
2316
2410
  if (organizationSlug) {
2317
- p6.log.info(
2318
- `Or ${pc7.cyan(`npx skillstogether update ${organizationSlug}`)} to update this organization only`
2411
+ p7.log.info(
2412
+ `Or ${pc8.cyan(`npx skillstogether update ${organizationSlug}`)} to update this organization only`
2319
2413
  );
2320
2414
  }
2321
2415
  } else {
2322
- p6.log.success(
2323
- `All ${pc7.green(upToDateSkills.length.toString())} skill${upToDateSkills.length !== 1 ? "s are" : " is"} up to date!`
2416
+ p7.log.success(
2417
+ `All ${pc8.green(upToDateSkills.length.toString())} skill${upToDateSkills.length !== 1 ? "s are" : " is"} up to date!`
2324
2418
  );
2325
2419
  }
2326
2420
  if (errors.length > 0) {
2327
2421
  console.log();
2328
- p6.log.error(
2422
+ p7.log.error(
2329
2423
  `Failed to check ${errors.length} organization${errors.length !== 1 ? "s" : ""}:`
2330
2424
  );
2331
2425
  for (const error of errors) {
2332
- console.log(` ${pc7.red("\u2022")} ${error}`);
2426
+ console.log(` ${pc8.red("\u2022")} ${error}`);
2333
2427
  }
2334
2428
  }
2335
- p6.outro(pc7.dim("Done"));
2429
+ p7.outro(pc8.dim("Done"));
2336
2430
  }
2337
2431
  );
2338
2432
 
2339
2433
  // src/commands/uninstall.ts
2340
- import * as p7 from "@clack/prompts";
2341
- import { Command as Command6 } from "commander";
2434
+ import * as p8 from "@clack/prompts";
2435
+ import { Command as Command7 } from "commander";
2342
2436
  import { rmSync } from "fs";
2343
2437
  import { dirname as dirname2 } from "path";
2344
- import pc8 from "picocolors";
2438
+ import pc9 from "picocolors";
2345
2439
  function removeSkill(skill) {
2346
2440
  try {
2347
2441
  const skillDir = dirname2(skill.path);
@@ -2354,10 +2448,13 @@ function removeSkill(skill) {
2354
2448
  };
2355
2449
  }
2356
2450
  }
2357
- var uninstallCommand = new Command6("uninstall").description("Remove installed skills").argument("<target>", "Organization slug or organization/skill slug").option("--all", "Remove all skills from the organization").option("--global", "Remove from global installation only").option("--project", "Remove from project installation only").option("-y, --yes", "Skip confirmation prompts").action(
2451
+ var uninstallCommand = new Command7("uninstall").description("Remove installed skills").argument("<target>", "Organization slug").option("--all", "Remove all skills from the organization").option(
2452
+ "--skill <slug>",
2453
+ "Remove a specific skill by slug (already org-prefixed, e.g. acme-onboarding)"
2454
+ ).option("--global", "Remove from global installation only").option("--project", "Remove from project installation only").option("-y, --yes", "Skip confirmation prompts").action(
2358
2455
  async (target, options) => {
2359
2456
  printCompactBanner();
2360
- p7.intro(pc8.bgCyan(pc8.black(" Uninstall Skills ")));
2457
+ p8.intro(pc9.bgCyan(pc9.black(" Uninstall Skills ")));
2361
2458
  let scope;
2362
2459
  if (options.global && !options.project) {
2363
2460
  scope = "global";
@@ -2369,64 +2466,69 @@ var uninstallCommand = new Command6("uninstall").description("Remove installed s
2369
2466
  parsed = parseUninstallTarget(target);
2370
2467
  } catch (err) {
2371
2468
  const msg = err instanceof Error && "message" in err ? err.message : "Invalid target format";
2372
- p7.log.error(msg);
2373
- p7.outro(pc8.red("Invalid format"));
2469
+ p8.log.error(msg);
2470
+ p8.outro(pc9.red("Invalid format"));
2374
2471
  process.exit(1);
2375
2472
  }
2376
- if (parsed.skillSlug === void 0) {
2377
- if (!options.all) {
2378
- p7.log.error(
2379
- `To uninstall all skills from ${pc8.cyan(parsed.organizationSlug)}, use the ${pc8.cyan("--all")} flag`
2380
- );
2381
- p7.log.info(
2382
- `Or specify a skill: ${pc8.cyan(`npx skillstogether uninstall ${parsed.organizationSlug}/<skill-slug>`)}`
2473
+ if (options.skill) {
2474
+ const skillResult = skillSlugSchema.safeParse(options.skill);
2475
+ if (!skillResult.success) {
2476
+ const msg = skillResult.error.issues?.[0]?.message ?? skillResult.error.message ?? "Invalid skill slug";
2477
+ p8.log.error(msg);
2478
+ p8.outro(pc9.red("Invalid format"));
2479
+ process.exit(1);
2480
+ }
2481
+ const expectedPrefix = `${parsed.organizationSlug}-`;
2482
+ if (!skillResult.data.startsWith(expectedPrefix)) {
2483
+ p8.log.error(
2484
+ `Skill slug must be prefixed with the organization slug (e.g., ${pc9.cyan(`${expectedPrefix}my-skill`)})`
2383
2485
  );
2384
- p7.outro(pc8.red("Aborted"));
2486
+ p8.outro(pc9.red("Invalid format"));
2385
2487
  process.exit(1);
2386
2488
  }
2387
- await uninstallOrganization(parsed.organizationSlug, scope, options.yes);
2388
- } else {
2389
2489
  await uninstallSkill(
2390
2490
  parsed.organizationSlug,
2391
- parsed.skillSlug,
2491
+ skillResult.data,
2392
2492
  scope,
2393
2493
  options.yes
2394
2494
  );
2495
+ return;
2395
2496
  }
2497
+ await uninstallOrganization(parsed.organizationSlug, scope, options.yes);
2396
2498
  }
2397
2499
  );
2398
2500
  async function uninstallOrganization(organizationSlug, scope, skipConfirm) {
2399
- const s = p7.spinner();
2400
- s.start(`Finding skills from ${pc8.cyan(organizationSlug)}...`);
2501
+ const s = p8.spinner();
2502
+ s.start(`Finding skills from ${pc9.cyan(organizationSlug)}...`);
2401
2503
  const skills = scanInstalledSkills({ organization: organizationSlug, scope });
2402
2504
  if (skills.length === 0) {
2403
- s.stop(`No skills found from ${pc8.cyan(organizationSlug)}`);
2404
- p7.outro(pc8.yellow("Nothing to uninstall"));
2505
+ s.stop(`No skills found from ${pc9.cyan(organizationSlug)}`);
2506
+ p8.outro(pc9.yellow("Nothing to uninstall"));
2405
2507
  return;
2406
2508
  }
2407
2509
  s.stop(
2408
- `Found ${pc8.green(skills.length.toString())} skill${skills.length !== 1 ? "s" : ""} from ${pc8.cyan(organizationSlug)}`
2510
+ `Found ${pc9.green(skills.length.toString())} skill${skills.length !== 1 ? "s" : ""} from ${pc9.cyan(organizationSlug)}`
2409
2511
  );
2410
2512
  console.log();
2411
- p7.log.info("Skills to remove:");
2513
+ p8.log.info("Skills to remove:");
2412
2514
  for (const skill of skills) {
2413
- const scopeBadge = skill.scope === "global" ? pc8.yellow("(global)") : pc8.dim("(project)");
2515
+ const scopeBadge = skill.scope === "global" ? pc9.yellow("(global)") : pc9.dim("(project)");
2414
2516
  console.log(
2415
- ` ${pc8.red("\u2022")} ${skill.name} ${pc8.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
2517
+ ` ${pc9.red("\u2022")} ${skill.name} ${pc9.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
2416
2518
  );
2417
2519
  }
2418
2520
  console.log();
2419
2521
  if (!skipConfirm) {
2420
- const confirmed = await p7.confirm({
2522
+ const confirmed = await p8.confirm({
2421
2523
  message: `Remove all ${skills.length} skill${skills.length !== 1 ? "s" : ""} from ${organizationSlug}?`,
2422
2524
  initialValue: false
2423
2525
  });
2424
- if (p7.isCancel(confirmed) || !confirmed) {
2425
- p7.cancel("Uninstall cancelled");
2526
+ if (p8.isCancel(confirmed) || !confirmed) {
2527
+ p8.cancel("Uninstall cancelled");
2426
2528
  process.exit(0);
2427
2529
  }
2428
2530
  }
2429
- const removeSpinner = p7.spinner();
2531
+ const removeSpinner = p8.spinner();
2430
2532
  removeSpinner.start("Removing skills...");
2431
2533
  let removed = 0;
2432
2534
  let failed = 0;
@@ -2442,53 +2544,53 @@ async function uninstallOrganization(organizationSlug, scope, skipConfirm) {
2442
2544
  }
2443
2545
  removeSpinner.stop("Removal complete");
2444
2546
  if (removed > 0) {
2445
- p7.log.success(
2446
- `Removed ${pc8.green(removed.toString())} skill${removed !== 1 ? "s" : ""}`
2547
+ p8.log.success(
2548
+ `Removed ${pc9.green(removed.toString())} skill${removed !== 1 ? "s" : ""}`
2447
2549
  );
2448
2550
  }
2449
2551
  if (failed > 0) {
2450
- p7.log.error(
2451
- `Failed to remove ${pc8.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
2552
+ p8.log.error(
2553
+ `Failed to remove ${pc9.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
2452
2554
  );
2453
2555
  for (const error of errors) {
2454
- p7.log.error(pc8.dim(` ${error}`));
2556
+ p8.log.error(pc9.dim(` ${error}`));
2455
2557
  }
2456
2558
  }
2457
- p7.outro(pc8.dim("Done"));
2559
+ p8.outro(pc9.dim("Done"));
2458
2560
  }
2459
2561
  async function uninstallSkill(organizationSlug, skillSlug, scope, skipConfirm) {
2460
- const s = p7.spinner();
2461
- s.start(`Finding ${pc8.cyan(`${organizationSlug}/${skillSlug}`)}...`);
2562
+ const s = p8.spinner();
2563
+ s.start(`Finding ${pc9.cyan(`${organizationSlug}/${skillSlug}`)}...`);
2462
2564
  const instances = findSkillInstances(organizationSlug, skillSlug, { scope });
2463
2565
  if (instances.length === 0) {
2464
- s.stop(`Skill ${pc8.cyan(`${organizationSlug}/${skillSlug}`)} not found`);
2465
- p7.outro(pc8.yellow("Nothing to uninstall"));
2566
+ s.stop(`Skill ${pc9.cyan(`${organizationSlug}/${skillSlug}`)} not found`);
2567
+ p8.outro(pc9.yellow("Nothing to uninstall"));
2466
2568
  return;
2467
2569
  }
2468
2570
  s.stop(
2469
- `Found ${pc8.green(instances.length.toString())} instance${instances.length !== 1 ? "s" : ""} of ${pc8.cyan(`${organizationSlug}/${skillSlug}`)}`
2571
+ `Found ${pc9.green(instances.length.toString())} instance${instances.length !== 1 ? "s" : ""} of ${pc9.cyan(`${organizationSlug}/${skillSlug}`)}`
2470
2572
  );
2471
2573
  console.log();
2472
- p7.log.info("Instances to remove:");
2574
+ p8.log.info("Instances to remove:");
2473
2575
  for (const skill of instances) {
2474
- const scopeBadge = skill.scope === "global" ? pc8.yellow("(global)") : pc8.dim("(project)");
2576
+ const scopeBadge = skill.scope === "global" ? pc9.yellow("(global)") : pc9.dim("(project)");
2475
2577
  console.log(
2476
- ` ${pc8.red("\u2022")} ${pc8.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
2578
+ ` ${pc9.red("\u2022")} ${pc9.dim(`[${skill.agent.name}]`)} ${scopeBadge}`
2477
2579
  );
2478
- console.log(` ${pc8.dim(shortenPath(skill.path))}`);
2580
+ console.log(` ${pc9.dim(shortenPath(skill.path))}`);
2479
2581
  }
2480
2582
  console.log();
2481
2583
  if (!skipConfirm) {
2482
- const confirmed = await p7.confirm({
2584
+ const confirmed = await p8.confirm({
2483
2585
  message: `Remove ${instances.length} instance${instances.length !== 1 ? "s" : ""} of ${organizationSlug}/${skillSlug}?`,
2484
2586
  initialValue: false
2485
2587
  });
2486
- if (p7.isCancel(confirmed) || !confirmed) {
2487
- p7.cancel("Uninstall cancelled");
2588
+ if (p8.isCancel(confirmed) || !confirmed) {
2589
+ p8.cancel("Uninstall cancelled");
2488
2590
  process.exit(0);
2489
2591
  }
2490
2592
  }
2491
- const removeSpinner = p7.spinner();
2593
+ const removeSpinner = p8.spinner();
2492
2594
  removeSpinner.start("Removing skill...");
2493
2595
  let removed = 0;
2494
2596
  let failed = 0;
@@ -2504,26 +2606,26 @@ async function uninstallSkill(organizationSlug, skillSlug, scope, skipConfirm) {
2504
2606
  }
2505
2607
  removeSpinner.stop("Removal complete");
2506
2608
  if (removed > 0) {
2507
- p7.log.success(
2508
- `Removed ${pc8.green(removed.toString())} instance${removed !== 1 ? "s" : ""}`
2609
+ p8.log.success(
2610
+ `Removed ${pc9.green(removed.toString())} instance${removed !== 1 ? "s" : ""}`
2509
2611
  );
2510
2612
  }
2511
2613
  if (failed > 0) {
2512
- p7.log.error(
2513
- `Failed to remove ${pc8.red(failed.toString())} instance${failed !== 1 ? "s" : ""}`
2614
+ p8.log.error(
2615
+ `Failed to remove ${pc9.red(failed.toString())} instance${failed !== 1 ? "s" : ""}`
2514
2616
  );
2515
2617
  for (const error of errors) {
2516
- p7.log.error(pc8.dim(` ${error}`));
2618
+ p8.log.error(pc9.dim(` ${error}`));
2517
2619
  }
2518
2620
  }
2519
- p7.outro(pc8.dim("Done"));
2621
+ p8.outro(pc9.dim("Done"));
2520
2622
  }
2521
2623
 
2522
2624
  // src/commands/update.ts
2523
- import * as p8 from "@clack/prompts";
2524
- import { Command as Command7 } from "commander";
2625
+ import * as p9 from "@clack/prompts";
2626
+ import { Command as Command8 } from "commander";
2525
2627
  import { writeFileSync as writeFileSync3 } from "fs";
2526
- import pc9 from "picocolors";
2628
+ import pc10 from "picocolors";
2527
2629
  function generateUpdatedContent(skill, organizationSlug) {
2528
2630
  const frontmatter = generateFrontmatter({
2529
2631
  name: skill.name,
@@ -2535,16 +2637,16 @@ function generateUpdatedContent(skill, organizationSlug) {
2535
2637
  });
2536
2638
  return frontmatter + "\n" + (skill.content || "");
2537
2639
  }
2538
- var updateCommand = new Command7("update").description("Update installed skills to latest version").argument("[target]", "Organization slug or organization/skill slug").option("--global", "Update only globally installed skills").option("--project", "Update only project-installed skills").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Show what would be updated without making changes").action(
2640
+ var updateCommand = new Command8("update").description("Update installed skills to latest version").argument("[target]", "Organization slug or organization/skill slug").option("--global", "Update only globally installed skills").option("--project", "Update only project-installed skills").option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Show what would be updated without making changes").action(
2539
2641
  async (target, options) => {
2540
2642
  printCompactBanner();
2541
- p8.intro(pc9.bgCyan(pc9.black(" Update Skills ")));
2643
+ p9.intro(pc10.bgCyan(pc10.black(" Update Skills ")));
2542
2644
  const token = getToken();
2543
2645
  if (!token) {
2544
- p8.log.error(
2545
- `Not authenticated. Run ${pc9.cyan("npx skillstogether auth login")} first.`
2646
+ p9.log.error(
2647
+ `Not authenticated. Run ${pc10.cyan("npx skillstogether auth login")} first.`
2546
2648
  );
2547
- p8.outro(pc9.red("Authentication required"));
2649
+ p9.outro(pc10.red("Authentication required"));
2548
2650
  process.exit(1);
2549
2651
  }
2550
2652
  let scope;
@@ -2562,12 +2664,12 @@ var updateCommand = new Command7("update").description("Update installed skills
2562
2664
  skillSlug = parsed.skillSlug;
2563
2665
  } catch (err) {
2564
2666
  const msg = err instanceof Error && "message" in err ? err.message : "Invalid target format";
2565
- p8.log.error(msg);
2566
- p8.outro(pc9.red("Invalid format"));
2667
+ p9.log.error(msg);
2668
+ p9.outro(pc10.red("Invalid format"));
2567
2669
  process.exit(1);
2568
2670
  }
2569
2671
  }
2570
- const s = p8.spinner();
2672
+ const s = p9.spinner();
2571
2673
  s.start("Scanning installed skills...");
2572
2674
  const allInstalledSkills = scanInstalledSkills({
2573
2675
  scope,
@@ -2579,15 +2681,15 @@ var updateCommand = new Command7("update").description("Update installed skills
2579
2681
  }
2580
2682
  if (skillsToCheck.length === 0) {
2581
2683
  s.stop("No installed skills found");
2582
- p8.log.info(
2583
- pc9.dim("Install skills with: npx skillstogether add <org-slug>")
2684
+ p9.log.info(
2685
+ pc10.dim("Install skills with: npx skillstogether add <org-slug>")
2584
2686
  );
2585
- p8.outro(pc9.dim("Done"));
2687
+ p9.outro(pc10.dim("Done"));
2586
2688
  return;
2587
2689
  }
2588
2690
  const uniqueSkills = deduplicateSkills(skillsToCheck);
2589
2691
  s.stop(
2590
- `Found ${pc9.green(uniqueSkills.length.toString())} installed skill${uniqueSkills.length !== 1 ? "s" : ""}`
2692
+ `Found ${pc10.green(uniqueSkills.length.toString())} installed skill${uniqueSkills.length !== 1 ? "s" : ""}`
2591
2693
  );
2592
2694
  const byOrg = /* @__PURE__ */ new Map();
2593
2695
  for (const skill of uniqueSkills) {
@@ -2595,7 +2697,7 @@ var updateCommand = new Command7("update").description("Update installed skills
2595
2697
  existing.push(skill);
2596
2698
  byOrg.set(skill.organization, existing);
2597
2699
  }
2598
- const checkSpinner = p8.spinner();
2700
+ const checkSpinner = p9.spinner();
2599
2701
  checkSpinner.start("Checking for updates...");
2600
2702
  const skillsToUpdate = [];
2601
2703
  const errors = [];
@@ -2624,17 +2726,17 @@ var updateCommand = new Command7("update").description("Update installed skills
2624
2726
  }
2625
2727
  checkSpinner.stop("Update check complete");
2626
2728
  if (skillsToUpdate.length === 0) {
2627
- p8.log.success("All skills are up to date!");
2729
+ p9.log.success("All skills are up to date!");
2628
2730
  if (errors.length > 0) {
2629
2731
  console.log();
2630
- p8.log.error(
2732
+ p9.log.error(
2631
2733
  `Failed to check ${errors.length} organization${errors.length !== 1 ? "s" : ""}:`
2632
2734
  );
2633
2735
  for (const error of errors) {
2634
- console.log(` ${pc9.red("\u2022")} ${error}`);
2736
+ console.log(` ${pc10.red("\u2022")} ${error}`);
2635
2737
  }
2636
2738
  }
2637
- p8.outro(pc9.dim("Done"));
2739
+ p9.outro(pc10.dim("Done"));
2638
2740
  return;
2639
2741
  }
2640
2742
  const totalInstances = skillsToUpdate.reduce(
@@ -2642,33 +2744,33 @@ var updateCommand = new Command7("update").description("Update installed skills
2642
2744
  0
2643
2745
  );
2644
2746
  console.log();
2645
- const updateMsg = skillsToUpdate.length === totalInstances ? `${pc9.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} will be updated:` : `${pc9.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalInstances} installations) will be updated:`;
2646
- p8.log.info(updateMsg);
2747
+ const updateMsg = skillsToUpdate.length === totalInstances ? `${pc10.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} will be updated:` : `${pc10.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalInstances} installations) will be updated:`;
2748
+ p9.log.info(updateMsg);
2647
2749
  for (const { unique, remoteVersion } of skillsToUpdate) {
2648
2750
  const agentNames = unique.agents.map((a) => a.name).join(", ");
2649
- const scopeBadge = unique.scope === "global" ? pc9.yellow("(global)") : pc9.dim("(project)");
2751
+ const scopeBadge = unique.scope === "global" ? pc10.yellow("(global)") : pc10.dim("(project)");
2650
2752
  console.log(
2651
- ` ${pc9.yellow("\u2191")} ${pc9.white(`${unique.organization}/${unique.slug}`)} ${pc9.dim(`v${unique.version || "?"}`)} \u2192 ${pc9.green(`v${remoteVersion}`)} ${pc9.dim(`[${agentNames}]`)} ${scopeBadge}`
2753
+ ` ${pc10.yellow("\u2191")} ${pc10.white(`${unique.organization}/${unique.slug}`)} ${pc10.dim(`v${unique.version || "?"}`)} \u2192 ${pc10.green(`v${remoteVersion}`)} ${pc10.dim(`[${agentNames}]`)} ${scopeBadge}`
2652
2754
  );
2653
2755
  }
2654
2756
  console.log();
2655
2757
  if (options.dryRun) {
2656
- p8.log.info(pc9.dim("Dry run - no changes made"));
2657
- p8.outro(pc9.dim("Done"));
2758
+ p9.log.info(pc10.dim("Dry run - no changes made"));
2759
+ p9.outro(pc10.dim("Done"));
2658
2760
  return;
2659
2761
  }
2660
2762
  if (!options.yes) {
2661
2763
  const confirmMsg = skillsToUpdate.length === totalInstances ? `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""}?` : `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalInstances} installations)?`;
2662
- const confirmed = await p8.confirm({
2764
+ const confirmed = await p9.confirm({
2663
2765
  message: confirmMsg,
2664
2766
  initialValue: true
2665
2767
  });
2666
- if (p8.isCancel(confirmed) || !confirmed) {
2667
- p8.cancel("Update cancelled");
2768
+ if (p9.isCancel(confirmed) || !confirmed) {
2769
+ p9.cancel("Update cancelled");
2668
2770
  process.exit(0);
2669
2771
  }
2670
2772
  }
2671
- const updateSpinner = p8.spinner();
2773
+ const updateSpinner = p9.spinner();
2672
2774
  updateSpinner.start("Updating skills...");
2673
2775
  let updatedSkills = 0;
2674
2776
  let updatedInstances = 0;
@@ -2692,23 +2794,23 @@ var updateCommand = new Command7("update").description("Update installed skills
2692
2794
  }
2693
2795
  updateSpinner.stop("Update complete");
2694
2796
  if (updatedSkills > 0) {
2695
- const summaryMsg = updatedSkills === updatedInstances ? `Updated ${pc9.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""}` : `Updated ${pc9.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""} (${updatedInstances} installations)`;
2696
- p8.log.success(summaryMsg);
2797
+ const summaryMsg = updatedSkills === updatedInstances ? `Updated ${pc10.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""}` : `Updated ${pc10.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""} (${updatedInstances} installations)`;
2798
+ p9.log.success(summaryMsg);
2697
2799
  }
2698
2800
  if (failed > 0) {
2699
- p8.log.error(
2700
- `Failed to update ${pc9.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
2801
+ p9.log.error(
2802
+ `Failed to update ${pc10.red(failed.toString())} skill${failed !== 1 ? "s" : ""}`
2701
2803
  );
2702
2804
  for (const error of updateErrors) {
2703
- console.log(` ${pc9.red("\u2022")} ${error}`);
2805
+ console.log(` ${pc10.red("\u2022")} ${error}`);
2704
2806
  }
2705
2807
  }
2706
- p8.outro(pc9.dim("Done"));
2808
+ p9.outro(pc10.dim("Done"));
2707
2809
  }
2708
2810
  );
2709
2811
 
2710
2812
  // src/index.ts
2711
- var program = new Command8();
2813
+ var program = new Command9();
2712
2814
  program.name("skillstogether").description("CLI tool to install organization skills").version("0.1.0").hook("preAction", (thisCommand) => {
2713
2815
  const commandName = thisCommand.name();
2714
2816
  if (commandName === "skillstogether") {
@@ -2724,6 +2826,7 @@ program.helpInformation = function() {
2724
2826
  program.addCommand(authCommand);
2725
2827
  program.addCommand(addCommand);
2726
2828
  program.addCommand(doctorCommand);
2829
+ program.addCommand(feedbackCommand);
2727
2830
  program.addCommand(listCommand);
2728
2831
  program.addCommand(statusCommand);
2729
2832
  program.addCommand(uninstallCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillstogether",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "CLI tool to install skills",
5
5
  "keywords": [
6
6
  "cli",