@indigoai-us/hq-cli 5.39.2 → 5.39.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.39.3]
6
+
7
+ ### Fixed
8
+
9
+ - **`hq members invite` no longer errors out on an existing member (HQ-11).**
10
+ Inviting (or `--resend`-ing) an email that is already an active member returns
11
+ `409 MEMBERSHIP_ALREADY_EXISTS`; the command used to print a red error and exit
12
+ `1`, so a re-run just re-fired the server's (correctly captured) 409 and a
13
+ bulk-invite script aborted on an already-member. It now treats that 409 as a
14
+ terminal "already a member" outcome — a plain note, exit `0`, no retry. The
15
+ 409 stays the server's correct signal; only the client's needless re-attempt
16
+ is removed. Sibling to the hq-console fix.
17
+
5
18
  ## [5.39.0]
6
19
 
7
20
  ### Added
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="83c39bc9-e532-580d-bc3a-5f176eb5cba6")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b2b63537-b45f-59d6-8783-172b7edcacd6")}catch(e){}}();
3
3
  import chalk from "chalk";
4
4
  import { ensureCognitoToken } from "../utils/cognito-session.js";
5
5
  import { vaultApiFetch, getCompanyUid } from "../utils/vault-api.js";
@@ -366,6 +366,16 @@ export function registerMembersCommand(program) {
366
366
  }
367
367
  }
368
368
  catch (err) {
369
+ // The target is ALREADY an active member (409 MEMBERSHIP_ALREADY_EXISTS).
370
+ // Terminal, not a failure: the person is already in the company, so
371
+ // there's nothing to invite or retry. Print a plain note and exit 0 —
372
+ // re-attempting just re-fires the server's (correctly captured) 409,
373
+ // and a bulk-invite script shouldn't abort on an already-member. HQ-11.
374
+ if (err instanceof InviteHttpError &&
375
+ err.code === "MEMBERSHIP_ALREADY_EXISTS") {
376
+ console.log(chalk.yellow(`${target.toLowerCase()} is already a member of this company — nothing to do.`));
377
+ return;
378
+ }
369
379
  if (err instanceof InviteHttpError) {
370
380
  console.error(chalk.red(formatInviteHttpError(err.status, err.message, err.code)));
371
381
  process.exit(1);
@@ -451,4 +461,4 @@ export function registerMembersCommand(program) {
451
461
  });
452
462
  }
453
463
  //# sourceMappingURL=members.js.map
454
- //# debugId=83c39bc9-e532-580d-bc3a-5f176eb5cba6
464
+ //# debugId=b2b63537-b45f-59d6-8783-172b7edcacd6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.39.2",
3
+ "version": "5.39.3",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -225,6 +225,31 @@ describe("inviteMember", () => {
225
225
  ).rejects.toBeInstanceOf(InviteHttpError);
226
226
  });
227
227
 
228
+ // HQ-11: inviting an already-active member returns 409 with the machine code
229
+ // MEMBERSHIP_ALREADY_EXISTS. The code must ride on the InviteHttpError so the
230
+ // `invite` command can treat it as a terminal "already a member" (no retry).
231
+ it("surfaces the server `code` (MEMBERSHIP_ALREADY_EXISTS) on the InviteHttpError", async () => {
232
+ fetchSpy.mockResolvedValueOnce(
233
+ jsonResponse(409, {
234
+ error:
235
+ "Membership already exists for person email:alice@example.com in company cmp_acme",
236
+ code: "MEMBERSHIP_ALREADY_EXISTS",
237
+ }),
238
+ );
239
+
240
+ const err = await inviteMember({
241
+ target: "alice@example.com",
242
+ role: "member",
243
+ companyUid: "cmp_acme",
244
+ callerUid: "prs_admin",
245
+ token: "test-token",
246
+ }).catch((e: unknown) => e);
247
+
248
+ expect(err).toBeInstanceOf(InviteHttpError);
249
+ expect((err as InviteHttpError).status).toBe(409);
250
+ expect((err as InviteHttpError).code).toBe("MEMBERSHIP_ALREADY_EXISTS");
251
+ });
252
+
228
253
  it("resolves the token when it is nested on the membership row", async () => {
229
254
  fetchSpy.mockResolvedValueOnce(
230
255
  jsonResponse(200, {
@@ -650,6 +650,22 @@ export function registerMembersCommand(program: Command): void {
650
650
  );
651
651
  }
652
652
  } catch (err) {
653
+ // The target is ALREADY an active member (409 MEMBERSHIP_ALREADY_EXISTS).
654
+ // Terminal, not a failure: the person is already in the company, so
655
+ // there's nothing to invite or retry. Print a plain note and exit 0 —
656
+ // re-attempting just re-fires the server's (correctly captured) 409,
657
+ // and a bulk-invite script shouldn't abort on an already-member. HQ-11.
658
+ if (
659
+ err instanceof InviteHttpError &&
660
+ err.code === "MEMBERSHIP_ALREADY_EXISTS"
661
+ ) {
662
+ console.log(
663
+ chalk.yellow(
664
+ `${target.toLowerCase()} is already a member of this company — nothing to do.`,
665
+ ),
666
+ );
667
+ return;
668
+ }
653
669
  if (err instanceof InviteHttpError) {
654
670
  console.error(
655
671
  chalk.red(