@eliya-oss/agent-slack 0.1.13 → 0.1.14
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/.agents/cli-api.md +6 -2
- package/CHANGELOG.md +9 -0
- package/dist/main.js +143 -119
- package/package.json +1 -1
package/.agents/cli-api.md
CHANGED
|
@@ -209,8 +209,9 @@ normalization and returns the raw Slack objects.
|
|
|
209
209
|
`tz`, and team fields.
|
|
210
210
|
- **file**: `id`, `name`, `mimetype`, `size`, and `permalink` when present.
|
|
211
211
|
Drops thumbnails and private URLs.
|
|
212
|
-
- **conversation**: `id`, `name`, `is_private`, `is_archived`, `
|
|
213
|
-
`purpose`, `num_members` when present.
|
|
212
|
+
- **conversation**: `id`, `name`, `is_private`, `is_archived`, `is_member`,
|
|
213
|
+
`topic`, `purpose`, `num_members` when present. `is_member` is kept as an
|
|
214
|
+
explicit boolean so an agent can tell membership from a list.
|
|
214
215
|
- `conversation context` dedupes thread roots already present in `messages` and
|
|
215
216
|
hydrates every unique author, including those who appear only in replies.
|
|
216
217
|
|
|
@@ -302,6 +303,9 @@ Schema output includes:
|
|
|
302
303
|
|
|
303
304
|
- command description and examples
|
|
304
305
|
- positional args and flags
|
|
306
|
+
- `dataKey`: the key under the response envelope's `data` that holds the
|
|
307
|
+
command's primary payload (for example `conversation list` reports
|
|
308
|
+
`dataKey: "channels"`, so the array is at `data.channels`, not `data`)
|
|
305
309
|
- payload schema when known
|
|
306
310
|
- required Slack method/scopes
|
|
307
311
|
- output schema
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @eliya-oss/agent-slack
|
|
2
2
|
|
|
3
|
+
## 0.1.14
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- d856e3b: Two agent-facing discoverability improvements.
|
|
8
|
+
|
|
9
|
+
- `describe --json` and `<command> --help --json` now report a `dataKey` for each command: the key under the response envelope's `data` that holds the primary payload (for example `conversation list` reports `dataKey: "channels"`, so results are at `data.channels`). Agents no longer have to probe the response shape.
|
|
10
|
+
- Conversation results now keep `is_member` as an explicit boolean, so an agent can tell which channels the active token has joined directly from `conversation list`.
|
|
11
|
+
|
|
3
12
|
## 0.1.13
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/main.js
CHANGED
|
@@ -25522,9 +25522,143 @@ const pad = (value, width) => value + " ".repeat(Math.max(0, width - value.lengt
|
|
|
25522
25522
|
const widthFor = (column) => column === "text" ? 72 : 24;
|
|
25523
25523
|
const truncate = (value, width) => value.length > width ? `${value.slice(0, Math.max(0, width - 3))}...` : value;
|
|
25524
25524
|
//#endregion
|
|
25525
|
+
//#region src/output/normalize.ts
|
|
25526
|
+
const isRec = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25527
|
+
const asArray = (value) => Array.isArray(value) ? value : [];
|
|
25528
|
+
const str = (record, key) => typeof record[key] === "string" && record[key].length > 0 ? record[key] : void 0;
|
|
25529
|
+
const slimFile = (input) => {
|
|
25530
|
+
if (!isRec(input)) return input;
|
|
25531
|
+
const out = {
|
|
25532
|
+
id: input.id,
|
|
25533
|
+
name: input.name
|
|
25534
|
+
};
|
|
25535
|
+
if (typeof input.mimetype === "string") out.mimetype = input.mimetype;
|
|
25536
|
+
if (typeof input.size === "number") out.size = input.size;
|
|
25537
|
+
const permalink = str(input, "permalink");
|
|
25538
|
+
if (permalink) out.permalink = permalink;
|
|
25539
|
+
return out;
|
|
25540
|
+
};
|
|
25541
|
+
const slimMessage = (input) => {
|
|
25542
|
+
if (!isRec(input)) return input;
|
|
25543
|
+
const m = input;
|
|
25544
|
+
const out = {};
|
|
25545
|
+
if (typeof m.user === "string") out.user = m.user;
|
|
25546
|
+
else if (typeof m.bot_id === "string") out.bot_id = m.bot_id;
|
|
25547
|
+
const username = str(m, "username");
|
|
25548
|
+
if (username) out.username = username;
|
|
25549
|
+
const subtype = str(m, "subtype");
|
|
25550
|
+
if (subtype) out.subtype = subtype;
|
|
25551
|
+
if (typeof m.ts === "string") out.ts = m.ts;
|
|
25552
|
+
out.text = typeof m.text === "string" ? m.text : "";
|
|
25553
|
+
if (typeof m.thread_ts === "string" && m.thread_ts !== m.ts) out.thread_ts = m.thread_ts;
|
|
25554
|
+
if (typeof m.reply_count === "number") out.reply_count = m.reply_count;
|
|
25555
|
+
const reactions = asArray(m.reactions).filter(isRec).map((r) => ({
|
|
25556
|
+
name: r.name,
|
|
25557
|
+
count: r.count
|
|
25558
|
+
}));
|
|
25559
|
+
if (reactions.length > 0) out.reactions = reactions;
|
|
25560
|
+
const files = asArray(m.files).map(slimFile);
|
|
25561
|
+
if (files.length > 0) out.files = files;
|
|
25562
|
+
if (m.edited !== void 0 && m.edited !== null) out.edited = true;
|
|
25563
|
+
return out;
|
|
25564
|
+
};
|
|
25565
|
+
const slimUser = (input) => {
|
|
25566
|
+
if (!isRec(input)) return input;
|
|
25567
|
+
const u = input;
|
|
25568
|
+
const profile = isRec(u.profile) ? u.profile : {};
|
|
25569
|
+
const out = {
|
|
25570
|
+
id: u.id,
|
|
25571
|
+
name: u.name
|
|
25572
|
+
};
|
|
25573
|
+
const real = str(profile, "display_name") ?? str(u, "real_name") ?? str(profile, "real_name");
|
|
25574
|
+
if (real) out.real_name = real;
|
|
25575
|
+
if (u.is_bot === true) out.is_bot = true;
|
|
25576
|
+
if (u.deleted === true) out.deleted = true;
|
|
25577
|
+
const title = str(profile, "title");
|
|
25578
|
+
if (title) out.title = title;
|
|
25579
|
+
return out;
|
|
25580
|
+
};
|
|
25581
|
+
const slimConversation = (input) => {
|
|
25582
|
+
if (!isRec(input)) return input;
|
|
25583
|
+
const c = input;
|
|
25584
|
+
const out = {
|
|
25585
|
+
id: c.id,
|
|
25586
|
+
name: c.name
|
|
25587
|
+
};
|
|
25588
|
+
if (c.is_private === true) out.is_private = true;
|
|
25589
|
+
if (c.is_archived === true) out.is_archived = true;
|
|
25590
|
+
if (c.is_im === true) out.is_im = true;
|
|
25591
|
+
if (c.is_mpim === true) out.is_mpim = true;
|
|
25592
|
+
if (typeof c.is_member === "boolean") out.is_member = c.is_member;
|
|
25593
|
+
const topic = isRec(c.topic) ? str(c.topic, "value") : void 0;
|
|
25594
|
+
if (topic) out.topic = topic;
|
|
25595
|
+
const purpose = isRec(c.purpose) ? str(c.purpose, "value") : void 0;
|
|
25596
|
+
if (purpose) out.purpose = purpose;
|
|
25597
|
+
if (typeof c.num_members === "number") out.num_members = c.num_members;
|
|
25598
|
+
return out;
|
|
25599
|
+
};
|
|
25600
|
+
const slimTeam = (input) => {
|
|
25601
|
+
if (!isRec(input)) return input;
|
|
25602
|
+
const t = input;
|
|
25603
|
+
const out = {
|
|
25604
|
+
id: t.id,
|
|
25605
|
+
name: t.name
|
|
25606
|
+
};
|
|
25607
|
+
const domain = str(t, "domain");
|
|
25608
|
+
if (domain) out.domain = domain;
|
|
25609
|
+
const emailDomain = str(t, "email_domain");
|
|
25610
|
+
if (emailDomain) out.email_domain = emailDomain;
|
|
25611
|
+
const enterpriseId = str(t, "enterprise_id");
|
|
25612
|
+
if (enterpriseId) out.enterprise_id = enterpriseId;
|
|
25613
|
+
const enterpriseName = str(t, "enterprise_name");
|
|
25614
|
+
if (enterpriseName) out.enterprise_name = enterpriseName;
|
|
25615
|
+
return out;
|
|
25616
|
+
};
|
|
25617
|
+
const stripResponseEnvelope = (response) => {
|
|
25618
|
+
const { ok, response_metadata, ...rest } = response;
|
|
25619
|
+
return rest;
|
|
25620
|
+
};
|
|
25621
|
+
const dataKeyFor = (method) => {
|
|
25622
|
+
switch (method) {
|
|
25623
|
+
case "conversations.history":
|
|
25624
|
+
case "conversations.replies": return "messages";
|
|
25625
|
+
case "conversations.info": return "channel";
|
|
25626
|
+
case "conversations.list": return "channels";
|
|
25627
|
+
case "conversations.members": return "members";
|
|
25628
|
+
case "users.info":
|
|
25629
|
+
case "users.lookupByEmail": return "user";
|
|
25630
|
+
case "users.list": return "users";
|
|
25631
|
+
case "files.info": return "file";
|
|
25632
|
+
case "files.list": return "files";
|
|
25633
|
+
case "team.info": return "team";
|
|
25634
|
+
default: return;
|
|
25635
|
+
}
|
|
25636
|
+
};
|
|
25637
|
+
const normalizeResponse = (method, response) => {
|
|
25638
|
+
if (!isRec(response)) return response;
|
|
25639
|
+
const r = response;
|
|
25640
|
+
switch (method) {
|
|
25641
|
+
case "conversations.history":
|
|
25642
|
+
case "conversations.replies": return { messages: asArray(r.messages).map(slimMessage) };
|
|
25643
|
+
case "conversations.info": return { channel: slimConversation(r.channel) };
|
|
25644
|
+
case "conversations.list": return { channels: asArray(r.channels).map(slimConversation) };
|
|
25645
|
+
case "users.info":
|
|
25646
|
+
case "users.lookupByEmail": return { user: slimUser(r.user) };
|
|
25647
|
+
case "users.list": return { users: asArray(r.members).map(slimUser) };
|
|
25648
|
+
case "files.info": return { file: slimFile(r.file) };
|
|
25649
|
+
case "files.list": return { files: asArray(r.files).map(slimFile) };
|
|
25650
|
+
case "team.info": return { team: slimTeam(r.team) };
|
|
25651
|
+
case "reactions.get": return isRec(r.message) ? {
|
|
25652
|
+
...stripResponseEnvelope(r),
|
|
25653
|
+
message: slimMessage(r.message)
|
|
25654
|
+
} : stripResponseEnvelope(r);
|
|
25655
|
+
default: return stripResponseEnvelope(r);
|
|
25656
|
+
}
|
|
25657
|
+
};
|
|
25658
|
+
//#endregion
|
|
25525
25659
|
//#region src/cli/metadata.ts
|
|
25526
25660
|
createRequire(import.meta.url);
|
|
25527
|
-
const packageJson = { version: "0.1.
|
|
25661
|
+
const packageJson = { version: "0.1.14" };
|
|
25528
25662
|
const PRIMARY_COMMAND_NAME = "agent-slack";
|
|
25529
25663
|
const SHORT_COMMAND_NAME = "aslk";
|
|
25530
25664
|
const COMMAND_NAMES = [PRIMARY_COMMAND_NAME, SHORT_COMMAND_NAME];
|
|
@@ -25915,7 +26049,14 @@ const commandMetadata = [
|
|
|
25915
26049
|
output: "download status",
|
|
25916
26050
|
examples: ["agent-slack file download F123 --out ./artifact.pdf --json"]
|
|
25917
26051
|
}
|
|
25918
|
-
]
|
|
26052
|
+
].map((command) => {
|
|
26053
|
+
const method = command.methods?.[0];
|
|
26054
|
+
const dataKey = method === void 0 ? void 0 : dataKeyFor(method);
|
|
26055
|
+
return dataKey === void 0 ? command : {
|
|
26056
|
+
...command,
|
|
26057
|
+
dataKey
|
|
26058
|
+
};
|
|
26059
|
+
});
|
|
25919
26060
|
const describeAllCommands = () => ({
|
|
25920
26061
|
name: PRIMARY_COMMAND_NAME,
|
|
25921
26062
|
aliases: [SHORT_COMMAND_NAME],
|
|
@@ -26003,123 +26144,6 @@ const renderCompletion = (shell) => {
|
|
|
26003
26144
|
};
|
|
26004
26145
|
const summaryFor = (path) => commandMetadata.find((command) => command.path.join(" ") === path)?.summary.replace(/'/g, "") ?? "";
|
|
26005
26146
|
//#endregion
|
|
26006
|
-
//#region src/output/normalize.ts
|
|
26007
|
-
const isRec = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26008
|
-
const asArray = (value) => Array.isArray(value) ? value : [];
|
|
26009
|
-
const str = (record, key) => typeof record[key] === "string" && record[key].length > 0 ? record[key] : void 0;
|
|
26010
|
-
const slimFile = (input) => {
|
|
26011
|
-
if (!isRec(input)) return input;
|
|
26012
|
-
const out = {
|
|
26013
|
-
id: input.id,
|
|
26014
|
-
name: input.name
|
|
26015
|
-
};
|
|
26016
|
-
if (typeof input.mimetype === "string") out.mimetype = input.mimetype;
|
|
26017
|
-
if (typeof input.size === "number") out.size = input.size;
|
|
26018
|
-
const permalink = str(input, "permalink");
|
|
26019
|
-
if (permalink) out.permalink = permalink;
|
|
26020
|
-
return out;
|
|
26021
|
-
};
|
|
26022
|
-
const slimMessage = (input) => {
|
|
26023
|
-
if (!isRec(input)) return input;
|
|
26024
|
-
const m = input;
|
|
26025
|
-
const out = {};
|
|
26026
|
-
if (typeof m.user === "string") out.user = m.user;
|
|
26027
|
-
else if (typeof m.bot_id === "string") out.bot_id = m.bot_id;
|
|
26028
|
-
const username = str(m, "username");
|
|
26029
|
-
if (username) out.username = username;
|
|
26030
|
-
const subtype = str(m, "subtype");
|
|
26031
|
-
if (subtype) out.subtype = subtype;
|
|
26032
|
-
if (typeof m.ts === "string") out.ts = m.ts;
|
|
26033
|
-
out.text = typeof m.text === "string" ? m.text : "";
|
|
26034
|
-
if (typeof m.thread_ts === "string" && m.thread_ts !== m.ts) out.thread_ts = m.thread_ts;
|
|
26035
|
-
if (typeof m.reply_count === "number") out.reply_count = m.reply_count;
|
|
26036
|
-
const reactions = asArray(m.reactions).filter(isRec).map((r) => ({
|
|
26037
|
-
name: r.name,
|
|
26038
|
-
count: r.count
|
|
26039
|
-
}));
|
|
26040
|
-
if (reactions.length > 0) out.reactions = reactions;
|
|
26041
|
-
const files = asArray(m.files).map(slimFile);
|
|
26042
|
-
if (files.length > 0) out.files = files;
|
|
26043
|
-
if (m.edited !== void 0 && m.edited !== null) out.edited = true;
|
|
26044
|
-
return out;
|
|
26045
|
-
};
|
|
26046
|
-
const slimUser = (input) => {
|
|
26047
|
-
if (!isRec(input)) return input;
|
|
26048
|
-
const u = input;
|
|
26049
|
-
const profile = isRec(u.profile) ? u.profile : {};
|
|
26050
|
-
const out = {
|
|
26051
|
-
id: u.id,
|
|
26052
|
-
name: u.name
|
|
26053
|
-
};
|
|
26054
|
-
const real = str(profile, "display_name") ?? str(u, "real_name") ?? str(profile, "real_name");
|
|
26055
|
-
if (real) out.real_name = real;
|
|
26056
|
-
if (u.is_bot === true) out.is_bot = true;
|
|
26057
|
-
if (u.deleted === true) out.deleted = true;
|
|
26058
|
-
const title = str(profile, "title");
|
|
26059
|
-
if (title) out.title = title;
|
|
26060
|
-
return out;
|
|
26061
|
-
};
|
|
26062
|
-
const slimConversation = (input) => {
|
|
26063
|
-
if (!isRec(input)) return input;
|
|
26064
|
-
const c = input;
|
|
26065
|
-
const out = {
|
|
26066
|
-
id: c.id,
|
|
26067
|
-
name: c.name
|
|
26068
|
-
};
|
|
26069
|
-
if (c.is_private === true) out.is_private = true;
|
|
26070
|
-
if (c.is_archived === true) out.is_archived = true;
|
|
26071
|
-
if (c.is_im === true) out.is_im = true;
|
|
26072
|
-
if (c.is_mpim === true) out.is_mpim = true;
|
|
26073
|
-
const topic = isRec(c.topic) ? str(c.topic, "value") : void 0;
|
|
26074
|
-
if (topic) out.topic = topic;
|
|
26075
|
-
const purpose = isRec(c.purpose) ? str(c.purpose, "value") : void 0;
|
|
26076
|
-
if (purpose) out.purpose = purpose;
|
|
26077
|
-
if (typeof c.num_members === "number") out.num_members = c.num_members;
|
|
26078
|
-
return out;
|
|
26079
|
-
};
|
|
26080
|
-
const slimTeam = (input) => {
|
|
26081
|
-
if (!isRec(input)) return input;
|
|
26082
|
-
const t = input;
|
|
26083
|
-
const out = {
|
|
26084
|
-
id: t.id,
|
|
26085
|
-
name: t.name
|
|
26086
|
-
};
|
|
26087
|
-
const domain = str(t, "domain");
|
|
26088
|
-
if (domain) out.domain = domain;
|
|
26089
|
-
const emailDomain = str(t, "email_domain");
|
|
26090
|
-
if (emailDomain) out.email_domain = emailDomain;
|
|
26091
|
-
const enterpriseId = str(t, "enterprise_id");
|
|
26092
|
-
if (enterpriseId) out.enterprise_id = enterpriseId;
|
|
26093
|
-
const enterpriseName = str(t, "enterprise_name");
|
|
26094
|
-
if (enterpriseName) out.enterprise_name = enterpriseName;
|
|
26095
|
-
return out;
|
|
26096
|
-
};
|
|
26097
|
-
const stripResponseEnvelope = (response) => {
|
|
26098
|
-
const { ok, response_metadata, ...rest } = response;
|
|
26099
|
-
return rest;
|
|
26100
|
-
};
|
|
26101
|
-
const normalizeResponse = (method, response) => {
|
|
26102
|
-
if (!isRec(response)) return response;
|
|
26103
|
-
const r = response;
|
|
26104
|
-
switch (method) {
|
|
26105
|
-
case "conversations.history":
|
|
26106
|
-
case "conversations.replies": return { messages: asArray(r.messages).map(slimMessage) };
|
|
26107
|
-
case "conversations.info": return { channel: slimConversation(r.channel) };
|
|
26108
|
-
case "conversations.list": return { channels: asArray(r.channels).map(slimConversation) };
|
|
26109
|
-
case "users.info":
|
|
26110
|
-
case "users.lookupByEmail": return { user: slimUser(r.user) };
|
|
26111
|
-
case "users.list": return { users: asArray(r.members).map(slimUser) };
|
|
26112
|
-
case "files.info": return { file: slimFile(r.file) };
|
|
26113
|
-
case "files.list": return { files: asArray(r.files).map(slimFile) };
|
|
26114
|
-
case "team.info": return { team: slimTeam(r.team) };
|
|
26115
|
-
case "reactions.get": return isRec(r.message) ? {
|
|
26116
|
-
...stripResponseEnvelope(r),
|
|
26117
|
-
message: slimMessage(r.message)
|
|
26118
|
-
} : stripResponseEnvelope(r);
|
|
26119
|
-
default: return stripResponseEnvelope(r);
|
|
26120
|
-
}
|
|
26121
|
-
};
|
|
26122
|
-
//#endregion
|
|
26123
26147
|
//#region src/output/projection.ts
|
|
26124
26148
|
const projectFields = (value, fields) => {
|
|
26125
26149
|
if (fields === void 0 || fields.trim() === "") return value;
|