@ait-co/console-cli 0.1.27 → 0.1.28

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/cli.mjs CHANGED
@@ -2448,7 +2448,7 @@ function optionalPathArray(input, key, configDir) {
2448
2448
  });
2449
2449
  }
2450
2450
  const EMAIL_REGEX = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
2451
- function isValidEmail(v) {
2451
+ function isValidEmail$1(v) {
2452
2452
  return EMAIL_REGEX.test(v.toLowerCase());
2453
2453
  }
2454
2454
  const TITLE_KO_REGEX = /^[가-힣A-Za-z0-9 :·?]+$/;
@@ -2510,7 +2510,7 @@ function validateManifest(raw, configDir) {
2510
2510
  }
2511
2511
  const appName = requireString(raw, "appName");
2512
2512
  const csEmail = requireString(raw, "csEmail");
2513
- if (!isValidEmail(csEmail)) throw new ManifestError("invalid-config", `csEmail is not a valid email address (got ${csEmail})`, "csEmail");
2513
+ if (!isValidEmail$1(csEmail)) throw new ManifestError("invalid-config", `csEmail is not a valid email address (got ${csEmail})`, "csEmail");
2514
2514
  const subtitle = requireString(raw, "subtitle");
2515
2515
  if (subtitle.length > MANIFEST_LIMITS.subtitleMaxChars) throw new ManifestError("invalid-config", `subtitle must be ${MANIFEST_LIMITS.subtitleMaxChars} characters or fewer (got ${subtitle.length})`, "subtitle");
2516
2516
  const description = requireString(raw, "description");
@@ -2792,7 +2792,7 @@ function validateAppName(raw) {
2792
2792
  return true;
2793
2793
  }
2794
2794
  function validateEmail(raw) {
2795
- if (!isValidEmail(raw)) return "not a valid email address";
2795
+ if (!isValidEmail$1(raw)) return "not a valid email address";
2796
2796
  return true;
2797
2797
  }
2798
2798
  function validateSubtitle(raw) {
@@ -8695,6 +8695,46 @@ async function fetchWorkspaceMembers(workspaceId, cookies, opts = {}) {
8695
8695
  if (!Array.isArray(raw)) throw new Error(`Unexpected members shape for workspace=${workspaceId}: not an array`);
8696
8696
  return raw.map((entry, index) => normalizeMember(entry, workspaceId, index));
8697
8697
  }
8698
+ /**
8699
+ * Invite a user by email to the workspace.
8700
+ *
8701
+ * Maps to `POST /workspaces/:wid/invites/send/by-email`. Payload shape is
8702
+ * inferred from static bundle analysis (PR #118); `role` is optional —
8703
+ * omit to use the server default.
8704
+ *
8705
+ * ⚠️ Inferred endpoint: method/path confirmed, payload/response/errorCodes
8706
+ * not live-captured. See docs/api/members.md "Invite 관련 endpoint".
8707
+ */
8708
+ async function inviteMember(workspaceId, email, role, cookies, opts = {}) {
8709
+ const url = `${BASE$1}/workspaces/${workspaceId}/invites/send/by-email`;
8710
+ const body = { email };
8711
+ if (role !== void 0) body.role = role;
8712
+ return { raw: await requestConsoleApi({
8713
+ method: "POST",
8714
+ url,
8715
+ cookies,
8716
+ body,
8717
+ ...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
8718
+ }) };
8719
+ }
8720
+ /**
8721
+ * Remove a member from the workspace by their `bizUserNo`.
8722
+ *
8723
+ * Maps to `DELETE /workspaces/:wid/members/:memberBizUserNo`. The path
8724
+ * param name `memberBizUserNo` is confirmed from bundle analysis (PR #118).
8725
+ * Response body shape is uncaptured; we treat any SUCCESS as success.
8726
+ *
8727
+ * ⚠️ Inferred endpoint: method/path confirmed, response/errorCodes not
8728
+ * live-captured. See docs/api/members.md "DELETE …/members/<memberBizUserNo>".
8729
+ */
8730
+ async function removeMember(workspaceId, memberBizUserNo, cookies, opts = {}) {
8731
+ await requestConsoleApi({
8732
+ method: "DELETE",
8733
+ url: `${BASE$1}/workspaces/${workspaceId}/members/${memberBizUserNo}`,
8734
+ cookies,
8735
+ ...opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}
8736
+ });
8737
+ }
8698
8738
  function normalizeMember(raw, workspaceId, index) {
8699
8739
  if (raw === null || typeof raw !== "object") throw new Error(`Unexpected member entry at index ${index} for workspace=${workspaceId}: not an object`);
8700
8740
  const rec = raw;
@@ -8719,60 +8759,185 @@ function normalizeMember(raw, workspaceId, index) {
8719
8759
  isAdult: Boolean(rec.isAdult)
8720
8760
  };
8721
8761
  }
8762
+ //#endregion
8763
+ //#region src/commands/members.ts
8764
+ const lsCommand$2 = defineCommand({
8765
+ meta: {
8766
+ name: "ls",
8767
+ description: "List members of the selected workspace."
8768
+ },
8769
+ args: {
8770
+ workspace: {
8771
+ type: "string",
8772
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8773
+ },
8774
+ json: {
8775
+ type: "boolean",
8776
+ description: "Emit machine-readable JSON to stdout.",
8777
+ default: false
8778
+ }
8779
+ },
8780
+ async run({ args }) {
8781
+ const ctx = await resolveWorkspaceContext(args);
8782
+ if (!ctx) return;
8783
+ const { session, workspaceId } = ctx;
8784
+ printContextHeader(ctx, { json: args.json });
8785
+ try {
8786
+ const members = await fetchWorkspaceMembers(workspaceId, session.cookies);
8787
+ if (args.json) {
8788
+ emitJson({
8789
+ ok: true,
8790
+ workspaceId,
8791
+ members: members.map((m) => ({
8792
+ bizUserNo: m.bizUserNo,
8793
+ name: m.name,
8794
+ email: m.email,
8795
+ status: m.status,
8796
+ role: m.role,
8797
+ isOwnerDelegationRequested: m.isOwnerDelegationRequested
8798
+ }))
8799
+ });
8800
+ return exitAfterFlush(ExitCode.Ok);
8801
+ }
8802
+ if (members.length === 0) {
8803
+ process.stdout.write(`No members in workspace ${workspaceId}.\n`);
8804
+ return exitAfterFlush(ExitCode.Ok);
8805
+ }
8806
+ for (const m of members) process.stdout.write(`${m.bizUserNo}\t${m.name}\t${m.email}\t${m.role}\t${m.status}\n`);
8807
+ return exitAfterFlush(ExitCode.Ok);
8808
+ } catch (err) {
8809
+ return emitFailureFromError(args.json, err);
8810
+ }
8811
+ }
8812
+ });
8813
+ function isValidEmail(email) {
8814
+ const at = email.indexOf("@");
8815
+ if (at <= 0) return false;
8816
+ const domain = email.slice(at + 1);
8817
+ return domain.length > 0 && domain.includes(".");
8818
+ }
8722
8819
  const membersCommand = defineCommand({
8723
8820
  meta: {
8724
8821
  name: "members",
8725
- description: "Inspect workspace members."
8822
+ description: "Inspect and manage workspace members."
8726
8823
  },
8727
- subCommands: { ls: defineCommand({
8728
- meta: {
8729
- name: "ls",
8730
- description: "List members of the selected workspace."
8731
- },
8732
- args: {
8733
- workspace: {
8734
- type: "string",
8735
- description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8824
+ subCommands: {
8825
+ ls: lsCommand$2,
8826
+ invite: defineCommand({
8827
+ meta: {
8828
+ name: "invite",
8829
+ description: "Invite a user to the workspace by email."
8736
8830
  },
8737
- json: {
8738
- type: "boolean",
8739
- description: "Emit machine-readable JSON to stdout.",
8740
- default: false
8741
- }
8742
- },
8743
- async run({ args }) {
8744
- const ctx = await resolveWorkspaceContext(args);
8745
- if (!ctx) return;
8746
- const { session, workspaceId } = ctx;
8747
- printContextHeader(ctx, { json: args.json });
8748
- try {
8749
- const members = await fetchWorkspaceMembers(workspaceId, session.cookies);
8750
- if (args.json) {
8751
- emitJson({
8752
- ok: true,
8753
- workspaceId,
8754
- members: members.map((m) => ({
8755
- bizUserNo: m.bizUserNo,
8756
- name: m.name,
8757
- email: m.email,
8758
- status: m.status,
8759
- role: m.role,
8760
- isOwnerDelegationRequested: m.isOwnerDelegationRequested
8761
- }))
8831
+ args: {
8832
+ email: {
8833
+ type: "positional",
8834
+ required: true,
8835
+ description: "Email address of the user to invite."
8836
+ },
8837
+ role: {
8838
+ type: "string",
8839
+ description: "Role to assign (default: server default). Example: MEMBER."
8840
+ },
8841
+ workspace: {
8842
+ type: "string",
8843
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8844
+ },
8845
+ json: {
8846
+ type: "boolean",
8847
+ description: "Emit machine-readable JSON to stdout.",
8848
+ default: false
8849
+ }
8850
+ },
8851
+ async run({ args }) {
8852
+ const ctx = await resolveWorkspaceContext(args);
8853
+ if (!ctx) return;
8854
+ const { session, workspaceId } = ctx;
8855
+ printContextHeader(ctx, { json: args.json });
8856
+ const email = String(args.email).trim();
8857
+ if (!isValidEmail(email)) {
8858
+ const message = `<email> must be a valid email address (got ${JSON.stringify(email)})`;
8859
+ if (args.json) emitJson({
8860
+ ok: false,
8861
+ reason: "invalid-email",
8862
+ message
8762
8863
  });
8864
+ else process.stderr.write(`${message}\n`);
8865
+ return exitAfterFlush(ExitCode.Usage);
8866
+ }
8867
+ const role = args.role ? String(args.role).trim() : void 0;
8868
+ try {
8869
+ await inviteMember(workspaceId, email, role, session.cookies);
8870
+ if (args.json) {
8871
+ emitJson({
8872
+ ok: true,
8873
+ workspaceId,
8874
+ email
8875
+ });
8876
+ return exitAfterFlush(ExitCode.Ok);
8877
+ }
8878
+ process.stdout.write(`Invited ${email} to workspace ${workspaceId}.\n`);
8763
8879
  return exitAfterFlush(ExitCode.Ok);
8880
+ } catch (err) {
8881
+ return emitFailureFromError(args.json, err);
8764
8882
  }
8765
- if (members.length === 0) {
8766
- process.stdout.write(`No members in workspace ${workspaceId}.\n`);
8883
+ }
8884
+ }),
8885
+ remove: defineCommand({
8886
+ meta: {
8887
+ name: "remove",
8888
+ description: "Remove a member from the workspace by their bizUserNo."
8889
+ },
8890
+ args: {
8891
+ bizUserNo: {
8892
+ type: "positional",
8893
+ required: true,
8894
+ description: "bizUserNo of the member to remove (from `aitcc members ls`)."
8895
+ },
8896
+ workspace: {
8897
+ type: "string",
8898
+ description: "Workspace ID. Defaults to the selected workspace (`aitcc workspace use`)."
8899
+ },
8900
+ json: {
8901
+ type: "boolean",
8902
+ description: "Emit machine-readable JSON to stdout.",
8903
+ default: false
8904
+ }
8905
+ },
8906
+ async run({ args }) {
8907
+ const ctx = await resolveWorkspaceContext(args);
8908
+ if (!ctx) return;
8909
+ const { session, workspaceId } = ctx;
8910
+ printContextHeader(ctx, { json: args.json });
8911
+ const rawId = String(args.bizUserNo);
8912
+ const parsed = parsePositiveInt$1(rawId);
8913
+ if (parsed === null) {
8914
+ const message = `<bizUserNo> must be a positive integer (got ${JSON.stringify(rawId)})`;
8915
+ if (args.json) emitJson({
8916
+ ok: false,
8917
+ reason: "invalid-id",
8918
+ message
8919
+ });
8920
+ else process.stderr.write(`${message}\n`);
8921
+ return exitAfterFlush(ExitCode.Usage);
8922
+ }
8923
+ try {
8924
+ await removeMember(workspaceId, parsed, session.cookies);
8925
+ if (args.json) {
8926
+ emitJson({
8927
+ ok: true,
8928
+ workspaceId,
8929
+ bizUserNo: parsed
8930
+ });
8931
+ return exitAfterFlush(ExitCode.Ok);
8932
+ }
8933
+ process.stdout.write(`Removed member ${parsed} from workspace ${workspaceId}.\n`);
8767
8934
  return exitAfterFlush(ExitCode.Ok);
8935
+ } catch (err) {
8936
+ return emitFailureFromError(args.json, err);
8768
8937
  }
8769
- for (const m of members) process.stdout.write(`${m.bizUserNo}\t${m.name}\t${m.email}\t${m.role}\t${m.status}\n`);
8770
- return exitAfterFlush(ExitCode.Ok);
8771
- } catch (err) {
8772
- return emitFailureFromError(args.json, err);
8773
8938
  }
8774
- }
8775
- }) }
8939
+ })
8940
+ }
8776
8941
  });
8777
8942
  const BASE = "https://api-public.toss.im/api-public/v3/ipd-thor/api/v1";
8778
8943
  async function fetchNotices(params, cookies, opts = {}) {
@@ -9166,7 +9331,7 @@ function resolveVersion() {
9166
9331
  if (typeof injected === "string" && injected.length > 0) return injected;
9167
9332
  } catch {}
9168
9333
  try {
9169
- return "0.1.27";
9334
+ return "0.1.28";
9170
9335
  } catch {}
9171
9336
  return "0.0.0-dev";
9172
9337
  }