slack-axi 0.1.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 (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/dist/bin/slack-axi.d.ts +2 -0
  4. package/dist/bin/slack-axi.js +4 -0
  5. package/dist/bin/slack-axi.js.map +1 -0
  6. package/dist/src/auth/setup.d.ts +39 -0
  7. package/dist/src/auth/setup.js +119 -0
  8. package/dist/src/auth/setup.js.map +1 -0
  9. package/dist/src/cli.d.ts +2 -0
  10. package/dist/src/cli.js +66 -0
  11. package/dist/src/cli.js.map +1 -0
  12. package/dist/src/commands/auth.d.ts +2 -0
  13. package/dist/src/commands/auth.js +192 -0
  14. package/dist/src/commands/auth.js.map +1 -0
  15. package/dist/src/commands/cache.d.ts +2 -0
  16. package/dist/src/commands/cache.js +25 -0
  17. package/dist/src/commands/cache.js.map +1 -0
  18. package/dist/src/commands/catchup.d.ts +2 -0
  19. package/dist/src/commands/catchup.js +171 -0
  20. package/dist/src/commands/catchup.js.map +1 -0
  21. package/dist/src/commands/channels.d.ts +6 -0
  22. package/dist/src/commands/channels.js +147 -0
  23. package/dist/src/commands/channels.js.map +1 -0
  24. package/dist/src/commands/cite.d.ts +2 -0
  25. package/dist/src/commands/cite.js +38 -0
  26. package/dist/src/commands/cite.js.map +1 -0
  27. package/dist/src/commands/doctor.d.ts +2 -0
  28. package/dist/src/commands/doctor.js +46 -0
  29. package/dist/src/commands/doctor.js.map +1 -0
  30. package/dist/src/commands/home.d.ts +6 -0
  31. package/dist/src/commands/home.js +37 -0
  32. package/dist/src/commands/home.js.map +1 -0
  33. package/dist/src/commands/read.d.ts +4 -0
  34. package/dist/src/commands/read.js +178 -0
  35. package/dist/src/commands/read.js.map +1 -0
  36. package/dist/src/commands/search.d.ts +2 -0
  37. package/dist/src/commands/search.js +135 -0
  38. package/dist/src/commands/search.js.map +1 -0
  39. package/dist/src/commands/setup.d.ts +2 -0
  40. package/dist/src/commands/setup.js +21 -0
  41. package/dist/src/commands/setup.js.map +1 -0
  42. package/dist/src/commands/write.d.ts +4 -0
  43. package/dist/src/commands/write.js +148 -0
  44. package/dist/src/commands/write.js.map +1 -0
  45. package/dist/src/config.d.ts +71 -0
  46. package/dist/src/config.js +184 -0
  47. package/dist/src/config.js.map +1 -0
  48. package/dist/src/flags.d.ts +11 -0
  49. package/dist/src/flags.js +21 -0
  50. package/dist/src/flags.js.map +1 -0
  51. package/dist/src/meta.d.ts +3 -0
  52. package/dist/src/meta.js +17 -0
  53. package/dist/src/meta.js.map +1 -0
  54. package/dist/src/output.d.ts +25 -0
  55. package/dist/src/output.js +52 -0
  56. package/dist/src/output.js.map +1 -0
  57. package/dist/src/session.d.ts +17 -0
  58. package/dist/src/session.js +25 -0
  59. package/dist/src/session.js.map +1 -0
  60. package/dist/src/slack/cache.d.ts +40 -0
  61. package/dist/src/slack/cache.js +161 -0
  62. package/dist/src/slack/cache.js.map +1 -0
  63. package/dist/src/slack/client.d.ts +21 -0
  64. package/dist/src/slack/client.js +39 -0
  65. package/dist/src/slack/client.js.map +1 -0
  66. package/dist/src/slack/errors.d.ts +14 -0
  67. package/dist/src/slack/errors.js +54 -0
  68. package/dist/src/slack/errors.js.map +1 -0
  69. package/dist/src/slack/format.d.ts +8 -0
  70. package/dist/src/slack/format.js +20 -0
  71. package/dist/src/slack/format.js.map +1 -0
  72. package/dist/src/slack/permalink.d.ts +7 -0
  73. package/dist/src/slack/permalink.js +10 -0
  74. package/dist/src/slack/permalink.js.map +1 -0
  75. package/dist/src/slack/resolve.d.ts +22 -0
  76. package/dist/src/slack/resolve.js +118 -0
  77. package/dist/src/slack/resolve.js.map +1 -0
  78. package/dist/src/slack/scopes.d.ts +7 -0
  79. package/dist/src/slack/scopes.js +23 -0
  80. package/dist/src/slack/scopes.js.map +1 -0
  81. package/dist/src/slack/threads.d.ts +24 -0
  82. package/dist/src/slack/threads.js +63 -0
  83. package/dist/src/slack/threads.js.map +1 -0
  84. package/dist/src/slack/time.d.ts +46 -0
  85. package/dist/src/slack/time.js +156 -0
  86. package/dist/src/slack/time.js.map +1 -0
  87. package/dist/src/slack/ts.d.ts +5 -0
  88. package/dist/src/slack/ts.js +14 -0
  89. package/dist/src/slack/ts.js.map +1 -0
  90. package/package.json +41 -0
@@ -0,0 +1,178 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ import { takeBool, takeFlag } from "../flags.js";
3
+ import { encodeObject, joinBlocks, renderHelp, renderList, truncate } from "../output.js";
4
+ import { activeSession } from "../session.js";
5
+ import { allCachedUsers, ensureUsers } from "../slack/cache.js";
6
+ import { formatText, userName } from "../slack/format.js";
7
+ import { getPermalink } from "../slack/permalink.js";
8
+ import { channelLabel, resolveChannel } from "../slack/resolve.js";
9
+ import { fetchReplies, fetchThread, fetchWindow, isBot } from "../slack/threads.js";
10
+ import { formatDate, formatDateTime, formatRange, formatTime, resolveWindow, tsToEpochMs } from "../slack/time.js";
11
+ import { dottedTs, handle } from "../slack/ts.js";
12
+ export const READ_HELP = `usage: slack-axi read <channel> [flags]
13
+ Reads a channel over a time window, threads inlined, paginated to completion.
14
+ flags[8]:
15
+ --since <span> Relative window ending now: 7d, 24h, 90m (default: 7d)
16
+ --from <when> Window start: date (2026-04-23), datetime (2026-04-23T14:00), or span
17
+ --to <when> Window end (default: now)
18
+ --tz <zone> Timezone for parsing + display (default: America/New_York)
19
+ --limit <n> Max top-level messages to show (default: 50)
20
+ --threads <m> full | summary | none (default: full)
21
+ --exclude-bots Drop bot/automation messages
22
+ --cite Add a permalink column (for bulk citation); else use ts + \`cite\`
23
+ --full Don't truncate message text
24
+ examples:
25
+ slack-axi read #bid-rtd-analytics
26
+ slack-axi read #eng --from 2026-04-23 --to 2026-04-29
27
+ slack-axi read #eng --since 24h --threads summary`;
28
+ export const THREAD_HELP = `usage: slack-axi thread <channel> <ts>
29
+ Reads a single thread fully (parent + all replies), names + permalinks resolved.`;
30
+ const DEFAULT_LIMIT = 50;
31
+ export async function readCommand(args) {
32
+ if (args.includes("--help"))
33
+ return READ_HELP;
34
+ const f = parseReadFlags(args);
35
+ if (!f.channel)
36
+ throw new AxiError("usage: slack-axi read <channel> [flags]", "USAGE", []);
37
+ const session = await activeSession({ teamFlag: f.team });
38
+ const channel = await resolveChannel(session, f.channel);
39
+ const window = resolveWindow({ since: f.since, from: f.from, to: f.to, tz: f.tz }, Date.now());
40
+ let parents = await fetchWindow(session, channel.id, window.oldestMs, window.endMs);
41
+ let botFiltered = 0;
42
+ if (f.excludeBots) {
43
+ const before = parents.length;
44
+ parents = parents.filter((m) => !isBot(m));
45
+ botFiltered = before - parents.length;
46
+ }
47
+ const label = await channelLabel(session, channel);
48
+ const header = {
49
+ workspace: `${session.teamName ?? session.teamId} (${session.teamId})`,
50
+ channel: `${label} (${channel.id}, ${channel.type})`,
51
+ range: formatRange(window),
52
+ };
53
+ if (parents.length === 0) {
54
+ header.messages = `0 messages in ${label} between ${formatDate(window.oldestMs, window.tz)} and ${formatDate(window.endMs - 1, window.tz)} (${window.tz})`;
55
+ return joinBlocks(encodeObject(header), renderHelp(["Widen the window with `--since 30d` or `--from <date>`"]));
56
+ }
57
+ const total = parents.length;
58
+ const complete = total <= f.limit;
59
+ const displayed = complete ? parents : parents.slice(-f.limit);
60
+ await ensureUsers(session);
61
+ const users = allCachedUsers(session.teamId);
62
+ // Build date-grouped blocks: each displayed parent followed by its inlined replies (a thread is a unit).
63
+ const groups = new Map();
64
+ for (const parent of displayed) {
65
+ const date = formatDate(tsToEpochMs(parent.ts), window.tz);
66
+ const rows = groups.get(date) ?? [];
67
+ rows.push(await buildRow(session, channel.id, parent, users, window.tz, f, false));
68
+ if (parent.replyCount > 0 && f.threads === "full") {
69
+ const replies = await fetchReplies(session, channel.id, parent.ts);
70
+ for (const r of replies)
71
+ rows.push(await buildRow(session, channel.id, r, users, window.tz, f, true));
72
+ }
73
+ else if (parent.replyCount > 0 && f.threads === "summary") {
74
+ rows.push({ time: "", author: "", text: `↳ ${parent.replyCount} repl${parent.replyCount === 1 ? "y" : "ies"} (use \`thread ${channel.id} ${parent.ts}\`)`, ts: "" });
75
+ }
76
+ groups.set(date, rows);
77
+ }
78
+ header.messages = `${displayed.length} of ${total} top-level (threads inlined below)`;
79
+ header.complete = complete;
80
+ if (botFiltered > 0)
81
+ header.bot_filtered = botFiltered;
82
+ const blocks = [encodeObject(header)];
83
+ for (const [date, rows] of groups)
84
+ blocks.push(`${date}:\n${indentLines(renderList("messages", rows), 2)}`);
85
+ const help = [
86
+ f.threads !== "full" ? `Run \`slack-axi thread ${channel.id} <ts>\` to expand a thread` : undefined,
87
+ !complete ? `Showing the most recent ${f.limit} of ${total}; raise \`--limit <n>\` or narrow the window` : undefined,
88
+ !f.cite ? `Run \`slack-axi cite ${channel.id} <ts...>\` for permalinks to messages you cite` : undefined,
89
+ ].filter((l) => Boolean(l));
90
+ return joinBlocks(...blocks, renderHelp(help));
91
+ }
92
+ export async function threadCommand(args) {
93
+ if (args.includes("--help"))
94
+ return THREAD_HELP;
95
+ const team = takeFlag(args, "--team");
96
+ const full = takeBool(team.rest, "--full");
97
+ const positional = full.rest.filter((a) => !a.startsWith("-"));
98
+ const [target, ts] = positional;
99
+ if (!target || !ts)
100
+ throw new AxiError("usage: slack-axi thread <channel> <ts>", "USAGE", []);
101
+ const session = await activeSession({ teamFlag: team.value });
102
+ const channel = await resolveChannel(session, target);
103
+ const msgs = await fetchThread(session, channel.id, dottedTs(ts));
104
+ if (msgs.length === 0)
105
+ throw new AxiError("Thread not found", "MESSAGE_NOT_FOUND", ["Check the ts and channel"]);
106
+ await ensureUsers(session);
107
+ const users = allCachedUsers(session.teamId);
108
+ const tz = "America/New_York";
109
+ const rows = await Promise.all(msgs.map(async (m, i) => ({
110
+ time: formatDateTime(tsToEpochMs(m.ts), tz),
111
+ author: authorName(m, users),
112
+ text: (i === 0 ? "" : "↳ ") + (full.present ? formatText(m.text, users) : truncate(formatText(m.text, users))),
113
+ ts: handle(m.ts),
114
+ permalink: await getPermalink(session, channel.id, m.ts),
115
+ })));
116
+ return joinBlocks(encodeObject({ channel: `${await channelLabel(session, channel)} (${channel.id})`, replies: msgs.length - 1 }), renderList("messages", rows));
117
+ }
118
+ function parseReadFlags(args) {
119
+ const team = takeFlag(args, "--team");
120
+ const since = takeFlag(team.rest, "--since");
121
+ const from = takeFlag(since.rest, "--from");
122
+ const to = takeFlag(from.rest, "--to");
123
+ const tz = takeFlag(to.rest, "--tz");
124
+ const limit = takeFlag(tz.rest, "--limit");
125
+ const threads = takeFlag(limit.rest, "--threads");
126
+ const excludeBots = takeBool(threads.rest, "--exclude-bots");
127
+ const cite = takeBool(excludeBots.rest, "--cite");
128
+ const full = takeBool(cite.rest, "--full");
129
+ const channel = full.rest.find((a) => !a.startsWith("-"));
130
+ const mode = (threads.value ?? "full");
131
+ if (!["full", "summary", "none"].includes(mode)) {
132
+ throw new AxiError(`Invalid --threads '${threads.value}'`, "USAGE", ["Use: full | summary | none"]);
133
+ }
134
+ const lim = limit.value ? Number.parseInt(limit.value, 10) : DEFAULT_LIMIT;
135
+ return {
136
+ team: team.value,
137
+ channel,
138
+ since: since.value,
139
+ from: from.value,
140
+ to: to.value,
141
+ tz: tz.value,
142
+ limit: Number.isFinite(lim) && lim > 0 ? lim : DEFAULT_LIMIT,
143
+ threads: mode,
144
+ excludeBots: excludeBots.present,
145
+ cite: cite.present,
146
+ full: full.present,
147
+ };
148
+ }
149
+ async function buildRow(session, channelId, msg, users, tz, f, reply) {
150
+ const text = formatText(msg.text, users);
151
+ // Replies can fall on a later day than their parent (the thread is grouped under the parent's date),
152
+ // so reply rows carry a full date+time to stay unambiguous; parents show just the time-of-day.
153
+ const epoch = tsToEpochMs(msg.ts);
154
+ const row = {
155
+ time: reply ? formatDateTime(epoch, tz) : formatTime(epoch, tz),
156
+ author: authorName(msg, users),
157
+ text: (reply ? "↳ " : "") + (f.full ? text : truncate(text)),
158
+ ts: handle(msg.ts),
159
+ };
160
+ if (f.cite)
161
+ row.permalink = await getPermalink(session, channelId, msg.ts);
162
+ return row;
163
+ }
164
+ function authorName(msg, users) {
165
+ if (msg.user)
166
+ return userName(msg.user, users);
167
+ if (msg.botId)
168
+ return "(bot)";
169
+ return "(system)";
170
+ }
171
+ function indentLines(text, spaces) {
172
+ const pad = " ".repeat(spaces);
173
+ return text
174
+ .split("\n")
175
+ .map((line) => (line.length > 0 ? pad + line : line))
176
+ .join("\n");
177
+ }
178
+ //# sourceMappingURL=read.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/commands/read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAgB,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,WAAW,EAAiB,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,KAAK,EAAY,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACnH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;oDAe2B,CAAC;AAErD,MAAM,CAAC,MAAM,WAAW,GAAG;iFACsD,CAAC;AAElF,MAAM,aAAa,GAAG,EAAE,CAAC;AAIzB,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,CAAC,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,CAAC,CAAC,OAAO;QAAE,MAAM,IAAI,QAAQ,CAAC,yCAAyC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAE3F,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAE/F,IAAI,OAAO,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACpF,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QAClB,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC9B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACxC,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,MAAM,GAA4B;QACtC,SAAS,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG;QACtE,OAAO,EAAE,GAAG,KAAK,KAAK,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,GAAG;QACpD,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC;KAC3B,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,QAAQ,GAAG,iBAAiB,KAAK,YAAY,UAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,QAAQ,UAAU,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC;QAC3J,OAAO,UAAU,CACf,YAAY,CAAC,MAAM,CAAC,EACpB,UAAU,CAAC,CAAC,wDAAwD,CAAC,CAAC,CACvE,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC;IAC7B,MAAM,QAAQ,GAAG,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC;IAClC,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAE/D,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,yGAAyG;IACzG,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0C,CAAC;IACjE,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QAEnF,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAClD,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;YACnE,KAAK,MAAM,CAAC,IAAI,OAAO;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACxG,CAAC;aAAM,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;YAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,MAAM,CAAC,UAAU,QAAQ,MAAM,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,kBAAkB,OAAO,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACvK,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,QAAQ,GAAG,GAAG,SAAS,CAAC,MAAM,OAAO,KAAK,oCAAoC,CAAC;IACtF,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,IAAI,WAAW,GAAG,CAAC;QAAE,MAAM,CAAC,YAAY,GAAG,WAAW,CAAC;IAEvD,MAAM,MAAM,GAAa,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,MAAM,WAAW,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5G,MAAM,IAAI,GAAG;QACX,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,0BAA0B,OAAO,CAAC,EAAE,4BAA4B,CAAC,CAAC,CAAC,SAAS;QACnG,CAAC,QAAQ,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,KAAK,OAAO,KAAK,8CAA8C,CAAC,CAAC,CAAC,SAAS;QACpH,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,wBAAwB,OAAO,CAAC,EAAE,gDAAgD,CAAC,CAAC,CAAC,SAAS;KACzG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzC,OAAO,UAAU,CAAC,GAAG,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAc;IAChD,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,WAAW,CAAC;IAChD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/D,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,UAAU,CAAC;IAChC,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,QAAQ,CAAC,wCAAwC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAE9F,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,QAAQ,CAAC,kBAAkB,EAAE,mBAAmB,EAAE,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAEjH,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,MAAM,EAAE,GAAG,kBAAkB,CAAC;IAC9B,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACxB,IAAI,EAAE,cAAc,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3C,MAAM,EAAE,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC;QAC5B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC9G,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAChB,SAAS,EAAE,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CAAC,CACJ,CAAC;IAEF,OAAO,UAAU,CACf,YAAY,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAC9G,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAC7B,CAAC;AACJ,CAAC;AAkBD,SAAS,cAAc,CAAC,IAAc;IACpC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC5C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,MAAM,CAAe,CAAC;IACrD,IAAI,CAAC,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,IAAI,QAAQ,CAAC,sBAAsB,OAAO,CAAC,KAAK,GAAG,EAAE,OAAO,EAAE,CAAC,4BAA4B,CAAC,CAAC,CAAC;IACtG,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC;IAC3E,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,OAAO;QACP,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,IAAI,EAAE,IAAI,CAAC,KAAK;QAChB,EAAE,EAAE,EAAE,CAAC,KAAK;QACZ,EAAE,EAAE,EAAE,CAAC,KAAK;QACZ,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa;QAC5D,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,WAAW,CAAC,OAAO;QAChC,IAAI,EAAE,IAAI,CAAC,OAAO;QAClB,IAAI,EAAE,IAAI,CAAC,OAAO;KACnB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,OAAgB,EAChB,SAAiB,EACjB,GAAQ,EACR,KAA+B,EAC/B,EAAU,EACV,CAAY,EACZ,KAAc;IAEd,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACzC,qGAAqG;IACrG,+FAA+F;IAC/F,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,GAAG,GAA4B;QACnC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC;QAC/D,MAAM,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC;QAC9B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5D,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;KACnB,CAAC;IACF,IAAI,CAAC,CAAC,IAAI;QAAE,GAAG,CAAC,SAAS,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC3E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,UAAU,CAAC,GAAQ,EAAE,KAA+B;IAC3D,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,GAAG,CAAC,KAAK;QAAE,OAAO,OAAO,CAAC;IAC9B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,MAAc;IAC/C,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SACpD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const SEARCH_HELP = "usage: slack-axi search \"<query>\" [flags]\nFinds messages across the workspace (search.messages). Use this to FIND a thing \u2014 to read a channel\nover a time window completely, use `read <channel> --from --to` instead.\nflags[6]:\n --in <channel> Limit to a channel (#name or id)\n --from <@user> Limit to a sender\n --with <@user> Limit to conversations that include this person (any sender)\n --after <when> On/after a date (2026-05-01) or span (7d)\n --before <when> On/before a date or span\n --limit <n> Max matches (default 20)\n --cite Add a permalink column\nexamples:\n slack-axi search \"proposal loss\"\n slack-axi search \"token refresh\" --in #eng --after 2026-05-01\n slack-axi search \"deploy\" --from @alice";
2
+ export declare function searchCommand(args: string[]): Promise<string>;
@@ -0,0 +1,135 @@
1
+ import { AxiError } from "axi-sdk-js";
2
+ import { takeBool, takeFlag } from "../flags.js";
3
+ import { encodeObject, joinBlocks, renderHelp, renderList, truncate } from "../output.js";
4
+ import { activeSession } from "../session.js";
5
+ import { allCachedUsers, ensureUsers } from "../slack/cache.js";
6
+ import { formatText } from "../slack/format.js";
7
+ import { looksLikeId, normalizeChannelArg, resolveChannel } from "../slack/resolve.js";
8
+ import { handle } from "../slack/ts.js";
9
+ import { DEFAULT_TZ, formatDate, formatDateTime, parseSpanMs, tsToEpochMs } from "../slack/time.js";
10
+ export const SEARCH_HELP = `usage: slack-axi search "<query>" [flags]
11
+ Finds messages across the workspace (search.messages). Use this to FIND a thing — to read a channel
12
+ over a time window completely, use \`read <channel> --from --to\` instead.
13
+ flags[6]:
14
+ --in <channel> Limit to a channel (#name or id)
15
+ --from <@user> Limit to a sender
16
+ --with <@user> Limit to conversations that include this person (any sender)
17
+ --after <when> On/after a date (2026-05-01) or span (7d)
18
+ --before <when> On/before a date or span
19
+ --limit <n> Max matches (default 20)
20
+ --cite Add a permalink column
21
+ examples:
22
+ slack-axi search "proposal loss"
23
+ slack-axi search "token refresh" --in #eng --after 2026-05-01
24
+ slack-axi search "deploy" --from @alice`;
25
+ const DEFAULT_LIMIT = 20;
26
+ export async function searchCommand(args) {
27
+ if (args.includes("--help"))
28
+ return SEARCH_HELP;
29
+ const team = takeFlag(args, "--team");
30
+ const inFlag = takeFlag(team.rest, "--in");
31
+ const fromFlag = takeFlag(inFlag.rest, "--from");
32
+ const withFlag = takeFlag(fromFlag.rest, "--with");
33
+ const after = takeFlag(withFlag.rest, "--after");
34
+ const before = takeFlag(after.rest, "--before");
35
+ const limitFlag = takeFlag(before.rest, "--limit");
36
+ const citeFlag = takeBool(limitFlag.rest, "--cite");
37
+ const cite = citeFlag.present;
38
+ const positional = citeFlag.rest.filter((a) => !a.startsWith("-"));
39
+ const query = positional.join(" ").trim();
40
+ if (!query) {
41
+ throw new AxiError('usage: slack-axi search "<query>" [flags]', "USAGE", [
42
+ 'Pass a search query, e.g. slack-axi search "proposal loss"',
43
+ ]);
44
+ }
45
+ const limit = limitFlag.value ? Number.parseInt(limitFlag.value, 10) : DEFAULT_LIMIT;
46
+ const session = await activeSession({ teamFlag: team.value });
47
+ const tz = DEFAULT_TZ;
48
+ // Translate friendly flags into Slack search modifiers.
49
+ const parts = [query];
50
+ if (inFlag.value)
51
+ parts.push(`in:#${await channelNameFor(session, inFlag.value)}`);
52
+ if (fromFlag.value)
53
+ parts.push(`from:${ensureAt(fromFlag.value)}`);
54
+ if (withFlag.value)
55
+ parts.push(`with:${ensureAt(withFlag.value)}`);
56
+ if (after.value)
57
+ parts.push(`after:${toSearchDate(after.value, tz)}`);
58
+ if (before.value)
59
+ parts.push(`before:${toSearchDate(before.value, tz)}`);
60
+ const fullQuery = parts.join(" ");
61
+ let res;
62
+ try {
63
+ res = await session.client.search.messages({
64
+ query: fullQuery,
65
+ count: Number.isFinite(limit) && limit > 0 ? limit : DEFAULT_LIMIT,
66
+ sort: "timestamp",
67
+ });
68
+ }
69
+ catch (err) {
70
+ // search.messages requires the user-only search:read scope.
71
+ const code = err?.data?.error;
72
+ if (code === "missing_scope") {
73
+ throw new AxiError("Token is missing the search:read scope", "SCOPE_MISSING", [
74
+ "Re-run `slack-axi auth setup`, add search:read, re-install the app, then `auth login`",
75
+ ]);
76
+ }
77
+ throw err;
78
+ }
79
+ const matches = res.messages?.matches ?? [];
80
+ const total = res.messages?.total ?? matches.length;
81
+ if (matches.length === 0) {
82
+ return joinBlocks(encodeObject({ workspace: `${session.teamName ?? session.teamId} (${session.teamId})`, query: fullQuery }), encodeObject({ matches: `0 matches for "${fullQuery}"` }), renderHelp(["Broaden the query, or use `slack-axi read <channel> --from --to` to sweep a window"]));
83
+ }
84
+ await ensureUsers(session);
85
+ const users = allCachedUsers(session.teamId);
86
+ const rows = matches.map((m) => {
87
+ const ts = String(m.ts ?? "");
88
+ const ch = m.channel;
89
+ const row = {
90
+ channel: formatMatchChannel(ch),
91
+ author: m.username || (m.user ? `@${m.user}` : "(unknown)"),
92
+ when: m.ts ? formatDateTime(tsToEpochMs(ts), tz) : "",
93
+ text: truncate(formatText(typeof m.text === "string" ? m.text : "", users)),
94
+ ts: handle(ts),
95
+ };
96
+ if (cite && typeof m.permalink === "string")
97
+ row.permalink = m.permalink;
98
+ return row;
99
+ });
100
+ const help = [
101
+ "To read a result's channel over a window completely, use `slack-axi read <channel> --from <date> --to <date>`",
102
+ rows.length < total ? `Showing ${rows.length} of ${total}; raise with \`--limit <n>\`` : undefined,
103
+ !cite ? "Add `--cite` (or run `slack-axi cite <channel> <ts>`) for permalinks to cite" : undefined,
104
+ ].filter((l) => Boolean(l));
105
+ return joinBlocks(encodeObject({ workspace: `${session.teamName ?? session.teamId} (${session.teamId})`, query: fullQuery }), renderList("matches", rows, { total }), renderHelp(help));
106
+ }
107
+ /** Resolve a `--in` channel argument to its bare name for the `in:#name` modifier. */
108
+ async function channelNameFor(session, arg) {
109
+ if (looksLikeId(arg)) {
110
+ const ch = await resolveChannel(session, arg);
111
+ return ch.name || arg;
112
+ }
113
+ return normalizeChannelArg(arg);
114
+ }
115
+ /** Label a match's channel: `#name (id)` for channels/group DMs, `dm (id)` for a 1:1 (D…) id. */
116
+ function formatMatchChannel(ch) {
117
+ if (!ch?.id)
118
+ return ch?.name ? `#${ch.name}` : "?";
119
+ if (ch.id.startsWith("D"))
120
+ return `dm (${ch.id})`;
121
+ return ch.name ? `#${ch.name} (${ch.id})` : ch.id;
122
+ }
123
+ /** Ensure a user reference has a leading `@` for `from:`/`with:` modifiers. */
124
+ function ensureAt(user) {
125
+ return user.startsWith("@") ? user : `@${user}`;
126
+ }
127
+ /** Slack `after:`/`before:` take a YYYY-MM-DD date; accept a date passthrough or a relative span. */
128
+ function toSearchDate(when, tz) {
129
+ const span = parseSpanMs(when);
130
+ if (span !== undefined)
131
+ return formatDate(Date.now() - span, tz);
132
+ const date = /^(\d{4}-\d{2}-\d{2})/.exec(when.trim());
133
+ return date ? date[1] : when;
134
+ }
135
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/commands/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const SETUP_HELP = "usage: slack-axi setup hooks\nInstall or repair agent SessionStart hooks so each session starts with slack-axi's home view\n(workspace + channel count) as ambient context. Idempotent; repairs a stale executable path.\nexamples:\n slack-axi setup hooks";
2
+ export declare function setupCommand(args: string[]): Promise<string>;
@@ -0,0 +1,21 @@
1
+ import { AxiError, installSessionStartHooks } from "axi-sdk-js";
2
+ import { encodeBlock, joinBlocks, renderHelp } from "../output.js";
3
+ export const SETUP_HELP = `usage: slack-axi setup hooks
4
+ Install or repair agent SessionStart hooks so each session starts with slack-axi's home view
5
+ (workspace + channel count) as ambient context. Idempotent; repairs a stale executable path.
6
+ examples:
7
+ slack-axi setup hooks`;
8
+ export async function setupCommand(args) {
9
+ if (args.includes("--help"))
10
+ return SETUP_HELP;
11
+ if (args[0] !== "hooks") {
12
+ throw new AxiError(`Unknown setup action: ${args[0] ?? "(none)"}`, "USAGE", ["Run `slack-axi setup hooks`"]);
13
+ }
14
+ const errors = [];
15
+ installSessionStartHooks({ marker: "slack-axi", timeoutSeconds: 10, onError: (m) => errors.push(m) });
16
+ if (errors.length > 0) {
17
+ throw new AxiError("Hook installation reported problems", "HOOK_INSTALL_FAILED", errors);
18
+ }
19
+ return joinBlocks(encodeBlock("hooks", { status: "installed", integrations: "Claude Code, Codex, OpenCode", marker: "slack-axi" }), renderHelp(["Restart your agent session to receive slack-axi ambient context"]));
20
+ }
21
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/commands/setup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnE,MAAM,CAAC,MAAM,UAAU,GAAG;;;;wBAIF,CAAC;AAEzB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,UAAU,CAAC;IAC/C,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;QACxB,MAAM,IAAI,QAAQ,CAAC,yBAAyB,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,EAAE,EAAE,OAAO,EAAE,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAC/G,CAAC;IAED,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,wBAAwB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACtG,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,QAAQ,CAAC,qCAAqC,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC3F,CAAC;IAED,OAAO,UAAU,CACf,WAAW,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,8BAA8B,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,EAChH,UAAU,CAAC,CAAC,iEAAiE,CAAC,CAAC,CAChF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const REACT_HELP = "usage: slack-axi react <channel> <ts> <:emoji:>\nAdds an emoji reaction to a message. Idempotent \u2014 re-reacting is a no-op.\nexamples:\n slack-axi react #eng 1717589640123456 :eyes:\n slack-axi react C09GHV2RUSJ 1717589640.123456 tada";
2
+ export declare const DRAFT_HELP = "usage: slack-axi draft <channel> \"<text>\" [--reply <ts>]\n slack-axi draft send <draft-id>\n slack-axi draft list\n slack-axi draft discard <draft-id>\nPrepares a message for approval \u2014 `draft` does NOT send. Review it, then `draft send <id>` posts it.\nexamples:\n slack-axi draft #eng \"Deploy is green \u2705\"\n slack-axi draft #eng --reply 1717589640123456 \"confirmed\"\n slack-axi draft send d_1a2b3c4d\n slack-axi draft list";
3
+ export declare function reactCommand(args: string[]): Promise<string>;
4
+ export declare function draftCommand(args: string[]): Promise<string>;
@@ -0,0 +1,148 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { AxiError } from "axi-sdk-js";
3
+ import { getDraft, getStoredToken, listDrafts, removeDraft, writeDraft, } from "../config.js";
4
+ import { takeFlag } from "../flags.js";
5
+ import { encodeObject, joinBlocks, renderHelp, renderList, truncate } from "../output.js";
6
+ import { activeSession } from "../session.js";
7
+ import { getPermalink } from "../slack/permalink.js";
8
+ import { channelLabel, resolveChannel } from "../slack/resolve.js";
9
+ import { toAxiError } from "../slack/errors.js";
10
+ import { dottedTs, handle } from "../slack/ts.js";
11
+ export const REACT_HELP = `usage: slack-axi react <channel> <ts> <:emoji:>
12
+ Adds an emoji reaction to a message. Idempotent — re-reacting is a no-op.
13
+ examples:
14
+ slack-axi react #eng 1717589640123456 :eyes:
15
+ slack-axi react C09GHV2RUSJ 1717589640.123456 tada`;
16
+ export const DRAFT_HELP = `usage: slack-axi draft <channel> "<text>" [--reply <ts>]
17
+ slack-axi draft send <draft-id>
18
+ slack-axi draft list
19
+ slack-axi draft discard <draft-id>
20
+ Prepares a message for approval — \`draft\` does NOT send. Review it, then \`draft send <id>\` posts it.
21
+ examples:
22
+ slack-axi draft #eng "Deploy is green ✅"
23
+ slack-axi draft #eng --reply 1717589640123456 "confirmed"
24
+ slack-axi draft send d_1a2b3c4d
25
+ slack-axi draft list`;
26
+ export async function reactCommand(args) {
27
+ if (args.includes("--help"))
28
+ return REACT_HELP;
29
+ const team = takeFlag(args, "--team");
30
+ const [channelArg, tsArg, emojiArg] = team.rest.filter((a) => !a.startsWith("-"));
31
+ if (!channelArg || !tsArg || !emojiArg) {
32
+ throw new AxiError("usage: slack-axi react <channel> <ts> <:emoji:>", "USAGE", []);
33
+ }
34
+ const name = emojiArg.replace(/:/g, "").trim();
35
+ const session = await activeSession({ teamFlag: team.value, mutation: true });
36
+ const channel = await resolveChannel(session, channelArg);
37
+ const ts = dottedTs(tsArg);
38
+ try {
39
+ await session.client.reactions.add({ channel: channel.id, timestamp: ts, name });
40
+ }
41
+ catch (err) {
42
+ const code = err?.data?.error;
43
+ if (code === "already_reacted") {
44
+ return encodeObject({ reaction: `:${name}: already on ${await channelLabel(session, channel)} message ${handle(ts)} (no-op)` });
45
+ }
46
+ throw toAxiError(err, { team: session.teamId, channel: channelArg });
47
+ }
48
+ return encodeObject({ reaction: `:${name}: added`, channel: `${await channelLabel(session, channel)} (${channel.id})`, ts: handle(ts) });
49
+ }
50
+ export async function draftCommand(args) {
51
+ if (args.includes("--help"))
52
+ return DRAFT_HELP;
53
+ const sub = args[0];
54
+ if (sub === "send")
55
+ return draftSend(args.slice(1));
56
+ if (sub === "list")
57
+ return draftList();
58
+ if (sub === "discard")
59
+ return draftDiscard(args.slice(1));
60
+ return draftCreate(args);
61
+ }
62
+ async function draftCreate(args) {
63
+ const team = takeFlag(args, "--team");
64
+ const reply = takeFlag(team.rest, "--reply");
65
+ const positional = reply.rest.filter((a) => !a.startsWith("-"));
66
+ const channelArg = positional[0];
67
+ const text = positional.slice(1).join(" ");
68
+ if (!channelArg || !text) {
69
+ throw new AxiError('usage: slack-axi draft <channel> "<text>" [--reply <ts>]', "USAGE", []);
70
+ }
71
+ // Creating a draft is local-only (no Slack write), but we resolve the channel to validate + label it.
72
+ const session = await activeSession({ teamFlag: team.value });
73
+ const channel = await resolveChannel(session, channelArg);
74
+ const label = await channelLabel(session, channel);
75
+ const draft = {
76
+ id: `d_${randomUUID().slice(0, 8)}`,
77
+ team: session.teamId,
78
+ channel_id: channel.id,
79
+ channel: label,
80
+ ...(reply.value ? { reply_to: dottedTs(reply.value) } : {}),
81
+ text,
82
+ created_at: new Date().toISOString(),
83
+ };
84
+ writeDraft(draft);
85
+ return joinBlocks(encodeObject({
86
+ draft: draft.id,
87
+ workspace: `${session.teamName ?? session.teamId} (${session.teamId})`,
88
+ channel: `${label} (${channel.id})`,
89
+ ...(draft.reply_to ? { reply_to: handle(draft.reply_to) } : {}),
90
+ text: draft.text,
91
+ }), renderHelp([`Review it, then post with \`slack-axi draft send ${draft.id}\` (or discard with \`draft discard ${draft.id}\`)`]));
92
+ }
93
+ async function draftSend(args) {
94
+ const id = args.find((a) => !a.startsWith("-"));
95
+ if (!id)
96
+ throw new AxiError("usage: slack-axi draft send <draft-id>", "USAGE", []);
97
+ const draft = getDraft(id);
98
+ if (!draft) {
99
+ throw new AxiError(`Draft ${id} not found`, "DRAFT_NOT_FOUND", ["Run `slack-axi draft list` to see pending drafts"]);
100
+ }
101
+ if (draft.sent) {
102
+ return encodeObject({ sent: `${id} already sent (no-op)`, ts: handle(draft.sent.ts), permalink: draft.sent.permalink });
103
+ }
104
+ if (!getStoredToken(draft.team)) {
105
+ throw new AxiError(`Draft's workspace ${draft.team} is no longer authenticated`, "TEAM_NOT_FOUND", [
106
+ "Re-auth with `slack-axi auth login`, or discard the draft",
107
+ ]);
108
+ }
109
+ // Send to the draft's own workspace (explicit team satisfies write-protection).
110
+ const session = await activeSession({ teamFlag: draft.team, mutation: true });
111
+ let posted;
112
+ try {
113
+ posted = await session.client.chat.postMessage({
114
+ channel: draft.channel_id,
115
+ text: draft.text,
116
+ ...(draft.reply_to ? { thread_ts: draft.reply_to } : {}),
117
+ });
118
+ }
119
+ catch (err) {
120
+ throw toAxiError(err, { team: draft.team, channel: draft.channel });
121
+ }
122
+ const ts = String(posted.ts ?? "");
123
+ const permalink = ts ? await getPermalink(session, draft.channel_id, ts) : "";
124
+ draft.sent = { ts, permalink, at: new Date().toISOString() };
125
+ writeDraft(draft);
126
+ return encodeObject({ sent: id, channel: `${draft.channel} (${draft.channel_id})`, ts: handle(ts), permalink });
127
+ }
128
+ function draftList() {
129
+ const drafts = listDrafts();
130
+ if (drafts.length === 0) {
131
+ return joinBlocks(encodeObject({ drafts: "0 drafts" }), renderHelp(['Create one with `slack-axi draft <channel> "<text>"`']));
132
+ }
133
+ const rows = drafts.map((d) => ({
134
+ id: d.id,
135
+ channel: d.channel,
136
+ status: d.sent ? "sent" : d.reply_to ? "reply (pending)" : "pending",
137
+ text: truncate(d.text, 80),
138
+ }));
139
+ return joinBlocks(renderList("drafts", rows), renderHelp(["Post a pending draft with `slack-axi draft send <id>`"]));
140
+ }
141
+ function draftDiscard(args) {
142
+ const id = args.find((a) => !a.startsWith("-"));
143
+ if (!id)
144
+ throw new AxiError("usage: slack-axi draft discard <draft-id>", "USAGE", []);
145
+ const existed = removeDraft(id);
146
+ return encodeObject({ discarded: existed ? id : `${id} (not found — no-op)` });
147
+ }
148
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/commands/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAEL,QAAQ,EACR,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,CAAC,MAAM,UAAU,GAAG;;;;qDAI2B,CAAC;AAEtD,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;uBASH,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,UAAU,CAAC;IAC/C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAClF,IAAI,CAAC,UAAU,IAAI,CAAC,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,QAAQ,CAAC,iDAAiD,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAE/C,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE3B,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACnF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAAqC,EAAE,IAAI,EAAE,KAAK,CAAC;QACjE,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC/B,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAI,IAAI,gBAAgB,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,MAAM,CAAC,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;QAClI,CAAC;QACD,MAAM,UAAU,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,YAAY,CAAC,EAAE,QAAQ,EAAE,IAAI,IAAI,SAAS,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;AAC3I,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,UAAU,CAAC;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,SAAS,EAAE,CAAC;IACvC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAc;IACvC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,MAAM,UAAU,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CAAC,0DAA0D,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,sGAAsG;IACtG,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9D,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAC1D,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAEnD,MAAM,KAAK,GAAU;QACnB,EAAE,EAAE,KAAK,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE;QACnC,IAAI,EAAE,OAAO,CAAC,MAAM;QACpB,UAAU,EAAE,OAAO,CAAC,EAAE;QACtB,OAAO,EAAE,KAAK;QACd,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI;QACJ,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;IACF,UAAU,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,UAAU,CACf,YAAY,CAAC;QACX,KAAK,EAAE,KAAK,CAAC,EAAE;QACf,SAAS,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG;QACtE,OAAO,EAAE,GAAG,KAAK,KAAK,OAAO,CAAC,EAAE,GAAG;QACnC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,IAAI,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC,EACF,UAAU,CAAC,CAAC,oDAAoD,KAAK,CAAC,EAAE,uCAAuC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAC/H,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAc;IACrC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,QAAQ,CAAC,wCAAwC,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACnF,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,QAAQ,CAAC,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC,kDAAkD,CAAC,CAAC,CAAC;IACvH,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;IAC1H,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,QAAQ,CAAC,qBAAqB,KAAK,CAAC,IAAI,6BAA6B,EAAE,gBAAgB,EAAE;YACjG,2DAA2D;SAC5D,CAAC,CAAC;IACL,CAAC;IAED,gFAAgF;IAChF,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC;YAC7C,OAAO,EAAE,KAAK,CAAC,UAAU;YACzB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,UAAU,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IACnC,MAAM,SAAS,GAAG,EAAE,CAAC,CAAC,CAAC,MAAM,YAAY,CAAC,OAAO,EAAE,KAAK,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,KAAK,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC7D,UAAU,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,UAAU,GAAG,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;AAClH,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,UAAU,CACf,YAAY,CAAC,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,EACpC,UAAU,CAAC,CAAC,sDAAsD,CAAC,CAAC,CACrE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC9B,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS;QACpE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;KAC3B,CAAC,CAAC,CAAC;IACJ,OAAO,UAAU,CACf,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,EAC1B,UAAU,CAAC,CAAC,uDAAuD,CAAC,CAAC,CACtE,CAAC;AACJ,CAAC;AAED,SAAS,YAAY,CAAC,IAAc;IAClC,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;IAChD,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,QAAQ,CAAC,2CAA2C,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;IACtF,MAAM,OAAO,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAChC,OAAO,YAAY,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,sBAAsB,EAAE,CAAC,CAAC;AACjF,CAAC"}
@@ -0,0 +1,71 @@
1
+ /** A stored user token for one workspace (team). Written at `auth login`. */
2
+ export interface StoredToken {
3
+ team_id: string;
4
+ team_name: string;
5
+ user_id: string;
6
+ user_name?: string;
7
+ token: string;
8
+ scopes: string[];
9
+ obtained_at: string;
10
+ }
11
+ export interface UserConfig {
12
+ default_team?: string;
13
+ }
14
+ /** Result of resolving which token/workspace a command should act against. */
15
+ export interface ActiveToken {
16
+ token: string;
17
+ teamId: string | undefined;
18
+ teamName: string | undefined;
19
+ scopes: string[] | undefined;
20
+ source: "env" | "flag" | "default" | "single";
21
+ }
22
+ /** Base config directory: $SLACK_AXI_CONFIG_DIR, else $XDG_CONFIG_HOME/slack-axi, else ~/.config/slack-axi. */
23
+ export declare function configDir(): string;
24
+ export declare function userConfigPath(): string;
25
+ export declare function setupStatePath(): string;
26
+ export declare function manifestPath(): string;
27
+ export declare function setupHtmlPath(): string;
28
+ export declare function workspaceDir(teamId: string): string;
29
+ export declare function tokenPath(teamId: string): string;
30
+ export declare function cacheChannelsPath(teamId: string): string;
31
+ export declare function cacheUsersPath(teamId: string): string;
32
+ /** A locally-stored message draft (prepare→approve; never auto-sent). */
33
+ export interface Draft {
34
+ id: string;
35
+ team: string;
36
+ channel_id: string;
37
+ channel: string;
38
+ reply_to?: string;
39
+ text: string;
40
+ created_at: string;
41
+ sent?: {
42
+ ts: string;
43
+ permalink: string;
44
+ at: string;
45
+ };
46
+ }
47
+ export declare function getDraft(id: string): Draft | undefined;
48
+ export declare function writeDraft(draft: Draft): void;
49
+ export declare function removeDraft(id: string): boolean;
50
+ export declare function listDrafts(): Draft[];
51
+ export declare function readUserConfig(): UserConfig;
52
+ export declare function writeUserConfig(config: UserConfig): void;
53
+ export declare function getDefaultTeam(): string | undefined;
54
+ export declare function setDefaultTeam(teamId: string): void;
55
+ /** Team ids with a stored token, in directory order. */
56
+ export declare function listWorkspaceIds(): string[];
57
+ export declare function listWorkspaces(): StoredToken[];
58
+ export declare function getStoredToken(teamId: string): StoredToken | undefined;
59
+ /** Persist a token (mode 0600); first stored workspace becomes the default. */
60
+ export declare function writeStoredToken(token: StoredToken): void;
61
+ /** Delete a workspace's stored token + dir. Idempotent. Repairs a dangling default. */
62
+ export declare function removeWorkspace(teamId: string): boolean;
63
+ /**
64
+ * Resolve which token/workspace a command should act against, per
65
+ * specs/behaviors/auth-and-workspaces.md. Order: env → --team → default → single → error.
66
+ * Mutations with 2+ stored workspaces require an explicit team (env or flag).
67
+ */
68
+ export declare function resolveActiveToken(options: {
69
+ teamFlag?: string;
70
+ mutation?: boolean;
71
+ }): ActiveToken;