@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.
@@ -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`, `topic`,
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.13" };
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eliya-oss/agent-slack",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Slack context CLI for AI agents.",
5
5
  "type": "module",
6
6
  "bin": {