@uzolab/skillhub 0.12.0 → 0.13.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.
Files changed (2) hide show
  1. package/dist/bin.js +106 -8
  2. package/package.json +1 -1
package/dist/bin.js CHANGED
@@ -28568,10 +28568,38 @@ var inviteeSchema = external_exports.object({
28568
28568
  }).refine((v) => v.email === void 0 !== (v.githubHandle === void 0), {
28569
28569
  message: "Provide exactly one of email or githubHandle"
28570
28570
  });
28571
+ var inviteDeliverySchema = external_exports.discriminatedUnion("status", [
28572
+ external_exports.object({
28573
+ status: external_exports.literal("sent"),
28574
+ /** The address the message was ADDRESSED to, even when a redirect rewrote it. */
28575
+ to: external_exports.email(),
28576
+ /** True when a non-production redirect sent it somewhere other than `to`. */
28577
+ redirected: external_exports.boolean()
28578
+ }),
28579
+ external_exports.object({
28580
+ status: external_exports.literal("skipped"),
28581
+ reason: external_exports.enum(["no-address", "logged", "not-configured", "mail-disabled"])
28582
+ }),
28583
+ external_exports.object({
28584
+ status: external_exports.literal("rate-limited"),
28585
+ /**
28586
+ * Whole seconds until this caller may cause another message. Always ≥ 1, so a
28587
+ * surface can always state a wait rather than having to hedge about one.
28588
+ */
28589
+ retryAfterSeconds: external_exports.number().int().positive()
28590
+ }),
28591
+ external_exports.object({ status: external_exports.literal("failed"), retryable: external_exports.boolean() })
28592
+ ]);
28571
28593
  var inviteIssuedSchema = external_exports.object({
28572
28594
  invite: inviteSchema,
28573
28595
  /** Shareable redemption link — contains the token; shown once at issuance. */
28574
- inviteUrl: external_exports.url()
28596
+ inviteUrl: external_exports.url(),
28597
+ /**
28598
+ * What the invitation email did. Present on every issuance, including the ones
28599
+ * that mailed nothing, so a caller reports the outcome it was given rather than
28600
+ * the one it intended.
28601
+ */
28602
+ delivery: inviteDeliverySchema
28575
28603
  });
28576
28604
  var create = authedBase.errors(pickErrors("CONFLICT", "PLAN_LIMIT")).route({ method: "POST", path: "/orgs", summary: "Create an organization" }).input(
28577
28605
  external_exports.object({
@@ -28654,11 +28682,29 @@ var membersRemove = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN", "CONF
28654
28682
  userHandle: handleSchema
28655
28683
  })
28656
28684
  ).output(external_exports.object({ removed: external_exports.literal(true) }));
28685
+ var auditList = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN", "PLAN_LIMIT")).route({
28686
+ method: "GET",
28687
+ path: "/orgs/{handle}/audit",
28688
+ summary: "List the organization audit log"
28689
+ }).input(
28690
+ external_exports.object({
28691
+ handle: handleSchema,
28692
+ /** Filter by dotted action name, e.g. `org.members.invite`. */
28693
+ action: external_exports.string().min(1).optional(),
28694
+ /** Filter by acting user handle. */
28695
+ actorHandle: handleSchema.optional(),
28696
+ since: timestampSchema.optional(),
28697
+ until: timestampSchema.optional()
28698
+ }).extend(paginationInputSchema.shape)
28699
+ ).output(paginatedOutputSchema(auditEntrySchema));
28657
28700
  var orgsContract = {
28658
28701
  create,
28659
28702
  get,
28660
28703
  update,
28661
28704
  listMine,
28705
+ audit: {
28706
+ list: auditList
28707
+ },
28662
28708
  members: {
28663
28709
  list: membersList,
28664
28710
  invite: membersInvite,
@@ -28804,7 +28850,7 @@ var grantsInvite = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN", "CONFL
28804
28850
  role: registryRoleSchema
28805
28851
  })
28806
28852
  ).output(inviteIssuedSchema);
28807
- var auditList = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN", "PLAN_LIMIT")).route({
28853
+ var auditList2 = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN", "PLAN_LIMIT")).route({
28808
28854
  method: "GET",
28809
28855
  path: "/registries/{ownerHandle}/{slug}/audit",
28810
28856
  summary: "List the registry audit log"
@@ -28836,7 +28882,7 @@ var registriesContract = {
28836
28882
  invite: grantsInvite
28837
28883
  },
28838
28884
  audit: {
28839
- list: auditList
28885
+ list: auditList2
28840
28886
  },
28841
28887
  reviewQueue
28842
28888
  };
@@ -28877,7 +28923,18 @@ var requestChanges = authedBase.errors(pickErrors("NOT_FOUND", "FORBIDDEN")).rou
28877
28923
  /** The reviewer's optional note to the author (Markdown, ≤16 KiB). */
28878
28924
  message: external_exports.string().trim().min(1).max(16384).optional()
28879
28925
  })
28880
- ).output(reviewDecisionSchema);
28926
+ ).output(
28927
+ external_exports.object({
28928
+ /** The persisted standing decision this call wrote. */
28929
+ decision: reviewDecisionSchema,
28930
+ /**
28931
+ * How many notification rows this call wrote — 0 when there was nobody to
28932
+ * notify, the best-effort inbox write failed, or a retry re-derived rows
28933
+ * that already existed. Never a count of intended recipients.
28934
+ */
28935
+ notifiedCount: external_exports.number().int().nonnegative()
28936
+ })
28937
+ );
28881
28938
  var reviewsContract = {
28882
28939
  comments: {
28883
28940
  list: commentsList,
@@ -37455,7 +37512,7 @@ import { spawn } from "child_process";
37455
37512
  import process4 from "process";
37456
37513
 
37457
37514
  // src/version.ts
37458
- var CLI_VERSION = "0.12.0";
37515
+ var CLI_VERSION = "0.13.0";
37459
37516
 
37460
37517
  // src/commands/login.ts
37461
37518
  var loginOutputSchema = external_exports.object({
@@ -38564,7 +38621,16 @@ var registryOutputSchema = external_exports.discriminatedUnion("action", [
38564
38621
  role: registryRoleSchema,
38565
38622
  invite: inviteSchema,
38566
38623
  /** One-time redemption link — shown once at issuance, like the server does. */
38567
- inviteUrl: external_exports.string()
38624
+ inviteUrl: external_exports.string(),
38625
+ /**
38626
+ * What the invitation email did, exactly as the server reported it.
38627
+ *
38628
+ * Carried rather than dropped because a script consuming this output has the
38629
+ * same question a person does — is the invitee going to hear about this, or do
38630
+ * I have to send them the link? — and the answer is not derivable from
38631
+ * anything else in the payload.
38632
+ */
38633
+ delivery: inviteDeliverySchema
38568
38634
  })
38569
38635
  ]);
38570
38636
  outputSchemaRegistry.register("registry", registryOutputSchema);
@@ -38666,14 +38732,46 @@ async function runRegistryInvite(context, input, client) {
38666
38732
  ref: formatRegistryRef(path19),
38667
38733
  role,
38668
38734
  invite: issued.invite,
38669
- inviteUrl: issued.inviteUrl
38735
+ inviteUrl: issued.inviteUrl,
38736
+ delivery: issued.delivery
38670
38737
  };
38671
38738
  context.output.result(payload, (colors) => {
38672
38739
  const who = "email" in invitee ? invitee.email : `@${invitee.githubHandle}`;
38673
- return `${colors.green("\u2713")} invited ${who} to ${formatRegistryRef(path19)} as ${role}
38740
+ const headline = issued.delivery.status === "sent" && !issued.delivery.redirected ? `${colors.green("\u2713")} invited ${who} to ${formatRegistryRef(path19)} as ${role}` : `${colors.green("\u2713")} invite created for ${who} on ${formatRegistryRef(path19)} as ${role}
38741
+ ${colors.dim(deliveryNote(issued.delivery))}`;
38742
+ return `${headline}
38674
38743
  invite link (share it \u2014 shown only now): ${issued.inviteUrl}`;
38675
38744
  });
38676
38745
  }
38746
+ function deliveryNote(delivery) {
38747
+ switch (delivery.status) {
38748
+ case "sent":
38749
+ return "the email was redirected to a test mailbox, not to the invitee \u2014 send them the link";
38750
+ case "skipped":
38751
+ switch (delivery.reason) {
38752
+ case "no-address":
38753
+ return "a GitHub handle has no email address \u2014 the link is the only way to deliver it";
38754
+ case "logged":
38755
+ return "this environment logs mail instead of sending it \u2014 send them the link";
38756
+ case "not-configured":
38757
+ return "email is not configured on this deployment \u2014 send them the link";
38758
+ case "mail-disabled":
38759
+ return "email is switched off on this deployment \u2014 send them the link";
38760
+ default: {
38761
+ const unreachable = delivery.reason;
38762
+ throw new Error(`unhandled skip reason: ${String(unreachable)}`);
38763
+ }
38764
+ }
38765
+ case "rate-limited":
38766
+ return `no email was sent: this account has emailed too many invitations recently (retry in about ${String(Math.max(1, Math.round(delivery.retryAfterSeconds / 60)))} minutes) \u2014 the invite is valid, so send them the link`;
38767
+ case "failed":
38768
+ return "no email was sent \u2014 the invite is valid, so send them the link";
38769
+ default: {
38770
+ const unreachable = delivery;
38771
+ throw new Error(`unhandled invite delivery: ${JSON.stringify(unreachable)}`);
38772
+ }
38773
+ }
38774
+ }
38677
38775
  var command15 = defineCommand({
38678
38776
  meta: { name: "registry", description: DESCRIPTION10 },
38679
38777
  args: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uzolab/skillhub",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "description": "SkillHub — npm for agent skills: publish, review, and sync SKILL.md packages from registries your team owns.",
5
5
  "keywords": [
6
6
  "agent-skills",