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.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/bin/slack-axi.d.ts +2 -0
- package/dist/bin/slack-axi.js +4 -0
- package/dist/bin/slack-axi.js.map +1 -0
- package/dist/src/auth/setup.d.ts +39 -0
- package/dist/src/auth/setup.js +119 -0
- package/dist/src/auth/setup.js.map +1 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +66 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/commands/auth.d.ts +2 -0
- package/dist/src/commands/auth.js +192 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/cache.d.ts +2 -0
- package/dist/src/commands/cache.js +25 -0
- package/dist/src/commands/cache.js.map +1 -0
- package/dist/src/commands/catchup.d.ts +2 -0
- package/dist/src/commands/catchup.js +171 -0
- package/dist/src/commands/catchup.js.map +1 -0
- package/dist/src/commands/channels.d.ts +6 -0
- package/dist/src/commands/channels.js +147 -0
- package/dist/src/commands/channels.js.map +1 -0
- package/dist/src/commands/cite.d.ts +2 -0
- package/dist/src/commands/cite.js +38 -0
- package/dist/src/commands/cite.js.map +1 -0
- package/dist/src/commands/doctor.d.ts +2 -0
- package/dist/src/commands/doctor.js +46 -0
- package/dist/src/commands/doctor.js.map +1 -0
- package/dist/src/commands/home.d.ts +6 -0
- package/dist/src/commands/home.js +37 -0
- package/dist/src/commands/home.js.map +1 -0
- package/dist/src/commands/read.d.ts +4 -0
- package/dist/src/commands/read.js +178 -0
- package/dist/src/commands/read.js.map +1 -0
- package/dist/src/commands/search.d.ts +2 -0
- package/dist/src/commands/search.js +135 -0
- package/dist/src/commands/search.js.map +1 -0
- package/dist/src/commands/setup.d.ts +2 -0
- package/dist/src/commands/setup.js +21 -0
- package/dist/src/commands/setup.js.map +1 -0
- package/dist/src/commands/write.d.ts +4 -0
- package/dist/src/commands/write.js +148 -0
- package/dist/src/commands/write.js.map +1 -0
- package/dist/src/config.d.ts +71 -0
- package/dist/src/config.js +184 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/flags.d.ts +11 -0
- package/dist/src/flags.js +21 -0
- package/dist/src/flags.js.map +1 -0
- package/dist/src/meta.d.ts +3 -0
- package/dist/src/meta.js +17 -0
- package/dist/src/meta.js.map +1 -0
- package/dist/src/output.d.ts +25 -0
- package/dist/src/output.js +52 -0
- package/dist/src/output.js.map +1 -0
- package/dist/src/session.d.ts +17 -0
- package/dist/src/session.js +25 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/slack/cache.d.ts +40 -0
- package/dist/src/slack/cache.js +161 -0
- package/dist/src/slack/cache.js.map +1 -0
- package/dist/src/slack/client.d.ts +21 -0
- package/dist/src/slack/client.js +39 -0
- package/dist/src/slack/client.js.map +1 -0
- package/dist/src/slack/errors.d.ts +14 -0
- package/dist/src/slack/errors.js +54 -0
- package/dist/src/slack/errors.js.map +1 -0
- package/dist/src/slack/format.d.ts +8 -0
- package/dist/src/slack/format.js +20 -0
- package/dist/src/slack/format.js.map +1 -0
- package/dist/src/slack/permalink.d.ts +7 -0
- package/dist/src/slack/permalink.js +10 -0
- package/dist/src/slack/permalink.js.map +1 -0
- package/dist/src/slack/resolve.d.ts +22 -0
- package/dist/src/slack/resolve.js +118 -0
- package/dist/src/slack/resolve.js.map +1 -0
- package/dist/src/slack/scopes.d.ts +7 -0
- package/dist/src/slack/scopes.js +23 -0
- package/dist/src/slack/scopes.js.map +1 -0
- package/dist/src/slack/threads.d.ts +24 -0
- package/dist/src/slack/threads.js +63 -0
- package/dist/src/slack/threads.js.map +1 -0
- package/dist/src/slack/time.d.ts +46 -0
- package/dist/src/slack/time.js +156 -0
- package/dist/src/slack/time.js.map +1 -0
- package/dist/src/slack/ts.d.ts +5 -0
- package/dist/src/slack/ts.js +14 -0
- package/dist/src/slack/ts.js.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,171 @@
|
|
|
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, getChannels } 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 { fetchWindow, isBot } from "../slack/threads.js";
|
|
10
|
+
import { batchWindows, formatDate, formatDateTime, formatRange, parseSpanMs, resolveWindow, tsToEpochMs } from "../slack/time.js";
|
|
11
|
+
import { handle } from "../slack/ts.js";
|
|
12
|
+
export const CATCHUP_HELP = `usage: slack-axi catchup [flags]
|
|
13
|
+
Sweeps a SCOPED set of channels over a time window and returns everything posted — a multi-channel read.
|
|
14
|
+
Slack has no cross-conversation history endpoint, so this fans out per channel; scope keeps it bounded.
|
|
15
|
+
flags[10]:
|
|
16
|
+
--since <span> Window ending now: 1d, 12h, 90m (default: 1d)
|
|
17
|
+
--from <when> Window start (date / datetime / span); --to end (default now)
|
|
18
|
+
--tz <zone> Timezone (default America/New_York)
|
|
19
|
+
--every <span> PLAN MODE: emit batch windows (e.g. 1w) instead of fetching — for big catch-ups
|
|
20
|
+
--type <a,b> Conversation types to sweep (default: public,private)
|
|
21
|
+
--match <q> Only channels whose name contains <q>
|
|
22
|
+
--in <c1,c2,...> Explicit channel list (#name/name/id), overrides --type/--match
|
|
23
|
+
--limit-per <n> Max messages per channel (default 50)
|
|
24
|
+
--max-channels <n> Refuse to sweep more than this many (default 40)
|
|
25
|
+
--exclude-bots Drop bot/automation messages
|
|
26
|
+
--cite Add a permalink column
|
|
27
|
+
Threads are not inlined here (kept cheap across many channels); a [+N replies] note marks threads —
|
|
28
|
+
expand one with \`read <channel>\` or \`thread <channel> <ts>\`.
|
|
29
|
+
examples:
|
|
30
|
+
slack-axi catchup --since 1d --match bid
|
|
31
|
+
slack-axi catchup --from 2026-05-01 --to 2026-06-07 --every 1w --match bid (plan a month, weekly)
|
|
32
|
+
slack-axi catchup --from 2026-06-06T09:00 --in bid-rtd-analytics,transit-lake`;
|
|
33
|
+
const DEFAULT_MAX_CHANNELS = 40;
|
|
34
|
+
const DEFAULT_LIMIT_PER = 50;
|
|
35
|
+
export async function catchupCommand(args) {
|
|
36
|
+
if (args.includes("--help"))
|
|
37
|
+
return CATCHUP_HELP;
|
|
38
|
+
const team = takeFlag(args, "--team");
|
|
39
|
+
const since = takeFlag(team.rest, "--since");
|
|
40
|
+
const from = takeFlag(since.rest, "--from");
|
|
41
|
+
const to = takeFlag(from.rest, "--to");
|
|
42
|
+
const tz = takeFlag(to.rest, "--tz");
|
|
43
|
+
const every = takeFlag(tz.rest, "--every");
|
|
44
|
+
const type = takeFlag(every.rest, "--type");
|
|
45
|
+
const match = takeFlag(type.rest, "--match");
|
|
46
|
+
const inList = takeFlag(match.rest, "--in");
|
|
47
|
+
const limitPer = takeFlag(inList.rest, "--limit-per");
|
|
48
|
+
const maxCh = takeFlag(limitPer.rest, "--max-channels");
|
|
49
|
+
const excludeBots = takeBool(maxCh.rest, "--exclude-bots");
|
|
50
|
+
const cite = takeBool(excludeBots.rest, "--cite");
|
|
51
|
+
const perCap = posInt(limitPer.value, DEFAULT_LIMIT_PER);
|
|
52
|
+
const maxChannels = posInt(maxCh.value, DEFAULT_MAX_CHANNELS);
|
|
53
|
+
const session = await activeSession({ teamFlag: team.value });
|
|
54
|
+
// Default window for a catch-up is the last day, not the read default of 7d.
|
|
55
|
+
const window = resolveWindow({ since: since.value ?? (from.value || to.value ? undefined : "1d"), from: from.value, to: to.value, tz: tz.value }, Date.now());
|
|
56
|
+
// Plan mode: --every emits the batch windows only (no fetch), for the agent to iterate one at a time.
|
|
57
|
+
if (every.value !== undefined) {
|
|
58
|
+
const everyMs = parseSpanMs(every.value);
|
|
59
|
+
if (everyMs === undefined) {
|
|
60
|
+
throw new AxiError(`Invalid --every '${every.value}'`, "USAGE", ["Use a span like 1w, 3d, or 12h"]);
|
|
61
|
+
}
|
|
62
|
+
const batches = batchWindows(window.oldestMs, window.endMs, everyMs);
|
|
63
|
+
const scope = scopeSuffix({ type: type.value, match: match.value, in: inList.value, excludeBots: excludeBots.present });
|
|
64
|
+
const rows = batches.map((b, i) => ({
|
|
65
|
+
n: i + 1,
|
|
66
|
+
from: formatDate(b.startMs, window.tz),
|
|
67
|
+
to: formatDate(b.endMs - 1, window.tz),
|
|
68
|
+
}));
|
|
69
|
+
return joinBlocks(encodeObject({
|
|
70
|
+
"catchup-plan": `${batches.length} batches of ${every.value} over ${formatRange(window)}`,
|
|
71
|
+
}), renderList("batches", rows), renderHelp([
|
|
72
|
+
`Run each in order: slack-axi catchup --from <from> --to <to>${scope ? ` ${scope}` : ""}`,
|
|
73
|
+
"Process one batch (read/summarize/ingest), then the next — adjacent batches tile exactly (no gap, no overlap)",
|
|
74
|
+
]));
|
|
75
|
+
}
|
|
76
|
+
const pool = await resolveScope(session, { inList: inList.value, type: type.value, match: match.value });
|
|
77
|
+
if (pool.length === 0) {
|
|
78
|
+
return joinBlocks(encodeObject({ workspace: ws(session), range: formatRange(window) }), encodeObject({ channels: "0 channels matched the scope" }), renderHelp(["Broaden with `--type public,private,mpim,im` or `--match <q>`, or pass `--in <list>`"]));
|
|
79
|
+
}
|
|
80
|
+
if (pool.length > maxChannels) {
|
|
81
|
+
throw new AxiError(`Scope matched ${pool.length} channels; that's above --max-channels (${maxChannels})`, "TOO_MANY_CHANNELS", [
|
|
82
|
+
"Narrow with `--match <q>` or `--type`, or pass an explicit `--in <c1,c2,...>`",
|
|
83
|
+
`Or raise the cap: --max-channels ${pool.length}`,
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
await ensureUsers(session);
|
|
87
|
+
const users = allCachedUsers(session.teamId);
|
|
88
|
+
// Sequential sweep to respect Slack's tightened conversations.history rate limits.
|
|
89
|
+
const active = [];
|
|
90
|
+
for (const channel of pool) {
|
|
91
|
+
let msgs = await fetchWindow(session, channel.id, window.oldestMs, window.endMs);
|
|
92
|
+
if (excludeBots.present)
|
|
93
|
+
msgs = msgs.filter((m) => !isBot(m));
|
|
94
|
+
if (msgs.length === 0)
|
|
95
|
+
continue;
|
|
96
|
+
const total = msgs.length;
|
|
97
|
+
const shown = msgs.slice(-perCap);
|
|
98
|
+
const rows = [];
|
|
99
|
+
for (const m of shown)
|
|
100
|
+
rows.push(await buildRow(session, channel.id, m, users, window.tz, cite.present));
|
|
101
|
+
active.push({ channel, label: await channelLabel(session, channel), total, rows });
|
|
102
|
+
}
|
|
103
|
+
const header = encodeObject({
|
|
104
|
+
workspace: ws(session),
|
|
105
|
+
range: formatRange(window),
|
|
106
|
+
swept: `${pool.length} channels (${active.length} with activity)`,
|
|
107
|
+
});
|
|
108
|
+
const blocks = [header];
|
|
109
|
+
for (const a of active) {
|
|
110
|
+
const incomplete = a.rows.length < a.total ? ` (most recent ${a.rows.length} of ${a.total}; raise --limit-per)` : "";
|
|
111
|
+
blocks.push(`${a.label} (${a.channel.id})${incomplete}:\n${indentLines(renderList("messages", a.rows), 2)}`);
|
|
112
|
+
}
|
|
113
|
+
const help = [
|
|
114
|
+
active.length > 0 ? "Use `slack-axi read <channel> --from --to` or `thread <channel> <ts>` to expand" : "Nothing posted in this window across the scoped channels",
|
|
115
|
+
!cite.present ? "Add `--cite`, or `slack-axi cite <channel> <ts...>`, for permalinks" : undefined,
|
|
116
|
+
].filter((l) => Boolean(l));
|
|
117
|
+
return joinBlocks(...blocks, renderHelp(help));
|
|
118
|
+
}
|
|
119
|
+
async function resolveScope(session, opts) {
|
|
120
|
+
if (opts.inList) {
|
|
121
|
+
const names = opts.inList.split(",").map((s) => s.trim()).filter(Boolean);
|
|
122
|
+
return Promise.all(names.map((n) => resolveChannel(session, n)));
|
|
123
|
+
}
|
|
124
|
+
const types = (opts.type ?? "public,private").split(",").map((s) => s.trim()).filter(Boolean);
|
|
125
|
+
let pool = (await getChannels(session)).filter((c) => c.is_member && types.includes(c.type));
|
|
126
|
+
if (opts.match) {
|
|
127
|
+
const q = opts.match.toLowerCase();
|
|
128
|
+
pool = pool.filter((c) => c.name.toLowerCase().includes(q));
|
|
129
|
+
}
|
|
130
|
+
return pool;
|
|
131
|
+
}
|
|
132
|
+
async function buildRow(session, channelId, msg, users, tz, cite) {
|
|
133
|
+
const author = msg.user ? userName(msg.user, users) : msg.botId ? "(bot)" : "(system)";
|
|
134
|
+
const replyNote = msg.replyCount > 0 ? ` [+${msg.replyCount} repl${msg.replyCount === 1 ? "y" : "ies"}]` : "";
|
|
135
|
+
const row = {
|
|
136
|
+
time: formatDateTime(tsToEpochMs(msg.ts), tz),
|
|
137
|
+
author,
|
|
138
|
+
text: truncate(formatText(msg.text, users)) + replyNote,
|
|
139
|
+
ts: handle(msg.ts),
|
|
140
|
+
};
|
|
141
|
+
if (cite)
|
|
142
|
+
row.permalink = await getPermalink(session, channelId, msg.ts);
|
|
143
|
+
return row;
|
|
144
|
+
}
|
|
145
|
+
function ws(session) {
|
|
146
|
+
return `${session.teamName ?? session.teamId} (${session.teamId})`;
|
|
147
|
+
}
|
|
148
|
+
/** Rebuild the scope flags for the per-batch command emitted by plan mode. */
|
|
149
|
+
function scopeSuffix(opts) {
|
|
150
|
+
const parts = [];
|
|
151
|
+
if (opts.in)
|
|
152
|
+
parts.push(`--in ${opts.in}`);
|
|
153
|
+
else {
|
|
154
|
+
if (opts.type)
|
|
155
|
+
parts.push(`--type ${opts.type}`);
|
|
156
|
+
if (opts.match)
|
|
157
|
+
parts.push(`--match ${opts.match}`);
|
|
158
|
+
}
|
|
159
|
+
if (opts.excludeBots)
|
|
160
|
+
parts.push("--exclude-bots");
|
|
161
|
+
return parts.join(" ");
|
|
162
|
+
}
|
|
163
|
+
function posInt(value, fallback) {
|
|
164
|
+
const n = value ? Number.parseInt(value, 10) : NaN;
|
|
165
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
166
|
+
}
|
|
167
|
+
function indentLines(text, spaces) {
|
|
168
|
+
const pad = " ".repeat(spaces);
|
|
169
|
+
return text.split("\n").map((line) => (line.length > 0 ? pad + line : line)).join("\n");
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=catchup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catchup.js","sourceRoot":"","sources":["../../../src/commands/catchup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const CHANNELS_HELP = "usage: slack-axi channels [flags]\nLists the conversations you belong to across ALL types (public, private, group DMs, DMs).\nflags[5]:\n --type <t> Filter: public | private | mpim | im\n --all List every public+private channel in the workspace (not just yours)\n --match <q> Fuzzy-filter by name\n --limit <n> Max rows to show (default 50)\n --fields <a,b> Extra columns: is_member, topic, purpose\nexamples:\n slack-axi channels\n slack-axi channels --type private\n slack-axi channels --match bid\n slack-axi channels --all --match bid";
|
|
2
|
+
export declare const DMS_HELP = "usage: slack-axi dms\nLists your direct messages (im) and group DMs (mpim) with participant names resolved.";
|
|
3
|
+
export declare const MEMBERS_HELP = "usage: slack-axi members <channel>\nLists the members of a channel (#name, name, or id), names resolved.";
|
|
4
|
+
export declare function channelsCommand(args: string[]): Promise<string>;
|
|
5
|
+
export declare function dmsCommand(args: string[]): Promise<string>;
|
|
6
|
+
export declare function membersCommand(args: string[]): Promise<string>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { takeBool, takeFlag } from "../flags.js";
|
|
3
|
+
import { encodeBlock, joinBlocks, renderHelp, renderList, truncate } from "../output.js";
|
|
4
|
+
import { activeSession } from "../session.js";
|
|
5
|
+
import { cachedChannels, ensureUsers, getChannels, refreshAllChannels, } from "../slack/cache.js";
|
|
6
|
+
import { channelLabel, fuzzyChannelMatches, resolveChannel, userLabel } from "../slack/resolve.js";
|
|
7
|
+
export const CHANNELS_HELP = `usage: slack-axi channels [flags]
|
|
8
|
+
Lists the conversations you belong to across ALL types (public, private, group DMs, DMs).
|
|
9
|
+
flags[5]:
|
|
10
|
+
--type <t> Filter: public | private | mpim | im
|
|
11
|
+
--all List every public+private channel in the workspace (not just yours)
|
|
12
|
+
--match <q> Fuzzy-filter by name
|
|
13
|
+
--limit <n> Max rows to show (default 50)
|
|
14
|
+
--fields <a,b> Extra columns: is_member, topic, purpose
|
|
15
|
+
examples:
|
|
16
|
+
slack-axi channels
|
|
17
|
+
slack-axi channels --type private
|
|
18
|
+
slack-axi channels --match bid
|
|
19
|
+
slack-axi channels --all --match bid`;
|
|
20
|
+
const DEFAULT_CHANNEL_LIMIT = 50;
|
|
21
|
+
const DEFAULT_DM_LIMIT = 50;
|
|
22
|
+
const DEFAULT_MEMBER_LIMIT = 100;
|
|
23
|
+
function parseLimit(value, fallback) {
|
|
24
|
+
if (!value)
|
|
25
|
+
return fallback;
|
|
26
|
+
const n = Number.parseInt(value, 10);
|
|
27
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
28
|
+
}
|
|
29
|
+
export const DMS_HELP = `usage: slack-axi dms
|
|
30
|
+
Lists your direct messages (im) and group DMs (mpim) with participant names resolved.`;
|
|
31
|
+
export const MEMBERS_HELP = `usage: slack-axi members <channel>
|
|
32
|
+
Lists the members of a channel (#name, name, or id), names resolved.`;
|
|
33
|
+
const TYPE_ORDER = { public: 0, private: 1, mpim: 2, im: 3 };
|
|
34
|
+
export async function channelsCommand(args) {
|
|
35
|
+
if (args.includes("--help"))
|
|
36
|
+
return CHANNELS_HELP;
|
|
37
|
+
const team = takeFlag(args, "--team");
|
|
38
|
+
const all = takeBool(team.rest, "--all");
|
|
39
|
+
const type = takeFlag(all.rest, "--type");
|
|
40
|
+
const match = takeFlag(type.rest, "--match");
|
|
41
|
+
const limitFlag = takeFlag(match.rest, "--limit");
|
|
42
|
+
const fields = takeFlag(limitFlag.rest, "--fields");
|
|
43
|
+
const limit = parseLimit(limitFlag.value, DEFAULT_CHANNEL_LIMIT);
|
|
44
|
+
const extra = (fields.value ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
45
|
+
const session = await activeSession({ teamFlag: team.value });
|
|
46
|
+
let pool;
|
|
47
|
+
if (all.present) {
|
|
48
|
+
await refreshAllChannels(session);
|
|
49
|
+
pool = cachedChannels(session.teamId).filter((c) => c.type === "public" || c.type === "private");
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
pool = (await getChannels(session)).filter((c) => c.is_member);
|
|
53
|
+
}
|
|
54
|
+
const total = pool.length;
|
|
55
|
+
let filtered = pool;
|
|
56
|
+
if (type.value) {
|
|
57
|
+
if (!["public", "private", "mpim", "im"].includes(type.value)) {
|
|
58
|
+
throw new AxiError(`Unknown --type '${type.value}'`, "USAGE", ["Use one of: public, private, mpim, im"]);
|
|
59
|
+
}
|
|
60
|
+
filtered = filtered.filter((c) => c.type === type.value);
|
|
61
|
+
}
|
|
62
|
+
if (match.value)
|
|
63
|
+
filtered = fuzzyChannelMatches(filtered, match.value, filtered.length);
|
|
64
|
+
if (filtered.length === 0) {
|
|
65
|
+
const why = match.value ? ` matching "${match.value}"` : type.value ? ` of type ${type.value}` : "";
|
|
66
|
+
return joinBlocks(encodeBlock("channels", `0 channels${why} (of ${total} ${all.present ? "workspace" : "your"} channels)`), renderHelp(all.present ? [] : ["Run `slack-axi channels --all` to include channels you haven't joined"]));
|
|
67
|
+
}
|
|
68
|
+
// Resolve labels (im → @user) once, then sort by type group then name.
|
|
69
|
+
await ensureUsers(session);
|
|
70
|
+
const labeled = await Promise.all(filtered.map(async (c) => ({ meta: c, label: await channelLabel(session, c) })));
|
|
71
|
+
labeled.sort((a, b) => TYPE_ORDER[a.meta.type] - TYPE_ORDER[b.meta.type] || a.label.localeCompare(b.label));
|
|
72
|
+
const matched = filtered.length;
|
|
73
|
+
const capped = labeled.slice(0, limit);
|
|
74
|
+
const rows = capped.map(({ meta, label }) => {
|
|
75
|
+
const row = { id: meta.id, name: label, type: meta.type };
|
|
76
|
+
if (all.present || extra.includes("is_member"))
|
|
77
|
+
row.is_member = meta.is_member;
|
|
78
|
+
if (extra.includes("topic"))
|
|
79
|
+
row.topic = meta.topic ? truncate(meta.topic, 120) : "";
|
|
80
|
+
if (extra.includes("purpose"))
|
|
81
|
+
row.purpose = meta.purpose ? truncate(meta.purpose, 120) : "";
|
|
82
|
+
return row;
|
|
83
|
+
});
|
|
84
|
+
const help = [
|
|
85
|
+
"Run `slack-axi read <channel>` to read one (threads inlined)",
|
|
86
|
+
match.value ? undefined : "Narrow with `--match <q>` or `--type public|private|mpim|im`",
|
|
87
|
+
capped.length < matched ? `Showing ${capped.length} of ${matched}; raise with \`--limit <n>\`` : undefined,
|
|
88
|
+
all.present ? "Drop `--all` to list just your channels" : "Add `--all` to include channels you haven't joined",
|
|
89
|
+
].filter((l) => Boolean(l));
|
|
90
|
+
return joinBlocks(encodeBlock("workspace", `${session.teamName ?? session.teamId} (${session.teamId})`), renderList("channels", rows, { total: matched }), renderHelp(help));
|
|
91
|
+
}
|
|
92
|
+
export async function dmsCommand(args) {
|
|
93
|
+
if (args.includes("--help"))
|
|
94
|
+
return DMS_HELP;
|
|
95
|
+
const team = takeFlag(args, "--team");
|
|
96
|
+
const limitFlag = takeFlag(team.rest, "--limit");
|
|
97
|
+
const limit = parseLimit(limitFlag.value, DEFAULT_DM_LIMIT);
|
|
98
|
+
const session = await activeSession({ teamFlag: team.value });
|
|
99
|
+
const dms = (await getChannels(session)).filter((c) => c.is_member && (c.type === "im" || c.type === "mpim"));
|
|
100
|
+
if (dms.length === 0)
|
|
101
|
+
return encodeBlock("dms", "0 direct or group-DM conversations");
|
|
102
|
+
// Sort cheaply (im first, then by id) and cap BEFORE resolving labels.
|
|
103
|
+
dms.sort((a, b) => TYPE_ORDER[a.type] - TYPE_ORDER[b.type] || a.id.localeCompare(b.id));
|
|
104
|
+
const capped = dms.slice(0, limit);
|
|
105
|
+
await ensureUsers(session); // for im labels; mpim participants come from the channel name (no calls)
|
|
106
|
+
const rows = await Promise.all(capped.map(async (c) => ({ id: c.id, type: c.type, with: await channelLabel(session, c) })));
|
|
107
|
+
const help = [
|
|
108
|
+
"Run `slack-axi read <id>` to read a DM thread",
|
|
109
|
+
capped.length < dms.length ? `Showing ${capped.length} of ${dms.length}; raise with \`--limit <n>\`` : undefined,
|
|
110
|
+
].filter((l) => Boolean(l));
|
|
111
|
+
return joinBlocks(encodeBlock("workspace", `${session.teamName ?? session.teamId} (${session.teamId})`), renderList("dms", rows, { total: dms.length }), renderHelp(help));
|
|
112
|
+
}
|
|
113
|
+
export async function membersCommand(args) {
|
|
114
|
+
if (args.includes("--help"))
|
|
115
|
+
return MEMBERS_HELP;
|
|
116
|
+
const team = takeFlag(args, "--team");
|
|
117
|
+
const limitFlag = takeFlag(team.rest, "--limit");
|
|
118
|
+
const limit = parseLimit(limitFlag.value, DEFAULT_MEMBER_LIMIT);
|
|
119
|
+
const target = limitFlag.rest.find((a) => !a.startsWith("-"));
|
|
120
|
+
if (!target)
|
|
121
|
+
throw new AxiError("usage: slack-axi members <channel> [--limit <n>]", "USAGE", []);
|
|
122
|
+
const session = await activeSession({ teamFlag: team.value });
|
|
123
|
+
const channel = await resolveChannel(session, target);
|
|
124
|
+
const ids = await listMembers(session, channel.id);
|
|
125
|
+
if (ids.length === 0)
|
|
126
|
+
return encodeBlock("members", `0 members in ${await channelLabel(session, channel)}`);
|
|
127
|
+
await ensureUsers(session);
|
|
128
|
+
const labeled = await Promise.all(ids.map(async (id) => ({ user: id, name: await userLabel(session, id) })));
|
|
129
|
+
labeled.sort((a, b) => a.name.localeCompare(b.name));
|
|
130
|
+
const rows = labeled.slice(0, limit);
|
|
131
|
+
const help = rows.length < labeled.length
|
|
132
|
+
? [`Showing ${rows.length} of ${labeled.length} members; raise with \`--limit <n>\``]
|
|
133
|
+
: [];
|
|
134
|
+
return joinBlocks(encodeBlock("channel", `${await channelLabel(session, channel)} (${channel.id})`), renderList("members", rows, { total: labeled.length }), renderHelp(help));
|
|
135
|
+
}
|
|
136
|
+
/** Channel member ids, paginated to completion. */
|
|
137
|
+
async function listMembers(session, channel) {
|
|
138
|
+
const ids = [];
|
|
139
|
+
let cursor;
|
|
140
|
+
do {
|
|
141
|
+
const res = await session.client.conversations.members({ channel, limit: 200, ...(cursor ? { cursor } : {}) });
|
|
142
|
+
ids.push(...(res.members ?? []));
|
|
143
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
144
|
+
} while (cursor);
|
|
145
|
+
return ids;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sourceRoot":"","sources":["../../../src/commands/channels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const CITE_HELP = "usage: slack-axi cite <channel> <ts> [<ts> ...]\nReconstructs permalinks (and the HQ slack_message {channel, ts, permalink} shape) for the given\nmessage handles. Stateless \u2014 channel + ts is all it needs. ts may be dotless or dotted.\nexamples:\n slack-axi cite #eng 1717589640123456\n slack-axi cite C09GHV2RUSJ 1717589640123456 1717589700234567";
|
|
2
|
+
export declare function citeCommand(args: string[]): Promise<string>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { AxiError } from "axi-sdk-js";
|
|
2
|
+
import { takeFlag } from "../flags.js";
|
|
3
|
+
import { encodeObject, joinBlocks, renderList } from "../output.js";
|
|
4
|
+
import { activeSession } from "../session.js";
|
|
5
|
+
import { getPermalink } from "../slack/permalink.js";
|
|
6
|
+
import { channelLabel, resolveChannel } from "../slack/resolve.js";
|
|
7
|
+
import { dottedTs, handle } from "../slack/ts.js";
|
|
8
|
+
export const CITE_HELP = `usage: slack-axi cite <channel> <ts> [<ts> ...]
|
|
9
|
+
Reconstructs permalinks (and the HQ slack_message {channel, ts, permalink} shape) for the given
|
|
10
|
+
message handles. Stateless — channel + ts is all it needs. ts may be dotless or dotted.
|
|
11
|
+
examples:
|
|
12
|
+
slack-axi cite #eng 1717589640123456
|
|
13
|
+
slack-axi cite C09GHV2RUSJ 1717589640123456 1717589700234567`;
|
|
14
|
+
export async function citeCommand(args) {
|
|
15
|
+
if (args.includes("--help"))
|
|
16
|
+
return CITE_HELP;
|
|
17
|
+
const team = takeFlag(args, "--team");
|
|
18
|
+
const positional = team.rest.filter((a) => !a.startsWith("-"));
|
|
19
|
+
const [target, ...tsArgs] = positional;
|
|
20
|
+
if (!target || tsArgs.length === 0) {
|
|
21
|
+
throw new AxiError("usage: slack-axi cite <channel> <ts> [<ts> ...]", "USAGE", [
|
|
22
|
+
"Pass a channel and one or more ts handles from a `read`/`search` row",
|
|
23
|
+
]);
|
|
24
|
+
}
|
|
25
|
+
const session = await activeSession({ teamFlag: team.value });
|
|
26
|
+
const channel = await resolveChannel(session, target);
|
|
27
|
+
const rows = await Promise.all(tsArgs.map(async (raw) => {
|
|
28
|
+
const ts = dottedTs(raw);
|
|
29
|
+
try {
|
|
30
|
+
return { ts: handle(ts), permalink: await getPermalink(session, channel.id, ts) };
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return { ts: handle(ts), permalink: "(not found in this channel)" };
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
return joinBlocks(encodeObject({ workspace: `${session.teamName ?? session.teamId} (${session.teamId})`, channel: `${await channelLabel(session, channel)} (${channel.id})` }), renderList("citations", rows));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=cite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.js","sourceRoot":"","sources":["../../../src/commands/cite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACpE,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,QAAQ,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;+DAKsC,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,SAAS,CAAC;IAC9C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACtC,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,GAAG,MAAM,CAAC,GAAG,UAAU,CAAC;IACvC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,QAAQ,CAAC,iDAAiD,EAAE,OAAO,EAAE;YAC7E,sEAAsE;SACvE,CAAC,CAAC;IACL,CAAC;IAED,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;IAEtD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5B,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC;YACH,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACpF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,6BAA6B,EAAE,CAAC;QACtE,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,UAAU,CACf,YAAY,CAAC,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAC5J,UAAU,CAAC,WAAW,EAAE,IAAI,CAAC,CAC9B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DOCTOR_HELP = "usage: slack-axi doctor [--team <id>]\nChecks the active workspace's token, scope coverage, and read access.\nExit 1 if any check fails; warnings (e.g. a missing scope) keep exit 0.";
|
|
2
|
+
export declare function doctorCommand(args: string[]): Promise<string>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { resolveActiveToken } from "../config.js";
|
|
2
|
+
import { takeFlag } from "../flags.js";
|
|
3
|
+
import { encodeBlock, joinBlocks, renderHelp, renderList } from "../output.js";
|
|
4
|
+
import { validateToken, webClient } from "../slack/client.js";
|
|
5
|
+
import { toAxiError } from "../slack/errors.js";
|
|
6
|
+
import { missingScopes } from "../slack/scopes.js";
|
|
7
|
+
export const DOCTOR_HELP = `usage: slack-axi doctor [--team <id>]
|
|
8
|
+
Checks the active workspace's token, scope coverage, and read access.
|
|
9
|
+
Exit 1 if any check fails; warnings (e.g. a missing scope) keep exit 0.`;
|
|
10
|
+
export async function doctorCommand(args) {
|
|
11
|
+
if (args.includes("--help"))
|
|
12
|
+
return DOCTOR_HELP;
|
|
13
|
+
const { value: teamFlag } = takeFlag(args, "--team");
|
|
14
|
+
const active = resolveActiveToken({ teamFlag });
|
|
15
|
+
const checks = [];
|
|
16
|
+
// 1. Token validity (hard fail → exit 1).
|
|
17
|
+
let identity;
|
|
18
|
+
try {
|
|
19
|
+
identity = await validateToken(active.token);
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw toAxiError(err, teamFlag ? { team: teamFlag } : {});
|
|
23
|
+
}
|
|
24
|
+
checks.push({ check: "token", status: "ok", detail: "auth.test passed" });
|
|
25
|
+
// 2. Scope coverage (missing → warn, exit 0).
|
|
26
|
+
const missing = missingScopes(identity.scopes);
|
|
27
|
+
checks.push({
|
|
28
|
+
check: "scopes",
|
|
29
|
+
status: missing.length === 0 ? "ok" : "warn",
|
|
30
|
+
detail: missing.length === 0 ? "all required granted" : `missing ${missing.join(", ")}`,
|
|
31
|
+
});
|
|
32
|
+
// 3. Read probe (hard fail → exit 1).
|
|
33
|
+
try {
|
|
34
|
+
await webClient(active.token).users.conversations({ limit: 1 });
|
|
35
|
+
checks.push({ check: "read_probe", status: "ok", detail: "users.conversations reachable" });
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
throw toAxiError(err, teamFlag ? { team: teamFlag } : {});
|
|
39
|
+
}
|
|
40
|
+
const header = encodeBlock("workspace", `${identity.teamName} (${identity.teamId}) as ${identity.userName ?? identity.userId}`);
|
|
41
|
+
const help = missing.length > 0
|
|
42
|
+
? renderHelp([`Add missing scopes via \`slack-axi auth setup\`, then re-install + re-login`])
|
|
43
|
+
: "";
|
|
44
|
+
return joinBlocks(header, renderList("checks", checks), help);
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content-first no-args view. See specs/commands/home.md. The SDK prepends the bin/description
|
|
3
|
+
* header; this returns the live state below it.
|
|
4
|
+
* In plan 01 this shows auth/workspace state; unread + top-channels arrive with plan 02.
|
|
5
|
+
*/
|
|
6
|
+
export declare function homeCommand(): Promise<string>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { listWorkspaceIds, resolveActiveToken } from "../config.js";
|
|
2
|
+
import { encodeBlock, joinBlocks, renderHelp } from "../output.js";
|
|
3
|
+
import { cachedChannels } from "../slack/cache.js";
|
|
4
|
+
/**
|
|
5
|
+
* Content-first no-args view. See specs/commands/home.md. The SDK prepends the bin/description
|
|
6
|
+
* header; this returns the live state below it.
|
|
7
|
+
* In plan 01 this shows auth/workspace state; unread + top-channels arrive with plan 02.
|
|
8
|
+
*/
|
|
9
|
+
export async function homeCommand() {
|
|
10
|
+
let active;
|
|
11
|
+
try {
|
|
12
|
+
active = resolveActiveToken({});
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// No token resolvable → setup-oriented home.
|
|
16
|
+
return renderHelp([
|
|
17
|
+
"Run `slack-axi auth setup` to create a Slack app and obtain a user token",
|
|
18
|
+
"Then `slack-axi auth login --token xoxp-...`",
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
const workspaceLabel = active.teamName
|
|
22
|
+
? `${active.teamName} (${active.teamId ?? "?"})`
|
|
23
|
+
: active.teamId ?? "(from SLACK_AXI_TOKEN)";
|
|
24
|
+
const stored = listWorkspaceIds();
|
|
25
|
+
// Cache-only (no network): home loads on every session, so never refresh here.
|
|
26
|
+
const channelCount = active.teamId ? cachedChannels(active.teamId).filter((c) => c.is_member).length : 0;
|
|
27
|
+
const statusFields = { workspace: workspaceLabel };
|
|
28
|
+
if (channelCount > 0)
|
|
29
|
+
statusFields.your_channels = channelCount;
|
|
30
|
+
const status = encodeBlock("status", statusFields);
|
|
31
|
+
const help = ["Run `slack-axi channels` to list your channels (all types)"];
|
|
32
|
+
if (stored.length > 1)
|
|
33
|
+
help.push("Run `slack-axi auth workspaces` to see all workspaces");
|
|
34
|
+
help.push("Run `slack-axi doctor` to verify auth + scopes");
|
|
35
|
+
return joinBlocks(status, renderHelp(help));
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=home.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"home.js","sourceRoot":"","sources":["../../../src/commands/home.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;QAC7C,OAAO,UAAU,CAAC;YAChB,0EAA0E;YAC1E,8CAA8C;SAC/C,CAAC,CAAC;IACL,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,QAAQ;QACpC,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG;QAChD,CAAC,CAAC,MAAM,CAAC,MAAM,IAAI,wBAAwB,CAAC;IAE9C,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,+EAA+E;IAC/E,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzG,MAAM,YAAY,GAA4B,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5E,IAAI,YAAY,GAAG,CAAC;QAAE,YAAY,CAAC,aAAa,GAAG,YAAY,CAAC;IAChE,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEnD,MAAM,IAAI,GAAa,CAAC,4DAA4D,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,uDAAuD,CAAC,CAAC;IAC1F,IAAI,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;IAE5D,OAAO,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const READ_HELP = "usage: slack-axi read <channel> [flags]\nReads a channel over a time window, threads inlined, paginated to completion.\nflags[8]:\n --since <span> Relative window ending now: 7d, 24h, 90m (default: 7d)\n --from <when> Window start: date (2026-04-23), datetime (2026-04-23T14:00), or span\n --to <when> Window end (default: now)\n --tz <zone> Timezone for parsing + display (default: America/New_York)\n --limit <n> Max top-level messages to show (default: 50)\n --threads <m> full | summary | none (default: full)\n --exclude-bots Drop bot/automation messages\n --cite Add a permalink column (for bulk citation); else use ts + `cite`\n --full Don't truncate message text\nexamples:\n slack-axi read #bid-rtd-analytics\n slack-axi read #eng --from 2026-04-23 --to 2026-04-29\n slack-axi read #eng --since 24h --threads summary";
|
|
2
|
+
export declare const THREAD_HELP = "usage: slack-axi thread <channel> <ts>\nReads a single thread fully (parent + all replies), names + permalinks resolved.";
|
|
3
|
+
export declare function readCommand(args: string[]): Promise<string>;
|
|
4
|
+
export declare function threadCommand(args: string[]): Promise<string>;
|