@floomhq/skills 0.2.18 → 0.2.19

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/dist/index.js CHANGED
@@ -2547,7 +2547,7 @@ function isLegacyApiUrl(apiUrl) {
2547
2547
  }
2548
2548
 
2549
2549
  // src/version.ts
2550
- var VERSION = "0.2.18";
2550
+ var VERSION = "0.2.19";
2551
2551
 
2552
2552
  // src/api-client.ts
2553
2553
  var DEFAULT_TIMEOUT_MS = 2e4;
@@ -3104,37 +3104,31 @@ function buildAuthenticatedSkillUrl(appUrl, librarySlug, skillSlug) {
3104
3104
  }
3105
3105
  function buildPublicSkillUrl(appUrl, handle, librarySlug, skillSlug) {
3106
3106
  const base = trimAppUrl(appUrl);
3107
- if (librarySlug !== handle) return null;
3108
- return `${base}/@${handle}/${skillSlug}`;
3107
+ if (librarySlug === handle) return `${base}/@${encodeURIComponent(handle)}/${encodeURIComponent(skillSlug)}`;
3108
+ return `${base}/${encodeURIComponent(librarySlug)}/${encodeURIComponent(skillSlug)}`;
3109
3109
  }
3110
3110
  function buildPublishViewLines(args) {
3111
3111
  const manageUrl = buildAuthenticatedSkillUrl(args.appUrl, args.refRoot, args.slug);
3112
3112
  const publicUrl = buildPublicSkillUrl(args.appUrl, args.handle, args.refRoot, args.slug);
3113
3113
  if (args.visibility === "public") {
3114
3114
  return {
3115
- heading: publicUrl ? "View (public):" : "Manage (workspace skill):",
3116
- primaryUrl: publicUrl ?? manageUrl,
3117
- ...publicUrl ? {} : { note: "Workspace skills stay under their authenticated library URL unless copied to your personal library." },
3115
+ heading: "View (public):",
3116
+ primaryUrl: publicUrl,
3118
3117
  shareUrl: args.shareUrl ?? void 0
3119
3118
  };
3120
3119
  }
3121
3120
  if (args.visibility === "unlisted") {
3122
3121
  return {
3123
- heading: publicUrl ? "View (unlisted - use a share link for unauthenticated access):" : "Manage (unlisted workspace skill):",
3124
- primaryUrl: publicUrl ?? manageUrl,
3125
- ...publicUrl ? {} : { note: "Use the share link for unauthenticated access; workspace detail URLs remain authenticated." },
3122
+ heading: "View (unlisted - use a share link for unauthenticated access):",
3123
+ primaryUrl: publicUrl,
3126
3124
  shareUrl: args.shareUrl ?? void 0
3127
3125
  };
3128
3126
  }
3129
3127
  return {
3130
3128
  heading: "Manage (private - sign in to your workspace):",
3131
3129
  primaryUrl: manageUrl,
3132
- ...publicUrl ? {
3133
- secondaryHeading: "Public URL after you make it public or unlisted:",
3134
- secondaryUrl: publicUrl
3135
- } : {
3136
- note: "Workspace skills stay under their authenticated library URL unless copied to your personal library."
3137
- }
3130
+ secondaryHeading: "Public URL after you make it public or unlisted:",
3131
+ secondaryUrl: publicUrl
3138
3132
  };
3139
3133
  }
3140
3134
 
@@ -3767,9 +3761,30 @@ async function infoCommand(refStr) {
3767
3761
  }
3768
3762
 
3769
3763
  // src/commands/share.ts
3764
+ import prompts2 from "prompts";
3770
3765
  function isValidEmail(email) {
3771
3766
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
3772
3767
  }
3768
+ function isValidRole(role) {
3769
+ return role === "viewer" || role === "editor";
3770
+ }
3771
+ async function confirmShare(refStr, email, role, opts) {
3772
+ if (opts.yes) return;
3773
+ if (!process.stdin.isTTY) {
3774
+ log.err(`Sharing ${refStr} with ${email} requires confirmation. Re-run with --yes to confirm.`);
3775
+ process.exit(1);
3776
+ }
3777
+ const answer = await prompts2({
3778
+ type: "confirm",
3779
+ name: "confirmed",
3780
+ message: `Share ${refStr} with ${email} as ${role}?`,
3781
+ initial: false
3782
+ });
3783
+ if (!answer.confirmed) {
3784
+ log.info("Share cancelled.");
3785
+ process.exit(1);
3786
+ }
3787
+ }
3773
3788
  async function shareCommand(refStr, email, opts = {}) {
3774
3789
  const ref = parseSkillRef(refStr);
3775
3790
  if (!ref) {
@@ -3781,12 +3796,18 @@ async function shareCommand(refStr, email, opts = {}) {
3781
3796
  process.exit(1);
3782
3797
  }
3783
3798
  const role = opts.role ?? "viewer";
3799
+ if (!isValidRole(role)) {
3800
+ log.err(`Invalid role: ${role}. Expected viewer or editor.`);
3801
+ process.exit(1);
3802
+ }
3803
+ await confirmShare(refStr, email, role, opts);
3784
3804
  const r = await api(`/skills/${ref.owner}/${ref.slug}/grants`, {
3785
3805
  method: "POST",
3786
3806
  authRequired: true,
3787
3807
  body: { email, role }
3788
3808
  });
3789
3809
  log.ok(`Shared ${refStr} with ${r.grant.email} as ${r.grant.role}.`);
3810
+ log.info(`Undo: floom unshare ${refStr} ${r.grant.email}`);
3790
3811
  if (r.email_status) log.kv("email", r.email_status);
3791
3812
  }
3792
3813
  async function unshareCommand(refStr, email) {
@@ -4972,7 +4993,7 @@ program.command("pull").description("Pull account/workspace instructions for act
4972
4993
  program.command("pin <ref>").description("Pin a workspace skill for local pull").option("--workspace <slug>", "Workspace slug").option("--target <target>", "claude | codex | cursor | kimi | opencode", "codex").action((ref, opts) => pinCommand(ref, opts));
4973
4994
  program.command("pinned").alias("pins").description("List workspace skills pinned for local pull").option("--workspace <slug>", "Workspace slug").option("--target <target>", "claude | codex | cursor | kimi | opencode", "codex").option("--json", "Emit machine-readable JSON").action((opts) => pinnedCommand(opts));
4974
4995
  program.command("unpin <ref>").description("Unpin a workspace skill for local pull").option("--workspace <slug>", "Workspace slug").option("--target <target>", "claude | codex | cursor | kimi | opencode", "codex").action((ref, opts) => unpinCommand(ref, opts));
4975
- program.command("share <ref> <email>").description("Invite someone to a skill by email.").option("--role <role>", "viewer (default) or editor").action((ref, email, opts) => shareCommand(ref, email, opts));
4996
+ program.command("share <ref> <email>").description("Invite someone to a skill by email.").option("--role <role>", "viewer (default) or editor").option("--yes", "Confirm the share without an interactive prompt").action((ref, email, opts) => shareCommand(ref, email, opts));
4976
4997
  program.command("unshare <ref> <email>").description("Revoke someone's access.").action((ref, email) => unshareCommand(ref, email));
4977
4998
  var linkCmd = program.command("link").description("Create opaque share links for unlisted/public skills");
4978
4999
  linkCmd.command("create <ref>").description("Create a share link URL for a skill.").option("--name <name>", "Optional link label").option("--role <role>", "viewer (default) or editor").action((ref, opts) => linkCreateCommand(ref, opts));
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "0.2.18";
1
+ export const VERSION = "0.2.19";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/skills",
3
- "version": "0.2.18",
3
+ "version": "0.2.19",
4
4
  "description": "Floom CLI — publish, install, sync, and share AI agent skills.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://skills.floom.dev",