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,184 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { AxiError } from "axi-sdk-js";
|
|
5
|
+
/** Base config directory: $SLACK_AXI_CONFIG_DIR, else $XDG_CONFIG_HOME/slack-axi, else ~/.config/slack-axi. */
|
|
6
|
+
export function configDir() {
|
|
7
|
+
if (process.env.SLACK_AXI_CONFIG_DIR)
|
|
8
|
+
return process.env.SLACK_AXI_CONFIG_DIR;
|
|
9
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
10
|
+
const base = xdg && xdg.length > 0 ? xdg : join(homedir(), ".config");
|
|
11
|
+
return join(base, "slack-axi");
|
|
12
|
+
}
|
|
13
|
+
export function userConfigPath() {
|
|
14
|
+
return join(configDir(), "config.json");
|
|
15
|
+
}
|
|
16
|
+
export function setupStatePath() {
|
|
17
|
+
return join(configDir(), "setup.json");
|
|
18
|
+
}
|
|
19
|
+
export function manifestPath() {
|
|
20
|
+
return join(configDir(), "manifest.yaml");
|
|
21
|
+
}
|
|
22
|
+
export function setupHtmlPath() {
|
|
23
|
+
return join(configDir(), "setup.html");
|
|
24
|
+
}
|
|
25
|
+
export function workspaceDir(teamId) {
|
|
26
|
+
return join(configDir(), "workspaces", teamId);
|
|
27
|
+
}
|
|
28
|
+
export function tokenPath(teamId) {
|
|
29
|
+
return join(workspaceDir(teamId), "token.json");
|
|
30
|
+
}
|
|
31
|
+
export function cacheChannelsPath(teamId) {
|
|
32
|
+
return join(configDir(), "cache", teamId, "channels.json");
|
|
33
|
+
}
|
|
34
|
+
export function cacheUsersPath(teamId) {
|
|
35
|
+
return join(configDir(), "cache", teamId, "users.json");
|
|
36
|
+
}
|
|
37
|
+
function draftsDir() {
|
|
38
|
+
return join(configDir(), "drafts");
|
|
39
|
+
}
|
|
40
|
+
function draftPath(id) {
|
|
41
|
+
return join(draftsDir(), `${id}.json`);
|
|
42
|
+
}
|
|
43
|
+
export function getDraft(id) {
|
|
44
|
+
return readJson(draftPath(id));
|
|
45
|
+
}
|
|
46
|
+
export function writeDraft(draft) {
|
|
47
|
+
writeJson(draftPath(draft.id), draft);
|
|
48
|
+
}
|
|
49
|
+
export function removeDraft(id) {
|
|
50
|
+
if (!existsSync(draftPath(id)))
|
|
51
|
+
return false;
|
|
52
|
+
rmSync(draftPath(id), { force: true });
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
export function listDrafts() {
|
|
56
|
+
const dir = draftsDir();
|
|
57
|
+
if (!existsSync(dir))
|
|
58
|
+
return [];
|
|
59
|
+
return readdirSync(dir)
|
|
60
|
+
.filter((f) => f.endsWith(".json"))
|
|
61
|
+
.map((f) => readJson(join(dir, f)))
|
|
62
|
+
.filter((d) => d !== undefined)
|
|
63
|
+
.sort((a, b) => a.created_at.localeCompare(b.created_at));
|
|
64
|
+
}
|
|
65
|
+
function readJson(path) {
|
|
66
|
+
if (!existsSync(path))
|
|
67
|
+
return undefined;
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function writeJson(path, value, mode) {
|
|
76
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
77
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`, mode ? { mode } : undefined);
|
|
78
|
+
}
|
|
79
|
+
export function readUserConfig() {
|
|
80
|
+
return readJson(userConfigPath()) ?? {};
|
|
81
|
+
}
|
|
82
|
+
export function writeUserConfig(config) {
|
|
83
|
+
writeJson(userConfigPath(), config);
|
|
84
|
+
}
|
|
85
|
+
export function getDefaultTeam() {
|
|
86
|
+
return readUserConfig().default_team;
|
|
87
|
+
}
|
|
88
|
+
export function setDefaultTeam(teamId) {
|
|
89
|
+
writeUserConfig({ ...readUserConfig(), default_team: teamId });
|
|
90
|
+
}
|
|
91
|
+
/** Team ids with a stored token, in directory order. */
|
|
92
|
+
export function listWorkspaceIds() {
|
|
93
|
+
const dir = join(configDir(), "workspaces");
|
|
94
|
+
if (!existsSync(dir))
|
|
95
|
+
return [];
|
|
96
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
97
|
+
.filter((entry) => entry.isDirectory() && existsSync(tokenPath(entry.name)))
|
|
98
|
+
.map((entry) => entry.name);
|
|
99
|
+
}
|
|
100
|
+
export function listWorkspaces() {
|
|
101
|
+
return listWorkspaceIds()
|
|
102
|
+
.map((id) => readJson(tokenPath(id)))
|
|
103
|
+
.filter((t) => t !== undefined);
|
|
104
|
+
}
|
|
105
|
+
export function getStoredToken(teamId) {
|
|
106
|
+
return readJson(tokenPath(teamId));
|
|
107
|
+
}
|
|
108
|
+
/** Persist a token (mode 0600); first stored workspace becomes the default. */
|
|
109
|
+
export function writeStoredToken(token) {
|
|
110
|
+
writeJson(tokenPath(token.team_id), token, 0o600);
|
|
111
|
+
if (getDefaultTeam() === undefined)
|
|
112
|
+
setDefaultTeam(token.team_id);
|
|
113
|
+
}
|
|
114
|
+
/** Delete a workspace's stored token + dir. Idempotent. Repairs a dangling default. */
|
|
115
|
+
export function removeWorkspace(teamId) {
|
|
116
|
+
const dir = workspaceDir(teamId);
|
|
117
|
+
const existed = existsSync(tokenPath(teamId));
|
|
118
|
+
if (existsSync(dir))
|
|
119
|
+
rmSync(dir, { recursive: true, force: true });
|
|
120
|
+
if (getDefaultTeam() === teamId) {
|
|
121
|
+
const remaining = listWorkspaceIds();
|
|
122
|
+
const config = readUserConfig();
|
|
123
|
+
if (remaining.length > 0)
|
|
124
|
+
config.default_team = remaining[0];
|
|
125
|
+
else
|
|
126
|
+
delete config.default_team;
|
|
127
|
+
writeUserConfig(config);
|
|
128
|
+
}
|
|
129
|
+
return existed;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Resolve which token/workspace a command should act against, per
|
|
133
|
+
* specs/behaviors/auth-and-workspaces.md. Order: env → --team → default → single → error.
|
|
134
|
+
* Mutations with 2+ stored workspaces require an explicit team (env or flag).
|
|
135
|
+
*/
|
|
136
|
+
export function resolveActiveToken(options) {
|
|
137
|
+
const { teamFlag, mutation = false } = options;
|
|
138
|
+
const envToken = process.env.SLACK_AXI_TOKEN;
|
|
139
|
+
if (envToken && envToken.length > 0) {
|
|
140
|
+
const envTeam = process.env.SLACK_AXI_TEAM ?? teamFlag;
|
|
141
|
+
const stored = envTeam ? getStoredToken(envTeam) : undefined;
|
|
142
|
+
return {
|
|
143
|
+
token: envToken,
|
|
144
|
+
teamId: envTeam,
|
|
145
|
+
teamName: stored?.team_name,
|
|
146
|
+
scopes: stored?.scopes,
|
|
147
|
+
source: "env",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const ids = listWorkspaceIds();
|
|
151
|
+
if (ids.length === 0) {
|
|
152
|
+
throw new AxiError("No Slack token available", "NO_TOKEN", [
|
|
153
|
+
"Set SLACK_AXI_TOKEN, or run `slack-axi auth setup` to create an app and store a token",
|
|
154
|
+
"Then `slack-axi auth login --token xoxp-...`",
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
if (teamFlag)
|
|
158
|
+
return fromStored(teamFlag, "flag");
|
|
159
|
+
if (mutation && ids.length > 1) {
|
|
160
|
+
throw new AxiError("Multiple workspaces are stored; a mutation requires an explicit workspace", "TEAM_REQUIRED", [
|
|
161
|
+
`Pass --team <id> (one of: ${ids.join(", ")}) or set SLACK_AXI_TEAM`,
|
|
162
|
+
]);
|
|
163
|
+
}
|
|
164
|
+
const def = getDefaultTeam();
|
|
165
|
+
if (def && getStoredToken(def))
|
|
166
|
+
return fromStored(def, "default");
|
|
167
|
+
if (ids.length === 1)
|
|
168
|
+
return fromStored(ids[0], "single");
|
|
169
|
+
throw new AxiError("No default workspace set and multiple are stored", "NO_DEFAULT_TEAM", [`Run \`slack-axi auth use <team>\` (one of: ${ids.join(", ")})`]);
|
|
170
|
+
}
|
|
171
|
+
function fromStored(teamId, source) {
|
|
172
|
+
const stored = getStoredToken(teamId);
|
|
173
|
+
if (!stored) {
|
|
174
|
+
throw new AxiError(`Workspace ${teamId} is not authenticated`, "TEAM_NOT_FOUND", [`Authenticated workspaces: ${listWorkspaceIds().join(", ") || "(none)"}`]);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
token: stored.token,
|
|
178
|
+
teamId: stored.team_id,
|
|
179
|
+
teamName: stored.team_name,
|
|
180
|
+
scopes: stored.scopes,
|
|
181
|
+
source,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Minimal, lenient flag parsing shared by commands. Unknown flags are left in `rest`. */
|
|
2
|
+
/** Extract a single string-valued flag (e.g. `--team T1`), returning the value and remaining args. */
|
|
3
|
+
export declare function takeFlag(args: string[], name: string): {
|
|
4
|
+
value?: string;
|
|
5
|
+
rest: string[];
|
|
6
|
+
};
|
|
7
|
+
/** Whether a boolean flag is present, returning the remaining args. */
|
|
8
|
+
export declare function takeBool(args: string[], name: string): {
|
|
9
|
+
present: boolean;
|
|
10
|
+
rest: string[];
|
|
11
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Minimal, lenient flag parsing shared by commands. Unknown flags are left in `rest`. */
|
|
2
|
+
/** Extract a single string-valued flag (e.g. `--team T1`), returning the value and remaining args. */
|
|
3
|
+
export function takeFlag(args, name) {
|
|
4
|
+
const rest = [];
|
|
5
|
+
let value;
|
|
6
|
+
for (let i = 0; i < args.length; i++) {
|
|
7
|
+
if (args[i] === name && i + 1 < args.length) {
|
|
8
|
+
value = args[i + 1];
|
|
9
|
+
i++;
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
rest.push(args[i]);
|
|
13
|
+
}
|
|
14
|
+
return { value, rest };
|
|
15
|
+
}
|
|
16
|
+
/** Whether a boolean flag is present, returning the remaining args. */
|
|
17
|
+
export function takeBool(args, name) {
|
|
18
|
+
const rest = args.filter((a) => a !== name);
|
|
19
|
+
return { present: rest.length !== args.length, rest };
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/flags.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAE1F,sGAAsG;AACtG,MAAM,UAAU,QAAQ,CAAC,IAAc,EAAE,IAAY;IACnD,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,KAAyB,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC5C,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACpB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,QAAQ,CAAC,IAAc,EAAE,IAAY;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;AACxD,CAAC"}
|
package/dist/src/meta.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export const DESCRIPTION = "Read, search, and draft Slack across your workspaces";
|
|
5
|
+
/** Read the package version from the nearest package.json (dist or src layout). */
|
|
6
|
+
export function readVersion() {
|
|
7
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
for (const candidate of [join(here, "..", "package.json"), join(here, "..", "..", "package.json")]) {
|
|
9
|
+
if (!existsSync(candidate))
|
|
10
|
+
continue;
|
|
11
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
12
|
+
if (typeof parsed.version === "string" && parsed.version.length > 0)
|
|
13
|
+
return parsed.version;
|
|
14
|
+
}
|
|
15
|
+
return "0.0.0";
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,WAAW,GAAG,sDAAsD,CAAC;AAElF,mFAAmF;AACnF,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,KAAK,MAAM,SAAS,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC;QACnG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,SAAS;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAA0B,CAAC;QACrF,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC,OAAO,CAAC;IAC7F,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Collapse the user's home directory prefix to `~` for display. */
|
|
2
|
+
export declare function collapseHome(path: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Token-efficient TOON output helpers — the shared rendering boundary for every command.
|
|
5
|
+
* See specs/behaviors/output-format.md. Internal logic stays on JSON; commands convert here.
|
|
6
|
+
*/
|
|
7
|
+
/** Encode a labeled value as a TOON block, e.g. `encodeBlock("workspace", {...})`. */
|
|
8
|
+
export declare function encodeBlock(label: string, value: unknown): string;
|
|
9
|
+
/** Encode a flat key/value object as top-level TOON lines (no wrapping label). */
|
|
10
|
+
export declare function encodeObject(value: Record<string, unknown>): string;
|
|
11
|
+
/** Render a list of already-flat rows under a labeled TOON array with a count header. */
|
|
12
|
+
export declare function renderList(label: string, rows: Array<Record<string, unknown>>, options?: {
|
|
13
|
+
total?: number;
|
|
14
|
+
}): string;
|
|
15
|
+
/**
|
|
16
|
+
* Render help suggestions. encode() inlines primitive arrays, so we format manually to get the
|
|
17
|
+
* multi-line `help[N]:` block the AXI standard uses.
|
|
18
|
+
*/
|
|
19
|
+
export declare function renderHelp(lines: string[]): string;
|
|
20
|
+
/** Render a structured error as TOON on stdout, with optional fixing suggestions. */
|
|
21
|
+
export declare function renderError(message: string, code: string, suggestions?: string[]): string;
|
|
22
|
+
/** Join non-empty TOON blocks with single newlines. */
|
|
23
|
+
export declare function joinBlocks(...blocks: Array<string | undefined>): string;
|
|
24
|
+
/** Truncate free text to `max` chars, noting the original length. */
|
|
25
|
+
export declare function truncate(text: string, max?: number): string;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { encode } from "@toon-format/toon";
|
|
3
|
+
/** Collapse the user's home directory prefix to `~` for display. */
|
|
4
|
+
export function collapseHome(path) {
|
|
5
|
+
const home = homedir();
|
|
6
|
+
return path.startsWith(home) ? `~${path.slice(home.length)}` : path;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Token-efficient TOON output helpers — the shared rendering boundary for every command.
|
|
10
|
+
* See specs/behaviors/output-format.md. Internal logic stays on JSON; commands convert here.
|
|
11
|
+
*/
|
|
12
|
+
/** Encode a labeled value as a TOON block, e.g. `encodeBlock("workspace", {...})`. */
|
|
13
|
+
export function encodeBlock(label, value) {
|
|
14
|
+
return encode({ [label]: value });
|
|
15
|
+
}
|
|
16
|
+
/** Encode a flat key/value object as top-level TOON lines (no wrapping label). */
|
|
17
|
+
export function encodeObject(value) {
|
|
18
|
+
return encode(value);
|
|
19
|
+
}
|
|
20
|
+
/** Render a list of already-flat rows under a labeled TOON array with a count header. */
|
|
21
|
+
export function renderList(label, rows, options = {}) {
|
|
22
|
+
const total = options.total ?? rows.length;
|
|
23
|
+
const header = total === rows.length ? `${label}[${rows.length}]` : `${label}[${rows.length} of ${total}]`;
|
|
24
|
+
// Encode under a placeholder label, then swap in our count-annotated header.
|
|
25
|
+
const encoded = encode({ [label]: rows });
|
|
26
|
+
return encoded.replace(new RegExp(`^${label}\\[${rows.length}\\]`), header);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Render help suggestions. encode() inlines primitive arrays, so we format manually to get the
|
|
30
|
+
* multi-line `help[N]:` block the AXI standard uses.
|
|
31
|
+
*/
|
|
32
|
+
export function renderHelp(lines) {
|
|
33
|
+
const items = lines.filter((l) => l && l.length > 0);
|
|
34
|
+
if (items.length === 0)
|
|
35
|
+
return "";
|
|
36
|
+
return `help[${items.length}]:\n${items.map((l) => ` ${l}`).join("\n")}`;
|
|
37
|
+
}
|
|
38
|
+
/** Render a structured error as TOON on stdout, with optional fixing suggestions. */
|
|
39
|
+
export function renderError(message, code, suggestions = []) {
|
|
40
|
+
return joinBlocks(encode({ error: message, code }), renderHelp(suggestions));
|
|
41
|
+
}
|
|
42
|
+
/** Join non-empty TOON blocks with single newlines. */
|
|
43
|
+
export function joinBlocks(...blocks) {
|
|
44
|
+
return blocks.filter((b) => Boolean(b && b.length > 0)).join("\n");
|
|
45
|
+
}
|
|
46
|
+
/** Truncate free text to `max` chars, noting the original length. */
|
|
47
|
+
export function truncate(text, max = 500) {
|
|
48
|
+
if (text.length <= max)
|
|
49
|
+
return text;
|
|
50
|
+
return `${text.slice(0, max - 1)}… (truncated, ${text.length} chars total)`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/output.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WebClient } from "@slack/web-api";
|
|
2
|
+
/** An authenticated, ready-to-use Slack session for one workspace. */
|
|
3
|
+
export interface Session {
|
|
4
|
+
token: string;
|
|
5
|
+
teamId: string;
|
|
6
|
+
teamName?: string;
|
|
7
|
+
client: WebClient;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the active workspace into a usable session. teamId is guaranteed: for a stored token it
|
|
11
|
+
* comes from token.json; for a bare SLACK_AXI_TOKEN env (no SLACK_AXI_TEAM) it's derived via a single
|
|
12
|
+
* auth.test. The teamId is the cache key, so it must be known before any read.
|
|
13
|
+
*/
|
|
14
|
+
export declare function activeSession(options?: {
|
|
15
|
+
teamFlag?: string;
|
|
16
|
+
mutation?: boolean;
|
|
17
|
+
}): Promise<Session>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { resolveActiveToken } from "./config.js";
|
|
2
|
+
import { validateToken, webClient } from "./slack/client.js";
|
|
3
|
+
import { toAxiError } from "./slack/errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the active workspace into a usable session. teamId is guaranteed: for a stored token it
|
|
6
|
+
* comes from token.json; for a bare SLACK_AXI_TOKEN env (no SLACK_AXI_TEAM) it's derived via a single
|
|
7
|
+
* auth.test. The teamId is the cache key, so it must be known before any read.
|
|
8
|
+
*/
|
|
9
|
+
export async function activeSession(options = {}) {
|
|
10
|
+
const active = resolveActiveToken(options);
|
|
11
|
+
let teamId = active.teamId;
|
|
12
|
+
let teamName = active.teamName;
|
|
13
|
+
if (!teamId) {
|
|
14
|
+
try {
|
|
15
|
+
const identity = await validateToken(active.token);
|
|
16
|
+
teamId = identity.teamId;
|
|
17
|
+
teamName = identity.teamName;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw toAxiError(err, options.teamFlag ? { team: options.teamFlag } : {});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { token: active.token, teamId, teamName, client: webClient(active.token) };
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/session.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAU/C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAqD,EAAE;IACzF,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,IAAI,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YACzB,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Session } from "../session.js";
|
|
2
|
+
export type ChannelType = "public" | "private" | "mpim" | "im";
|
|
3
|
+
export interface ChannelMeta {
|
|
4
|
+
id: string;
|
|
5
|
+
/** Channel name (no leading #). For `im` this is empty; use `user` to resolve a label. */
|
|
6
|
+
name: string;
|
|
7
|
+
type: ChannelType;
|
|
8
|
+
is_member: boolean;
|
|
9
|
+
is_archived: boolean;
|
|
10
|
+
/** For `im` channels: the other participant's user id. */
|
|
11
|
+
user?: string;
|
|
12
|
+
topic?: string;
|
|
13
|
+
purpose?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface UserMeta {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
real_name?: string;
|
|
19
|
+
display_name?: string;
|
|
20
|
+
is_bot: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Cache freshness window. Caches only map id↔name; message content is always fetched live. */
|
|
23
|
+
export declare const CACHE_TTL_MS: number;
|
|
24
|
+
/** Fetch the user's conversations across ALL types (paginate to completion) and update the cache. */
|
|
25
|
+
export declare function refreshMemberChannels(session: Session): Promise<ChannelMeta[]>;
|
|
26
|
+
/** Fetch every public+private channel in the workspace (paginate to completion) and update the cache. */
|
|
27
|
+
export declare function refreshAllChannels(session: Session): Promise<ChannelMeta[]>;
|
|
28
|
+
/** All cached channels, refreshing member channels first if the cache is stale or empty. */
|
|
29
|
+
export declare function getChannels(session: Session): Promise<ChannelMeta[]>;
|
|
30
|
+
export declare function cachedChannels(teamId: string): ChannelMeta[];
|
|
31
|
+
export declare function getCachedChannel(teamId: string, id: string): ChannelMeta | undefined;
|
|
32
|
+
/** Fetch a single channel by id via conversations.info and cache it. */
|
|
33
|
+
export declare function fetchChannelInfo(session: Session, id: string): Promise<ChannelMeta>;
|
|
34
|
+
/** Fetch the full user directory (paginate to completion) and replace the users cache. */
|
|
35
|
+
export declare function refreshUsers(session: Session): Promise<void>;
|
|
36
|
+
/** Ensure the users cache is populated and fresh. */
|
|
37
|
+
export declare function ensureUsers(session: Session): Promise<void>;
|
|
38
|
+
export declare function cachedUser(teamId: string, id: string): UserMeta | undefined;
|
|
39
|
+
/** The whole users map (one file read) — for labeling many messages without repeated reads. */
|
|
40
|
+
export declare function allCachedUsers(teamId: string): Record<string, UserMeta>;
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { cacheChannelsPath, cacheUsersPath } from "../config.js";
|
|
4
|
+
/** Cache freshness window. Caches only map id↔name; message content is always fetched live. */
|
|
5
|
+
export const CACHE_TTL_MS = 60 * 60 * 1000;
|
|
6
|
+
function readJson(path) {
|
|
7
|
+
if (!existsSync(path))
|
|
8
|
+
return undefined;
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function writeJson(path, value) {
|
|
17
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
18
|
+
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
19
|
+
}
|
|
20
|
+
function now() {
|
|
21
|
+
return Date.now();
|
|
22
|
+
}
|
|
23
|
+
// ---------------------------------------------------------------------------- channels
|
|
24
|
+
function classify(c) {
|
|
25
|
+
if (c.is_im)
|
|
26
|
+
return "im";
|
|
27
|
+
if (c.is_mpim)
|
|
28
|
+
return "mpim";
|
|
29
|
+
if (c.is_private)
|
|
30
|
+
return "private";
|
|
31
|
+
return "public";
|
|
32
|
+
}
|
|
33
|
+
function toChannelMeta(c) {
|
|
34
|
+
const topic = c.topic?.value;
|
|
35
|
+
const purpose = c.purpose?.value;
|
|
36
|
+
return {
|
|
37
|
+
id: String(c.id),
|
|
38
|
+
name: typeof c.name === "string" ? c.name : "",
|
|
39
|
+
type: classify(c),
|
|
40
|
+
is_member: c.is_member === true,
|
|
41
|
+
is_archived: c.is_archived === true,
|
|
42
|
+
...(typeof c.user === "string" ? { user: c.user } : {}),
|
|
43
|
+
...(topic ? { topic } : {}),
|
|
44
|
+
...(purpose ? { purpose } : {}),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function loadChannels(teamId) {
|
|
48
|
+
return readJson(cacheChannelsPath(teamId)) ?? { fetched_at: 0, channels: {} };
|
|
49
|
+
}
|
|
50
|
+
function saveChannels(teamId, cache) {
|
|
51
|
+
writeJson(cacheChannelsPath(teamId), cache);
|
|
52
|
+
}
|
|
53
|
+
/** Merge freshly-fetched channels into the cache (newer entries win). */
|
|
54
|
+
function mergeChannels(teamId, fresh) {
|
|
55
|
+
const cache = loadChannels(teamId);
|
|
56
|
+
for (const ch of fresh)
|
|
57
|
+
cache.channels[ch.id] = ch;
|
|
58
|
+
cache.fetched_at = now();
|
|
59
|
+
saveChannels(teamId, cache);
|
|
60
|
+
return fresh;
|
|
61
|
+
}
|
|
62
|
+
/** Fetch the user's conversations across ALL types (paginate to completion) and update the cache. */
|
|
63
|
+
export async function refreshMemberChannels(session) {
|
|
64
|
+
const result = [];
|
|
65
|
+
let cursor;
|
|
66
|
+
do {
|
|
67
|
+
const res = await session.client.users.conversations({
|
|
68
|
+
types: "public_channel,private_channel,mpim,im",
|
|
69
|
+
exclude_archived: false,
|
|
70
|
+
limit: 200,
|
|
71
|
+
...(cursor ? { cursor } : {}),
|
|
72
|
+
});
|
|
73
|
+
for (const c of res.channels ?? [])
|
|
74
|
+
result.push(toChannelMeta({ ...c, is_member: true }));
|
|
75
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
76
|
+
} while (cursor);
|
|
77
|
+
return mergeChannels(session.teamId, result);
|
|
78
|
+
}
|
|
79
|
+
/** Fetch every public+private channel in the workspace (paginate to completion) and update the cache. */
|
|
80
|
+
export async function refreshAllChannels(session) {
|
|
81
|
+
const result = [];
|
|
82
|
+
let cursor;
|
|
83
|
+
do {
|
|
84
|
+
const res = await session.client.conversations.list({
|
|
85
|
+
types: "public_channel,private_channel",
|
|
86
|
+
exclude_archived: false,
|
|
87
|
+
limit: 200,
|
|
88
|
+
...(cursor ? { cursor } : {}),
|
|
89
|
+
});
|
|
90
|
+
for (const c of res.channels ?? [])
|
|
91
|
+
result.push(toChannelMeta(c));
|
|
92
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
93
|
+
} while (cursor);
|
|
94
|
+
return mergeChannels(session.teamId, result);
|
|
95
|
+
}
|
|
96
|
+
/** All cached channels, refreshing member channels first if the cache is stale or empty. */
|
|
97
|
+
export async function getChannels(session) {
|
|
98
|
+
const cache = loadChannels(session.teamId);
|
|
99
|
+
if (now() - cache.fetched_at > CACHE_TTL_MS || Object.keys(cache.channels).length === 0) {
|
|
100
|
+
await refreshMemberChannels(session);
|
|
101
|
+
}
|
|
102
|
+
return Object.values(loadChannels(session.teamId).channels);
|
|
103
|
+
}
|
|
104
|
+
export function cachedChannels(teamId) {
|
|
105
|
+
return Object.values(loadChannels(teamId).channels);
|
|
106
|
+
}
|
|
107
|
+
export function getCachedChannel(teamId, id) {
|
|
108
|
+
return loadChannels(teamId).channels[id];
|
|
109
|
+
}
|
|
110
|
+
/** Fetch a single channel by id via conversations.info and cache it. */
|
|
111
|
+
export async function fetchChannelInfo(session, id) {
|
|
112
|
+
const res = await session.client.conversations.info({ channel: id });
|
|
113
|
+
const [meta] = mergeChannels(session.teamId, [toChannelMeta(res.channel)]);
|
|
114
|
+
return meta;
|
|
115
|
+
}
|
|
116
|
+
// ---------------------------------------------------------------------------- users
|
|
117
|
+
function toUserMeta(u) {
|
|
118
|
+
const profile = u.profile ?? {};
|
|
119
|
+
return {
|
|
120
|
+
id: String(u.id),
|
|
121
|
+
name: typeof u.name === "string" ? u.name : String(u.id),
|
|
122
|
+
...(profile.real_name ? { real_name: profile.real_name } : {}),
|
|
123
|
+
...(profile.display_name ? { display_name: profile.display_name } : {}),
|
|
124
|
+
is_bot: u.is_bot === true,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function loadUsers(teamId) {
|
|
128
|
+
return readJson(cacheUsersPath(teamId)) ?? { fetched_at: 0, users: {} };
|
|
129
|
+
}
|
|
130
|
+
function saveUsers(teamId, cache) {
|
|
131
|
+
writeJson(cacheUsersPath(teamId), cache);
|
|
132
|
+
}
|
|
133
|
+
/** Fetch the full user directory (paginate to completion) and replace the users cache. */
|
|
134
|
+
export async function refreshUsers(session) {
|
|
135
|
+
const users = {};
|
|
136
|
+
let cursor;
|
|
137
|
+
do {
|
|
138
|
+
const res = await session.client.users.list({ limit: 200, ...(cursor ? { cursor } : {}) });
|
|
139
|
+
for (const u of res.members ?? []) {
|
|
140
|
+
const meta = toUserMeta(u);
|
|
141
|
+
users[meta.id] = meta;
|
|
142
|
+
}
|
|
143
|
+
cursor = res.response_metadata?.next_cursor || undefined;
|
|
144
|
+
} while (cursor);
|
|
145
|
+
saveUsers(session.teamId, { fetched_at: now(), users });
|
|
146
|
+
}
|
|
147
|
+
/** Ensure the users cache is populated and fresh. */
|
|
148
|
+
export async function ensureUsers(session) {
|
|
149
|
+
const cache = loadUsers(session.teamId);
|
|
150
|
+
if (now() - cache.fetched_at > CACHE_TTL_MS || Object.keys(cache.users).length === 0) {
|
|
151
|
+
await refreshUsers(session);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export function cachedUser(teamId, id) {
|
|
155
|
+
return loadUsers(teamId).users[id];
|
|
156
|
+
}
|
|
157
|
+
/** The whole users map (one file read) — for labeling many messages without repeated reads. */
|
|
158
|
+
export function allCachedUsers(teamId) {
|
|
159
|
+
return loadUsers(teamId).users;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/slack/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { WebClient } from "@slack/web-api";
|
|
2
|
+
/** A validated token plus the workspace/user metadata derived from auth.test. */
|
|
3
|
+
export interface TokenIdentity {
|
|
4
|
+
teamId: string;
|
|
5
|
+
teamName: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
userName?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
scopes: string[];
|
|
10
|
+
}
|
|
11
|
+
/** Build a Slack Web API client for a token. The SDK handles tiered rate-limit retry. */
|
|
12
|
+
export declare function webClient(token: string): WebClient;
|
|
13
|
+
/**
|
|
14
|
+
* Validate a token via auth.test and capture granted scopes.
|
|
15
|
+
*
|
|
16
|
+
* Uses a direct fetch (not WebClient) because the granted scopes are returned in the
|
|
17
|
+
* `x-oauth-scopes` response header, which we want alongside the body in a single call —
|
|
18
|
+
* the reliable source for scope-coverage checks (see specs/behaviors/auth-and-workspaces.md).
|
|
19
|
+
* Throws the raw Slack error code (string) on failure for the caller to translate.
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateToken(token: string): Promise<TokenIdentity>;
|