@indigoai-us/hq-cli 5.136.0 → 5.137.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.
- package/CHANGELOG.md +5 -0
- package/dist/command-catalog.generated.d.ts +16 -0
- package/dist/command-catalog.generated.js +21 -0
- package/dist/commands/channels.d.ts +9 -1
- package/dist/commands/channels.js +56 -1
- package/dist/commands/dm.d.ts +6 -0
- package/dist/commands/dm.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2388,6 +2388,22 @@ export declare const COMMAND_CATALOG: readonly [{
|
|
|
2388
2388
|
readonly arguments: readonly [];
|
|
2389
2389
|
readonly options: readonly [];
|
|
2390
2390
|
readonly subcommands: readonly [];
|
|
2391
|
+
}, {
|
|
2392
|
+
readonly name: "members";
|
|
2393
|
+
readonly description: "Print the members of one of your DM channels.";
|
|
2394
|
+
readonly aliases: readonly [];
|
|
2395
|
+
readonly hidden: false;
|
|
2396
|
+
readonly usage: "[options] <channel>";
|
|
2397
|
+
readonly arguments: readonly [{
|
|
2398
|
+
readonly name: "channel";
|
|
2399
|
+
readonly required: true;
|
|
2400
|
+
readonly variadic: false;
|
|
2401
|
+
}];
|
|
2402
|
+
readonly options: readonly [{
|
|
2403
|
+
readonly flags: "--json";
|
|
2404
|
+
readonly description: "Output the member array as JSON.";
|
|
2405
|
+
}];
|
|
2406
|
+
readonly subcommands: readonly [];
|
|
2391
2407
|
}];
|
|
2392
2408
|
}, {
|
|
2393
2409
|
readonly name: "onboard";
|
|
@@ -3067,6 +3067,27 @@ export const COMMAND_CATALOG = [
|
|
|
3067
3067
|
"arguments": [],
|
|
3068
3068
|
"options": [],
|
|
3069
3069
|
"subcommands": []
|
|
3070
|
+
},
|
|
3071
|
+
{
|
|
3072
|
+
"name": "members",
|
|
3073
|
+
"description": "Print the members of one of your DM channels.",
|
|
3074
|
+
"aliases": [],
|
|
3075
|
+
"hidden": false,
|
|
3076
|
+
"usage": "[options] <channel>",
|
|
3077
|
+
"arguments": [
|
|
3078
|
+
{
|
|
3079
|
+
"name": "channel",
|
|
3080
|
+
"required": true,
|
|
3081
|
+
"variadic": false
|
|
3082
|
+
}
|
|
3083
|
+
],
|
|
3084
|
+
"options": [
|
|
3085
|
+
{
|
|
3086
|
+
"flags": "--json",
|
|
3087
|
+
"description": "Output the member array as JSON."
|
|
3088
|
+
}
|
|
3089
|
+
],
|
|
3090
|
+
"subcommands": []
|
|
3070
3091
|
}
|
|
3071
3092
|
]
|
|
3072
3093
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { type ChannelSummary } from "./dm.js";
|
|
2
|
+
import { type CallerIdentity, type ChannelMember, type ChannelSummary } from "./dm.js";
|
|
3
3
|
/**
|
|
4
4
|
* Human label for a channel row. Named channels (personal/company) show their
|
|
5
5
|
* name + a `hq dm <slug>` hint; unnamed group DMs are identified by their
|
|
@@ -12,5 +12,13 @@ export declare function describeChannel(c: ChannelSummary): string;
|
|
|
12
12
|
* fetched list) so the formatting is unit-testable without network/auth.
|
|
13
13
|
*/
|
|
14
14
|
export declare function formatChannelsList(channels: ChannelSummary[]): string;
|
|
15
|
+
/**
|
|
16
|
+
* Remove the caller from a channel roster before it is used for mentions.
|
|
17
|
+
* Machine principals identify themselves with the JWT uid; human sessions can
|
|
18
|
+
* also match the roster's email when the uid claim is absent.
|
|
19
|
+
*/
|
|
20
|
+
export declare function excludeCallerFromChannelMembers(members: ChannelMember[], caller: CallerIdentity): ChannelMember[];
|
|
21
|
+
/** Render the roster as either dm-bind's tab-separated format or JSON. */
|
|
22
|
+
export declare function formatChannelMembers(members: ChannelMember[], json: boolean): string;
|
|
15
23
|
export declare function registerChannelsCommand(program: Command): void;
|
|
16
24
|
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
3
3
|
import { vaultApiFetch } from "../utils/vault-api.js";
|
|
4
|
-
import { channelSlug } from "./dm.js";
|
|
4
|
+
import { callerFromToken, channelSlug, fetchChannelMembers, fetchChannels, matchChannelsByName, } from "./dm.js";
|
|
5
5
|
/**
|
|
6
6
|
* Human label for a channel row. Named channels (personal/company) show their
|
|
7
7
|
* name + a `hq dm <slug>` hint; unnamed group DMs are identified by their
|
|
@@ -42,6 +42,31 @@ export function formatChannelsList(channels) {
|
|
|
42
42
|
}
|
|
43
43
|
return lines.join("\n");
|
|
44
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Remove the caller from a channel roster before it is used for mentions.
|
|
47
|
+
* Machine principals identify themselves with the JWT uid; human sessions can
|
|
48
|
+
* also match the roster's email when the uid claim is absent.
|
|
49
|
+
*/
|
|
50
|
+
export function excludeCallerFromChannelMembers(members, caller) {
|
|
51
|
+
return members.filter((member) => {
|
|
52
|
+
if (caller.personUid && member.personUid === caller.personUid)
|
|
53
|
+
return false;
|
|
54
|
+
if (caller.email &&
|
|
55
|
+
member.email &&
|
|
56
|
+
member.email.trim().toLowerCase() === caller.email) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** Render the roster as either dm-bind's tab-separated format or JSON. */
|
|
63
|
+
export function formatChannelMembers(members, json) {
|
|
64
|
+
if (json)
|
|
65
|
+
return JSON.stringify(members);
|
|
66
|
+
return members
|
|
67
|
+
.map((member) => `${member.displayName ?? ""}\t${member.personUid}`)
|
|
68
|
+
.join("\n");
|
|
69
|
+
}
|
|
45
70
|
async function runChannelsList() {
|
|
46
71
|
try {
|
|
47
72
|
const token = await ensureCognitoToken();
|
|
@@ -64,6 +89,29 @@ async function runChannelsList() {
|
|
|
64
89
|
process.exit(1);
|
|
65
90
|
}
|
|
66
91
|
}
|
|
92
|
+
async function runChannelsMembers(channelName, opts) {
|
|
93
|
+
try {
|
|
94
|
+
const token = await ensureCognitoToken();
|
|
95
|
+
const channels = await fetchChannels(token);
|
|
96
|
+
const matches = matchChannelsByName(channels, channelName);
|
|
97
|
+
if (matches.length === 0) {
|
|
98
|
+
console.error(chalk.red(`No channel named '${channelName}' — run \`hq channels\` to see your channels.`));
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
if (matches.length > 1) {
|
|
102
|
+
const scopes = matches.map((match) => match.scope ?? "?").join(", ");
|
|
103
|
+
console.error(chalk.red(`'${channelName}' matches ${matches.length} channels (${scopes}) — this is ambiguous.`));
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
const members = await fetchChannelMembers(token, matches[0].channelId);
|
|
107
|
+
const visibleMembers = excludeCallerFromChannelMembers(members, callerFromToken(token));
|
|
108
|
+
console.log(formatChannelMembers(visibleMembers, opts.json === true));
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
console.error(chalk.red("Error:"), err instanceof Error ? err.message : String(err));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
67
115
|
export function registerChannelsCommand(program) {
|
|
68
116
|
const channels = program
|
|
69
117
|
.command("channels")
|
|
@@ -74,5 +122,12 @@ export function registerChannelsCommand(program) {
|
|
|
74
122
|
.action(async () => {
|
|
75
123
|
await runChannelsList();
|
|
76
124
|
});
|
|
125
|
+
channels
|
|
126
|
+
.command("members <channel>")
|
|
127
|
+
.description("Print the members of one of your DM channels.")
|
|
128
|
+
.option("--json", "Output the member array as JSON.")
|
|
129
|
+
.action(async (channelName, opts) => {
|
|
130
|
+
await runChannelsMembers(channelName, opts);
|
|
131
|
+
});
|
|
77
132
|
}
|
|
78
133
|
//# sourceMappingURL=channels.js.map
|
package/dist/commands/dm.d.ts
CHANGED
|
@@ -192,6 +192,12 @@ export declare function buildConnectionActionBody(identifier: string, matched: C
|
|
|
192
192
|
};
|
|
193
193
|
/** Fetch the caller's channels (GET /v1/notify/channels). */
|
|
194
194
|
export declare function fetchChannels(token: string): Promise<ChannelSummary[]>;
|
|
195
|
+
/**
|
|
196
|
+
* Fetch a channel's roster (GET /v1/notify/channels/{id}/members). Any member
|
|
197
|
+
* who can read the channel may read its members, so this is the same gate the
|
|
198
|
+
* post itself passes. Used to resolve `@name` mentions into participant uids.
|
|
199
|
+
*/
|
|
200
|
+
export declare function fetchChannelMembers(token: string, channelId: string): Promise<ChannelMember[]>;
|
|
195
201
|
/** One incoming DM as returned by GET /v1/notify/inbox. */
|
|
196
202
|
export interface DmInboxEvent {
|
|
197
203
|
eventId: string;
|
package/dist/commands/dm.js
CHANGED
|
@@ -503,7 +503,7 @@ export async function fetchChannels(token) {
|
|
|
503
503
|
* who can read the channel may read its members, so this is the same gate the
|
|
504
504
|
* post itself passes. Used to resolve `@name` mentions into participant uids.
|
|
505
505
|
*/
|
|
506
|
-
async function fetchChannelMembers(token, channelId) {
|
|
506
|
+
export async function fetchChannelMembers(token, channelId) {
|
|
507
507
|
const res = await vaultApiFetch({
|
|
508
508
|
token,
|
|
509
509
|
path: `/v1/notify/channels/${encodeURIComponent(channelId)}/members`,
|