@doist/comms-cli 1.0.0 → 1.2.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 (55) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/commands/channel/add.d.ts +3 -0
  3. package/dist/commands/channel/add.d.ts.map +1 -0
  4. package/dist/commands/channel/add.js +5 -0
  5. package/dist/commands/channel/add.js.map +1 -0
  6. package/dist/commands/channel/archive.d.ts +8 -0
  7. package/dist/commands/channel/archive.d.ts.map +1 -0
  8. package/dist/commands/channel/archive.js +37 -0
  9. package/dist/commands/channel/archive.js.map +1 -0
  10. package/dist/commands/channel/delete.d.ts +8 -0
  11. package/dist/commands/channel/delete.d.ts.map +1 -0
  12. package/dist/commands/channel/delete.js +42 -0
  13. package/dist/commands/channel/delete.js.map +1 -0
  14. package/dist/commands/channel/helpers.d.ts +8 -0
  15. package/dist/commands/channel/helpers.d.ts.map +1 -1
  16. package/dist/commands/channel/helpers.js +19 -2
  17. package/dist/commands/channel/helpers.js.map +1 -1
  18. package/dist/commands/channel/index.d.ts.map +1 -1
  19. package/dist/commands/channel/index.js +125 -1
  20. package/dist/commands/channel/index.js.map +1 -1
  21. package/dist/commands/channel/members.d.ts +5 -0
  22. package/dist/commands/channel/members.d.ts.map +1 -0
  23. package/dist/commands/channel/members.js +57 -0
  24. package/dist/commands/channel/members.js.map +1 -0
  25. package/dist/commands/channel/membership-helpers.d.ts +20 -0
  26. package/dist/commands/channel/membership-helpers.d.ts.map +1 -0
  27. package/dist/commands/channel/membership-helpers.js +125 -0
  28. package/dist/commands/channel/membership-helpers.js.map +1 -0
  29. package/dist/commands/channel/remove.d.ts +3 -0
  30. package/dist/commands/channel/remove.d.ts.map +1 -0
  31. package/dist/commands/channel/remove.js +5 -0
  32. package/dist/commands/channel/remove.js.map +1 -0
  33. package/dist/commands/channel/set.d.ts +7 -0
  34. package/dist/commands/channel/set.d.ts.map +1 -0
  35. package/dist/commands/channel/set.js +79 -0
  36. package/dist/commands/channel/set.js.map +1 -0
  37. package/dist/lib/api.d.ts +2 -0
  38. package/dist/lib/api.d.ts.map +1 -1
  39. package/dist/lib/api.js +12 -0
  40. package/dist/lib/api.js.map +1 -1
  41. package/dist/lib/auth-provider.d.ts.map +1 -1
  42. package/dist/lib/auth-provider.js +2 -0
  43. package/dist/lib/auth-provider.js.map +1 -1
  44. package/dist/lib/errors.d.ts +1 -1
  45. package/dist/lib/errors.d.ts.map +1 -1
  46. package/dist/lib/errors.js.map +1 -1
  47. package/dist/lib/refs.d.ts +20 -0
  48. package/dist/lib/refs.d.ts.map +1 -1
  49. package/dist/lib/refs.js +90 -0
  50. package/dist/lib/refs.js.map +1 -1
  51. package/dist/lib/skills/content.d.ts +1 -1
  52. package/dist/lib/skills/content.d.ts.map +1 -1
  53. package/dist/lib/skills/content.js +13 -0
  54. package/dist/lib/skills/content.js.map +1 -1
  55. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [1.2.0](https://github.com/Doist/comms-cli/compare/v1.1.0...v1.2.0) (2026-05-27)
2
+
3
+ ### Features
4
+
5
+ - **channel:** add delete, archive, unarchive subcommands ([#8](https://github.com/Doist/comms-cli/issues/8)) ([41acfe6](https://github.com/Doist/comms-cli/commit/41acfe6cf5022bb719b9dd4b8d406ce730926867)), closes [#246](https://github.com/Doist/comms-cli/issues/246)
6
+
7
+ ## [1.1.0](https://github.com/Doist/comms-cli/compare/v1.0.0...v1.1.0) (2026-05-27)
8
+
9
+ ### Features
10
+
11
+ - **channel:** channel membership control (members list/add/remove/set) ([#7](https://github.com/Doist/comms-cli/issues/7)) ([2a1e473](https://github.com/Doist/comms-cli/commit/2a1e473fb356fc44ae6bb7fb48f2465a85caad76)), closes [Doist/twist-cli#244](https://github.com/Doist/twist-cli/issues/244)
12
+
1
13
  ## 1.0.0 (2026-05-25)
2
14
 
3
15
  ### Features
@@ -0,0 +1,3 @@
1
+ import { type ChannelMutationOptions } from './membership-helpers.js';
2
+ export declare function addChannelMembers(channelRef: string, refs: string[], options: ChannelMutationOptions): Promise<void>;
3
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,sBAAsB,EAA2B,MAAM,yBAAyB,CAAA;AAE9F,wBAAsB,iBAAiB,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -0,0 +1,5 @@
1
+ import { mutateChannelMembership } from './membership-helpers.js';
2
+ export async function addChannelMembers(channelRef, refs, options) {
3
+ return mutateChannelMembership(channelRef, refs, 'add', options);
4
+ }
5
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../../src/commands/channel/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+B,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AAE9F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,UAAkB,EAClB,IAAc,EACd,OAA+B;IAE/B,OAAO,uBAAuB,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;AACpE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { MutationOptions } from '../../lib/options.js';
2
+ type ArchiveChannelOptions = MutationOptions & {
3
+ workspace?: string;
4
+ };
5
+ export declare function archiveChannel(ref: string, options: ArchiveChannelOptions): Promise<void>;
6
+ export declare function unarchiveChannel(ref: string, options: ArchiveChannelOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=archive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/archive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAI3D,KAAK,qBAAqB,GAAG,eAAe,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAqCrE,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/F;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjG"}
@@ -0,0 +1,37 @@
1
+ import { getCommsClient } from '../../lib/api.js';
2
+ import { formatJson, printDryRun } from '../../lib/output.js';
3
+ import { resolveChannelByRef } from './helpers.js';
4
+ async function setArchiveState(ref, options, archive) {
5
+ const action = archive ? 'archive' : 'unarchive';
6
+ const channel = await resolveChannelByRef(ref, options.workspace);
7
+ if (options.dryRun) {
8
+ printDryRun(`${action} channel`, {
9
+ Channel: `${channel.name} (id:${channel.id})`,
10
+ 'Currently archived': channel.archived ? 'yes' : 'no',
11
+ });
12
+ return;
13
+ }
14
+ if (channel.archived !== archive) {
15
+ const client = await getCommsClient();
16
+ if (archive) {
17
+ await client.channels.archiveChannel(channel.id);
18
+ }
19
+ else {
20
+ await client.channels.unarchiveChannel(channel.id);
21
+ }
22
+ }
23
+ if (options.json) {
24
+ console.log(formatJson({ id: channel.id, archived: archive }));
25
+ return;
26
+ }
27
+ const verb = archive ? 'archived' : 'unarchived';
28
+ const noop = channel.archived === archive ? ' (already in target state)' : '';
29
+ console.log(`Channel "${channel.name}" (id:${channel.id}) ${verb}${noop}.`);
30
+ }
31
+ export async function archiveChannel(ref, options) {
32
+ await setArchiveState(ref, options, true);
33
+ }
34
+ export async function unarchiveChannel(ref, options) {
35
+ await setArchiveState(ref, options, false);
36
+ }
37
+ //# sourceMappingURL=archive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"archive.js","sourceRoot":"","sources":["../../../src/commands/channel/archive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAIlD,KAAK,UAAU,eAAe,CAC1B,GAAW,EACX,OAA8B,EAC9B,OAAgB;IAEhB,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAA;IAChD,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAEjE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,WAAW,CAAC,GAAG,MAAM,UAAU,EAAE;YAC7B,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,GAAG;YAC7C,oBAAoB,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;SACxD,CAAC,CAAA;QACF,OAAM;IACV,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAA;QACrC,IAAI,OAAO,EAAE,CAAC;YACV,MAAM,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACpD,CAAC;aAAM,CAAC;YACJ,MAAM,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACtD,CAAC;IACL,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;QAC9D,OAAM;IACV,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,YAAY,CAAA;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,EAAE,CAAA;IAC7E,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,EAAE,KAAK,IAAI,GAAG,IAAI,GAAG,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAW,EAAE,OAA8B;IAC5E,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,CAAA;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,GAAW,EAAE,OAA8B;IAC9E,MAAM,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;AAC9C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { MutationOptions } from '../../lib/options.js';
2
+ type DeleteChannelOptions = MutationOptions & {
3
+ yes?: boolean;
4
+ workspace?: string;
5
+ };
6
+ export declare function deleteChannel(ref: string, options: DeleteChannelOptions): Promise<void>;
7
+ export {};
8
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/delete.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAI3D,KAAK,oBAAoB,GAAG,eAAe,GAAG;IAAE,GAAG,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnF,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8C7F"}
@@ -0,0 +1,42 @@
1
+ import { CommsRequestError } from '@doist/comms-sdk';
2
+ import { getCommsClient } from '../../lib/api.js';
3
+ import { CliError } from '../../lib/errors.js';
4
+ import { formatJson, printDryRun } from '../../lib/output.js';
5
+ import { resolveChannelByRef } from './helpers.js';
6
+ export async function deleteChannel(ref, options) {
7
+ if (!options.yes && !options.dryRun) {
8
+ if (options.json) {
9
+ throw new CliError('MISSING_YES_FLAG', '--yes is required to execute deletion in --json mode.');
10
+ }
11
+ console.log(`Would delete: ${ref}`);
12
+ console.log('Use --yes to confirm.');
13
+ return;
14
+ }
15
+ const channel = await resolveChannelByRef(ref, options.workspace);
16
+ if (options.dryRun) {
17
+ printDryRun('delete channel', {
18
+ Channel: `${channel.name} (id:${channel.id})`,
19
+ Visibility: channel.public ? 'public' : 'private',
20
+ });
21
+ return;
22
+ }
23
+ const client = await getCommsClient();
24
+ try {
25
+ await client.channels.deleteChannel(channel.id);
26
+ }
27
+ catch (error) {
28
+ if (error instanceof CommsRequestError && error.httpStatusCode === 403) {
29
+ throw new CliError('FORBIDDEN', `Comms refused to delete "${channel.name}" (id:${channel.id}): 403 Forbidden.`, [
30
+ 'Channel deletion is typically restricted to workspace admins',
31
+ 'Ask a workspace admin to delete it, or use the Comms web UI',
32
+ ]);
33
+ }
34
+ throw error;
35
+ }
36
+ if (options.json) {
37
+ console.log(formatJson({ id: channel.id, deleted: true }));
38
+ return;
39
+ }
40
+ console.log(`Channel "${channel.name}" (id:${channel.id}) deleted.`);
41
+ }
42
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../../src/commands/channel/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAIlD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW,EAAE,OAA6B;IAC1E,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAClC,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,IAAI,QAAQ,CACd,kBAAkB,EAClB,uDAAuD,CAC1D,CAAA;QACL,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,EAAE,CAAC,CAAA;QACnC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAA;QACpC,OAAM;IACV,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAEjE,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,WAAW,CAAC,gBAAgB,EAAE;YAC1B,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,GAAG;YAC7C,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;SACpD,CAAC,CAAA;QACF,OAAM;IACV,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,cAAc,EAAE,CAAA;IACrC,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,IAAI,KAAK,YAAY,iBAAiB,IAAI,KAAK,CAAC,cAAc,KAAK,GAAG,EAAE,CAAC;YACrE,MAAM,IAAI,QAAQ,CACd,WAAW,EACX,4BAA4B,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,EAAE,mBAAmB,EAC9E;gBACI,8DAA8D;gBAC9D,6DAA6D;aAChE,CACJ,CAAA;QACL,CAAC;QACD,MAAM,KAAK,CAAA;IACf,CAAC;IAED,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QAC1D,OAAM;IACV,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,IAAI,SAAS,OAAO,CAAC,EAAE,YAAY,CAAC,CAAA;AACxE,CAAC"}
@@ -1,9 +1,17 @@
1
+ import type { Channel } from '@doist/comms-sdk';
1
2
  export declare function validateChannelName(name: string): void;
2
3
  export declare function resolveVisibilityOption(options: {
3
4
  public?: boolean;
4
5
  private?: boolean;
5
6
  }): boolean | undefined;
6
7
  export declare function resolveChannelWorkspaceId(workspaceRef: string | undefined): Promise<number>;
8
+ /**
9
+ * Resolve a channel for a mutation. Direct refs (`id:` or URL) are fetched by
10
+ * ID via `getChannel`, which is workspace-agnostic — so a channel in another
11
+ * workspace resolves without a `--workspace` flag. Name refs still need a
12
+ * workspace to disambiguate. An explicit `--workspace` forces the name path.
13
+ */
14
+ export declare function resolveChannelByRef(ref: string, workspaceRef: string | undefined): Promise<Channel>;
7
15
  export declare function encodeCursor(offset: number): string;
8
16
  export declare function decodeCursor(cursor: string | undefined): number;
9
17
  //# sourceMappingURL=helpers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/helpers.ts"],"names":[],"mappings":"AAKA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQtD;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,OAAO,GAAG,SAAS,CAQtB;AAED,wBAAsB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAMjG;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAqB/D"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAW/C,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQtD;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC7C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;CACpB,GAAG,OAAO,GAAG,SAAS,CAQtB;AAED,wBAAsB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAMjG;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACrC,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GAAG,SAAS,GACjC,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAqB/D"}
@@ -1,6 +1,6 @@
1
- import { getCurrentWorkspaceId } from '../../lib/api.js';
1
+ import { getCommsClient, getCurrentWorkspaceId } from '../../lib/api.js';
2
2
  import { CliError } from '../../lib/errors.js';
3
- import { parseRef, resolveWorkspaceRef } from '../../lib/refs.js';
3
+ import { getDirectChannelId, parseRef, resolveChannelRef, resolveWorkspaceRef, } from '../../lib/refs.js';
4
4
  import { validateNonEmptyName } from '../../lib/validation.js';
5
5
  export function validateChannelName(name) {
6
6
  validateNonEmptyName(name, 'Channel');
@@ -26,6 +26,23 @@ export async function resolveChannelWorkspaceId(workspaceRef) {
26
26
  }
27
27
  return getCurrentWorkspaceId();
28
28
  }
29
+ /**
30
+ * Resolve a channel for a mutation. Direct refs (`id:` or URL) are fetched by
31
+ * ID via `getChannel`, which is workspace-agnostic — so a channel in another
32
+ * workspace resolves without a `--workspace` flag. Name refs still need a
33
+ * workspace to disambiguate. An explicit `--workspace` forces the name path.
34
+ */
35
+ export async function resolveChannelByRef(ref, workspaceRef) {
36
+ if (!workspaceRef) {
37
+ const directId = getDirectChannelId(ref);
38
+ if (directId) {
39
+ const client = await getCommsClient();
40
+ return client.channels.getChannel(directId);
41
+ }
42
+ }
43
+ const workspaceId = await resolveChannelWorkspaceId(workspaceRef);
44
+ return resolveChannelRef(ref, workspaceId);
45
+ }
29
46
  export function encodeCursor(offset) {
30
47
  return Buffer.from(JSON.stringify({ offset })).toString('base64url');
31
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/commands/channel/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAE9D,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC5C,oBAAoB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAA;IAErC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,IAAI,QAAQ,CAAC,cAAc,EAAE,6CAA6C,EAAE;YAC9E,6EAA6E;SAChF,CAAC,CAAA;IACN,CAAC;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,OAGvC;IACG,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,MAAM,IAAI,QAAQ,CAAC,qBAAqB,EAAE,6CAA6C,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,OAAO,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IACjC,OAAO,SAAS,CAAA;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,YAAgC;IAC5E,IAAI,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,MAAM,mBAAmB,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAA;IACvD,CAAC;IAED,OAAO,qBAAqB,EAAE,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAc;IACvC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAA0B;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,CAAA;IAErB,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACD,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IAC1E,CAAC;IAAC,MAAM,CAAC;QACL,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,MAAM,EAAE,CAAC,CAAA;IACrE,CAAC;IAED,IACI,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QAC1B,OAAQ,MAA+B,CAAC,MAAM,KAAK,QAAQ;QAC3D,CAAC,MAAM,CAAC,QAAQ,CAAE,MAA6B,CAAC,MAAM,CAAC;QACtD,MAA6B,CAAC,MAAM,GAAG,CAAC,EAC3C,CAAC;QACC,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,MAAM,EAAE,CAAC,CAAA;IACrE,CAAC;IAED,OAAQ,MAA6B,CAAC,MAAM,CAAA;AAChD,CAAC"}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/commands/channel/helpers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAO3C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA8H7D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAA;AAa3C,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiR7D"}
@@ -1,14 +1,20 @@
1
1
  import { Option } from 'commander';
2
2
  import { withCaseInsensitiveChoices } from '../../lib/completion.js';
3
+ import { addChannelMembers } from './add.js';
4
+ import { archiveChannel, unarchiveChannel } from './archive.js';
3
5
  import { createChannel } from './create.js';
6
+ import { deleteChannel } from './delete.js';
4
7
  import { listChannels } from './list.js';
8
+ import { listChannelMembers } from './members.js';
9
+ import { removeChannelMembers } from './remove.js';
10
+ import { setChannelMembers } from './set.js';
5
11
  import { showChannelThreads } from './threads.js';
6
12
  import { updateChannel } from './update.js';
7
13
  export function registerChannelCommand(program) {
8
14
  const channel = program
9
15
  .command('channel')
10
16
  .alias('channels')
11
- .description('Channel operations (list, create, update, threads)');
17
+ .description('Channel operations (list, create, update, threads, members)');
12
18
  channel
13
19
  .command('list [workspace-ref]', { isDefault: true })
14
20
  .description('List joined channels or discoverable public channels in a workspace')
@@ -74,6 +80,51 @@ Examples:
74
80
  tdc channel update id:abc123 --description "Team discussions"
75
81
  tdc channel update "Leadership" --private --json`)
76
82
  .action(updateChannel);
83
+ channel
84
+ .command('delete <channel-ref>')
85
+ .description('Permanently delete a channel')
86
+ .option('--workspace <ref>', 'Workspace ID or name')
87
+ .option('--yes', 'Confirm deletion')
88
+ .option('--dry-run', 'Show what would happen without executing')
89
+ .option('--json', 'Output result as JSON')
90
+ .addHelpText('after', `
91
+ Examples:
92
+ tdc channel delete "Engineering" --dry-run
93
+ tdc channel delete "Engineering" --yes
94
+ tdc channel delete id:abc123 --yes --json
95
+
96
+ Notes:
97
+ Channel deletion is typically restricted to workspace admins.`)
98
+ .action(deleteChannel);
99
+ channel
100
+ .command('archive <channel-ref>')
101
+ .description('Archive a channel')
102
+ .option('--workspace <ref>', 'Workspace ID or name')
103
+ .option('--dry-run', 'Show what would happen without executing')
104
+ .option('--json', 'Output result as JSON')
105
+ .addHelpText('after', `
106
+ Examples:
107
+ tdc channel archive "Engineering"
108
+ tdc channel archive id:abc123 --json
109
+
110
+ Notes:
111
+ No-op if the channel is already archived.
112
+ Archived channels can be listed with: tdc channels --state archived`)
113
+ .action(archiveChannel);
114
+ channel
115
+ .command('unarchive <channel-ref>')
116
+ .description('Unarchive a channel')
117
+ .option('--workspace <ref>', 'Workspace ID or name')
118
+ .option('--dry-run', 'Show what would happen without executing')
119
+ .option('--json', 'Output result as JSON')
120
+ .addHelpText('after', `
121
+ Examples:
122
+ tdc channel unarchive id:abc123
123
+ tdc channel unarchive id:abc123 --json
124
+
125
+ Notes:
126
+ Name-ref resolution only finds active channels — pass id: or numeric ID for archived channels.`)
127
+ .action(unarchiveChannel);
77
128
  channel
78
129
  .command('threads <channel-ref> [workspace-ref]')
79
130
  .description('List threads in a channel with pagination and filtering')
@@ -100,5 +151,78 @@ Notes:
100
151
  Sorted newest-first by last activity. --limit, --cursor, --since, --until,
101
152
  and --unread are applied client-side; --archive-filter is applied server-side.`)
102
153
  .action(showChannelThreads);
154
+ const members = channel
155
+ .command('members')
156
+ .description('Channel membership operations (list, add, remove, set)');
157
+ members
158
+ .command('list <channel-ref>', { isDefault: true })
159
+ .description("List a channel's members and groups fully present in the channel")
160
+ .option('--json', 'Output as JSON')
161
+ .option('--ndjson', 'Output as newline-delimited JSON')
162
+ .option('--full', 'Include all fields in JSON output')
163
+ .addHelpText('after', `
164
+ Examples:
165
+ tdc channel members 12345
166
+ tdc channel members "general" --json
167
+ tdc channel members add 12345 alice group:Design
168
+ tdc channel members remove 12345 alice
169
+ tdc channel members set 12345 group:Squad --apply
170
+
171
+ Notes:
172
+ "Groups fully in channel" lists groups whose entire current membership is
173
+ already in the channel — a hint, not a persistent link.`)
174
+ .action(listChannelMembers);
175
+ members
176
+ .command('add <channel-ref> [refs...]')
177
+ .description('Add users and/or groups to a channel')
178
+ .option('--dry-run', 'Show what would change without changing')
179
+ .option('--json', 'Output result as JSON')
180
+ .option('--full', 'Include the full updated channel in JSON output')
181
+ .addHelpText('after', `
182
+ Examples:
183
+ tdc channel members add 12345 alice@doist.com bob@doist.com
184
+ tdc channel members add "general" group:Frontend
185
+ tdc channel members add 12345 alice group:Design id:789 --json
186
+
187
+ Notes:
188
+ Refs accept user identifiers (id:N, email, name) or "group:<ref>" to expand
189
+ a group to its current members. Group expansion is one-shot — users added
190
+ later to the group will not auto-join the channel.`)
191
+ .action(addChannelMembers);
192
+ members
193
+ .command('remove <channel-ref> [refs...]')
194
+ .description('Remove users and/or groups from a channel')
195
+ .option('--dry-run', 'Show what would change without changing')
196
+ .option('--json', 'Output result as JSON')
197
+ .option('--full', 'Include the full updated channel in JSON output')
198
+ .addHelpText('after', `
199
+ Examples:
200
+ tdc channel members remove 12345 alice@doist.com
201
+ tdc channel members remove "general" group:Frontend
202
+
203
+ Notes:
204
+ Refs accept user identifiers (id:N, email, name) or "group:<ref>" to expand
205
+ a group to its current members.`)
206
+ .action(removeChannelMembers);
207
+ members
208
+ .command('set <channel-ref> [refs...]')
209
+ .description('Replace channel membership with the resolved set of refs')
210
+ .option('--apply', 'Actually mutate (otherwise dry-run)')
211
+ .option('--include-self', 'Allow set to remove the acting user')
212
+ .option('--dry-run', 'Force dry-run (default behaviour)')
213
+ .option('--json', 'Output result as JSON')
214
+ .option('--full', 'Include the full updated channel in JSON output')
215
+ .addHelpText('after', `
216
+ Examples:
217
+ tdc channel members set 12345 group:Frontend group:Design
218
+ tdc channel members set "general" alice bob carol --apply
219
+ tdc channel members set 12345 group:Squad --apply --include-self
220
+
221
+ Notes:
222
+ Dry-run by default. Pass --apply to mutate.
223
+ Refuses to remove the acting user unless --include-self is also passed.
224
+ Group expansion is one-shot — users added later to a referenced group will
225
+ not auto-join the channel.`)
226
+ .action(setChannelMembers);
103
227
  }
104
228
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/channel/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/channel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAA;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,UAAU,sBAAsB,CAAC,OAAgB;IACnD,MAAM,OAAO,GAAG,OAAO;SAClB,OAAO,CAAC,SAAS,CAAC;SAClB,KAAK,CAAC,UAAU,CAAC;SACjB,WAAW,CAAC,6DAA6D,CAAC,CAAA;IAE/E,OAAO;SACF,OAAO,CAAC,sBAAsB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SACpD,WAAW,CAAC,qEAAqE,CAAC;SAClF,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CACH,iBAAiB,EACjB,wEAAwE,CAC3E;SACA,MAAM,CACH,iBAAiB,EACjB,mEAAmE,CACtE;SACA,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,UAAU,EAAE,kCAAkC,CAAC;SACtD,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,WAAW,CACR,OAAO,EACP;;;;;;;;;;;;;;;;;;;qGAmByF,CAC5F;SACA,MAAM,CAAC,YAAY,CAAC,CAAA;IAEzB,OAAO;SACF,OAAO,CAAC,eAAe,CAAC;SACxB,WAAW,CAAC,kBAAkB,CAAC;SAC/B,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,sBAAsB,EAAE,qBAAqB,CAAC;SACrD,MAAM,CAAC,gBAAgB,EAAE,+DAA+D,CAAC;SACzF,MAAM,CAAC,UAAU,EAAE,yBAAyB,CAAC;SAC7C,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;SAC/C,MAAM,CAAC,WAAW,EAAE,6CAA6C,CAAC;SAClE,MAAM,CAAC,QAAQ,EAAE,gCAAgC,CAAC;SAClD,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,WAAW,CACR,OAAO,EACP;;;;8FAIkF,CACrF;SACA,MAAM,CAAC,aAAa,CAAC,CAAA;IAE1B,OAAO;SACF,OAAO,CAAC,6BAA6B,CAAC;SACtC,WAAW,CAAC,yBAAyB,CAAC;SACtC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC;SAC3C,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC;SACzD,MAAM,CAAC,qBAAqB,EAAE,+BAA+B,CAAC;SAC9D,MAAM,CAAC,UAAU,EAAE,yBAAyB,CAAC;SAC7C,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;SAC/C,MAAM,CAAC,WAAW,EAAE,6CAA6C,CAAC;SAClE,MAAM,CAAC,QAAQ,EAAE,gCAAgC,CAAC;SAClD,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,WAAW,CACR,OAAO,EACP;;;;mDAIuC,CAC1C;SACA,MAAM,CAAC,aAAa,CAAC,CAAA;IAE1B,OAAO;SACF,OAAO,CAAC,sBAAsB,CAAC;SAC/B,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAAC;SACnC,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;SAC/D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,WAAW,CACR,OAAO,EACP;;;;;;;gEAOoD,CACvD;SACA,MAAM,CAAC,aAAa,CAAC,CAAA;IAE1B,OAAO;SACF,OAAO,CAAC,uBAAuB,CAAC;SAChC,WAAW,CAAC,mBAAmB,CAAC;SAChC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;SAC/D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,WAAW,CACR,OAAO,EACP;;;;;;;sEAO0D,CAC7D;SACA,MAAM,CAAC,cAAc,CAAC,CAAA;IAE3B,OAAO;SACF,OAAO,CAAC,yBAAyB,CAAC;SAClC,WAAW,CAAC,qBAAqB,CAAC;SAClC,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,WAAW,EAAE,0CAA0C,CAAC;SAC/D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,WAAW,CACR,OAAO,EACP;;;;;;iGAMqF,CACxF;SACA,MAAM,CAAC,gBAAgB,CAAC,CAAA;IAE7B,OAAO;SACF,OAAO,CAAC,uCAAuC,CAAC;SAChD,WAAW,CAAC,yDAAyD,CAAC;SACtE,MAAM,CAAC,mBAAmB,EAAE,sBAAsB,CAAC;SACnD,MAAM,CAAC,UAAU,EAAE,0BAA0B,CAAC;SAC9C,SAAS,CACN,0BAA0B,CACtB,IAAI,MAAM,CACN,2BAA2B,EAC3B,yDAAyD,CAC5D,EACD,CAAC,QAAQ,EAAE,UAAU,EAAE,KAAK,CAAC,CAChC,CACJ;SACA,MAAM,CAAC,gBAAgB,EAAE,iDAAiD,CAAC;SAC3E,MAAM,CAAC,gBAAgB,EAAE,+CAA+C,CAAC;SACzE,MAAM,CAAC,aAAa,EAAE,oCAAoC,CAAC;SAC3D,MAAM,CAAC,mBAAmB,EAAE,4CAA4C,CAAC;SACzE,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,UAAU,EAAE,kCAAkC,CAAC;SACtD,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,WAAW,CACR,OAAO,EACP;;;;;;;;;;;iFAWqE,CACxE;SACA,MAAM,CAAC,kBAAkB,CAAC,CAAA;IAE/B,MAAM,OAAO,GAAG,OAAO;SAClB,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,wDAAwD,CAAC,CAAA;IAE1E,OAAO;SACF,OAAO,CAAC,oBAAoB,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;SAClD,WAAW,CAAC,kEAAkE,CAAC;SAC/E,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC;SAClC,MAAM,CAAC,UAAU,EAAE,kCAAkC,CAAC;SACtD,MAAM,CAAC,QAAQ,EAAE,mCAAmC,CAAC;SACrD,WAAW,CACR,OAAO,EACP;;;;;;;;;;0DAU8C,CACjD;SACA,MAAM,CAAC,kBAAkB,CAAC,CAAA;IAE/B,OAAO;SACF,OAAO,CAAC,6BAA6B,CAAC;SACtC,WAAW,CAAC,sCAAsC,CAAC;SACnD,MAAM,CAAC,WAAW,EAAE,yCAAyC,CAAC;SAC9D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,MAAM,CAAC,QAAQ,EAAE,iDAAiD,CAAC;SACnE,WAAW,CACR,OAAO,EACP;;;;;;;;;qDASyC,CAC5C;SACA,MAAM,CAAC,iBAAiB,CAAC,CAAA;IAE9B,OAAO;SACF,OAAO,CAAC,gCAAgC,CAAC;SACzC,WAAW,CAAC,2CAA2C,CAAC;SACxD,MAAM,CAAC,WAAW,EAAE,yCAAyC,CAAC;SAC9D,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,MAAM,CAAC,QAAQ,EAAE,iDAAiD,CAAC;SACnE,WAAW,CACR,OAAO,EACP;;;;;;;kCAOsB,CACzB;SACA,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAEjC,OAAO;SACF,OAAO,CAAC,6BAA6B,CAAC;SACtC,WAAW,CAAC,0DAA0D,CAAC;SACvE,MAAM,CAAC,SAAS,EAAE,qCAAqC,CAAC;SACxD,MAAM,CAAC,gBAAgB,EAAE,qCAAqC,CAAC;SAC/D,MAAM,CAAC,WAAW,EAAE,mCAAmC,CAAC;SACxD,MAAM,CAAC,QAAQ,EAAE,uBAAuB,CAAC;SACzC,MAAM,CAAC,QAAQ,EAAE,iDAAiD,CAAC;SACnE,WAAW,CACR,OAAO,EACP;;;;;;;;;;6BAUiB,CACpB;SACA,MAAM,CAAC,iBAAiB,CAAC,CAAA;AAClC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ViewOptions } from '../../lib/options.js';
2
+ export declare function listChannelMembers(channelRef: string, options: ViewOptions & {
3
+ full?: boolean;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=members.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/members.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAKvD,wBAAsB,kBAAkB,CACpC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,WAAW,GAAG;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAC1C,OAAO,CAAC,IAAI,CAAC,CA4Df"}
@@ -0,0 +1,57 @@
1
+ import { getCurrentWorkspaceId, getWorkspaceGroups } from '../../lib/api.js';
2
+ import { colors, formatJson, formatNdjson, pluralize } from '../../lib/output.js';
3
+ import { resolveChannelRef } from '../../lib/refs.js';
4
+ import { channelUserIds, fetchUsersByIds, groupsFullyInChannel } from './membership-helpers.js';
5
+ export async function listChannelMembers(channelRef, options) {
6
+ const workspaceId = await getCurrentWorkspaceId();
7
+ const [channel, groups] = await Promise.all([
8
+ resolveChannelRef(channelRef, workspaceId),
9
+ getWorkspaceGroups(workspaceId),
10
+ ]);
11
+ const userIds = channelUserIds(channel);
12
+ const userMap = await fetchUsersByIds(workspaceId, userIds);
13
+ const userIdSet = new Set(userIds);
14
+ const fullyInChannel = groupsFullyInChannel(groups, userIdSet);
15
+ const members = userIds.map((id) => {
16
+ const user = userMap.get(id);
17
+ return { id, name: user?.fullName ?? null, email: user?.email ?? null };
18
+ });
19
+ const slimPayload = {
20
+ id: channel.id,
21
+ name: channel.name,
22
+ workspaceId: channel.workspaceId,
23
+ members,
24
+ groupsFullyInChannel: fullyInChannel.map((g) => ({
25
+ id: g.id,
26
+ name: g.name,
27
+ userIds: g.userIds,
28
+ })),
29
+ };
30
+ const fullPayload = { ...channel, members, groupsFullyInChannel: fullyInChannel };
31
+ if (options.json) {
32
+ console.log(formatJson(options.full ? fullPayload : slimPayload));
33
+ return;
34
+ }
35
+ if (options.ndjson) {
36
+ console.log(formatNdjson([options.full ? fullPayload : slimPayload]));
37
+ return;
38
+ }
39
+ console.log(colors.channel(channel.name));
40
+ console.log(colors.timestamp(`id:${channel.id}`));
41
+ console.log('');
42
+ console.log(`${members.length} ${pluralize(members.length, 'member')}`);
43
+ for (const m of members) {
44
+ const name = m.name ?? `user:${m.id}`;
45
+ const email = m.email ? colors.timestamp(`<${m.email}>`) : '';
46
+ const id = colors.timestamp(`id:${m.id}`);
47
+ console.log(` ${id} ${colors.author(name)} ${email}`.trimEnd());
48
+ }
49
+ if (fullyInChannel.length > 0) {
50
+ console.log('');
51
+ console.log(`Groups fully in channel (${fullyInChannel.length}):`);
52
+ for (const g of fullyInChannel) {
53
+ console.log(` ${colors.timestamp(`id:${g.id}`)} ${g.name} ${colors.timestamp(`(${g.userIds.length} ${pluralize(g.userIds.length, 'member')})`)}`);
54
+ }
55
+ }
56
+ }
57
+ //# sourceMappingURL=members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../../src/commands/channel/members.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { Channel, Group, WorkspaceUser } from '@doist/comms-sdk';
2
+ import type { MutationOptions } from '../../lib/options.js';
3
+ export type ChannelMutationOptions = MutationOptions;
4
+ export type ExpandedGroup = {
5
+ groupId: string;
6
+ groupName: string;
7
+ userIds: number[];
8
+ };
9
+ export declare function channelUserIds(channel: Channel): number[];
10
+ export declare function fetchUsersByIds(workspaceId: number, userIds: number[]): Promise<Map<number, WorkspaceUser>>;
11
+ export declare function logExpansion(expandedFrom: ExpandedGroup[]): void;
12
+ export declare function describeExpansion(expandedFrom: ExpandedGroup[]): string | undefined;
13
+ export declare function groupsFullyInChannel(groups: Group[], channelUserIdSet: Set<number>): Group[];
14
+ /**
15
+ * Shared add/remove mutation flow. Resolves the channel and the requested refs
16
+ * concurrently, diffs against current membership, then either previews
17
+ * (`--dry-run`) or applies the mutation and prints / emits JSON.
18
+ */
19
+ export declare function mutateChannelMembership(channelRef: string, refs: string[], action: 'add' | 'remove', options: ChannelMutationOptions): Promise<void>;
20
+ //# sourceMappingURL=membership-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"membership-helpers.d.ts","sourceRoot":"","sources":["../../../src/commands/channel/membership-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAOrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAI3D,MAAM,MAAM,sBAAsB,GAAG,eAAe,CAAA;AAEpD,MAAM,MAAM,aAAa,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAErF,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,CAEzD;AAED,wBAAsB,eAAe,CACjC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAoBrC;AAED,wBAAgB,YAAY,CAAC,YAAY,EAAE,aAAa,EAAE,GAAG,IAAI,CAQhE;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,aAAa,EAAE,GAAG,MAAM,GAAG,SAAS,CAKnF;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,EAAE,CAI5F;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CACzC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,KAAK,GAAG,QAAQ,EACxB,OAAO,EAAE,sBAAsB,GAChC,OAAO,CAAC,IAAI,CAAC,CAqFf"}
@@ -0,0 +1,125 @@
1
+ import { addUsersToChannel, getCommsClient, getCurrentWorkspaceId, removeUsersFromChannel, } from '../../lib/api.js';
2
+ import { colors, formatJson, pluralize, printDryRun } from '../../lib/output.js';
3
+ import { resolveChannelMemberRefs, resolveChannelRef } from '../../lib/refs.js';
4
+ export function channelUserIds(channel) {
5
+ return channel.userIds ?? [];
6
+ }
7
+ export async function fetchUsersByIds(workspaceId, userIds) {
8
+ if (userIds.length === 0)
9
+ return new Map();
10
+ const client = await getCommsClient();
11
+ // Per-member fetch keeps latency tied to channel size, not workspace size
12
+ // (mirrors groups/view); missing/unresolvable users are simply skipped.
13
+ const entries = await Promise.all(userIds.map(async (userId) => {
14
+ try {
15
+ const user = await client.workspaceUsers.getUserById({ workspaceId, userId });
16
+ return [userId, user];
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }));
22
+ const map = new Map();
23
+ for (const entry of entries) {
24
+ if (entry)
25
+ map.set(entry[0], entry[1]);
26
+ }
27
+ return map;
28
+ }
29
+ export function logExpansion(expandedFrom) {
30
+ for (const g of expandedFrom) {
31
+ console.log(colors.timestamp(`Expanded group "${g.groupName}" → ${g.userIds.length} ${pluralize(g.userIds.length, 'user')}`));
32
+ }
33
+ }
34
+ export function describeExpansion(expandedFrom) {
35
+ if (expandedFrom.length === 0)
36
+ return undefined;
37
+ return expandedFrom
38
+ .map((g) => `${g.groupName} (id:${g.groupId}, ${g.userIds.length} users)`)
39
+ .join('\n');
40
+ }
41
+ export function groupsFullyInChannel(groups, channelUserIdSet) {
42
+ return groups.filter((g) => g.userIds.length > 0 && g.userIds.every((id) => channelUserIdSet.has(id)));
43
+ }
44
+ /**
45
+ * Shared add/remove mutation flow. Resolves the channel and the requested refs
46
+ * concurrently, diffs against current membership, then either previews
47
+ * (`--dry-run`) or applies the mutation and prints / emits JSON.
48
+ */
49
+ export async function mutateChannelMembership(channelRef, refs, action, options) {
50
+ const workspaceId = await getCurrentWorkspaceId();
51
+ const [channel, { userIds: requested, expandedFrom }] = await Promise.all([
52
+ resolveChannelRef(channelRef, workspaceId),
53
+ resolveChannelMemberRefs(refs, workspaceId),
54
+ ]);
55
+ const current = new Set(channelUserIds(channel));
56
+ const actionable = action === 'add'
57
+ ? requested.filter((id) => !current.has(id))
58
+ : requested.filter((id) => current.has(id));
59
+ const skipped = action === 'add'
60
+ ? requested.filter((id) => current.has(id))
61
+ : requested.filter((id) => !current.has(id));
62
+ const actionLabel = action === 'add' ? 'add users to' : 'remove users from';
63
+ const skippedLabel = action === 'add' ? 'Already members' : 'Not members';
64
+ if (options.dryRun) {
65
+ printDryRun(`${actionLabel} channel`, {
66
+ Channel: `${channel.name} (id:${channel.id})`,
67
+ 'Expanded from groups': describeExpansion(expandedFrom),
68
+ [`Users to ${action}`]: actionable.length > 0 ? actionable.join(', ') : '(none)',
69
+ [skippedLabel]: skipped.length > 0 ? skipped.join(', ') : undefined,
70
+ });
71
+ return;
72
+ }
73
+ if (actionable.length > 0) {
74
+ if (action === 'add') {
75
+ await addUsersToChannel(channel.id, actionable);
76
+ }
77
+ else {
78
+ await removeUsersFromChannel(channel.id, actionable);
79
+ }
80
+ }
81
+ const newMemberCount = action === 'add'
82
+ ? channelUserIds(channel).length + actionable.length
83
+ : channelUserIds(channel).length - actionable.length;
84
+ if (options.json) {
85
+ if (options.full) {
86
+ const client = await getCommsClient();
87
+ const updated = await client.channels.getChannel(channel.id);
88
+ console.log(formatJson(updated, 'channel', true));
89
+ }
90
+ else {
91
+ const result = {
92
+ id: channel.id,
93
+ memberCount: newMemberCount,
94
+ };
95
+ if (expandedFrom.length > 0)
96
+ result.expandedFrom = expandedFrom;
97
+ if (action === 'add') {
98
+ result.added = actionable;
99
+ result.alreadyMembers = skipped;
100
+ }
101
+ else {
102
+ result.removed = actionable;
103
+ result.notMembers = skipped;
104
+ }
105
+ console.log(formatJson(result));
106
+ }
107
+ return;
108
+ }
109
+ const pastVerb = action === 'add' ? 'Added' : 'Removed';
110
+ const preposition = action === 'add' ? 'to' : 'from';
111
+ const noneMsg = action === 'add'
112
+ ? `No new members added to "${channel.name}" (already in channel).`
113
+ : `No members removed from "${channel.name}" (none of the users were in channel).`;
114
+ logExpansion(expandedFrom);
115
+ if (actionable.length === 0) {
116
+ console.log(noneMsg);
117
+ }
118
+ else {
119
+ console.log(`${pastVerb} ${actionable.length} ${pluralize(actionable.length, 'user')} ${preposition} "${channel.name}" (now ${newMemberCount} ${pluralize(newMemberCount, 'member')}).`);
120
+ }
121
+ if (skipped.length > 0) {
122
+ console.log(`${skippedLabel}: ${skipped.join(', ')}`);
123
+ }
124
+ }
125
+ //# sourceMappingURL=membership-helpers.js.map