slack-term 1.23.1 → 1.24.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slack-term",
3
- "version": "1.23.1",
3
+ "version": "1.24.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/snomiao/slack-term.git"
package/ts/cli.ts CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  reactionAdd,
29
29
  reactionRemove,
30
30
  filesInfo,
31
+ filesList,
31
32
  history,
32
33
  listConversations,
33
34
  listDrafts,
@@ -1418,6 +1419,54 @@ async function cmdUpload(token: string, args: UploadArgs): Promise<void> {
1418
1419
  }
1419
1420
  }
1420
1421
 
1422
+ // --- files ls — list files visible to the token (files.list, read-only) ---
1423
+ // Walks files.list pages until it has `limit` rows or runs out. Canvases and
1424
+ // Slack Lists from the web "unified files" view mostly don't appear here (the
1425
+ // token can't reach those internal APIs) — this lists real file uploads.
1426
+ async function cmdFilesList(
1427
+ token: string,
1428
+ cookie: string | undefined,
1429
+ opts: { limit: number; types?: string; channel?: string; user?: string; format: string },
1430
+ ): Promise<void> {
1431
+ const channelId = opts.channel ? await resolveChannel(token, opts.channel, cookie) : undefined;
1432
+ const files: Record<string, Json>[] = [];
1433
+ let page = 1;
1434
+ let pages = 1;
1435
+ do {
1436
+ const listOpts: { page: number; count: number; types?: string; channel?: string; user?: string } = { page, count: 200 };
1437
+ if (opts.types) listOpts.types = opts.types;
1438
+ if (channelId) listOpts.channel = channelId;
1439
+ if (opts.user) listOpts.user = opts.user;
1440
+ const resp = asRecord((await filesList(token, listOpts, cookie)) as Json);
1441
+ for (const f of asArray(resp.files)) files.push(asRecord(f));
1442
+ pages = Number(asRecord(resp.paging).pages ?? 1);
1443
+ page++;
1444
+ } while (files.length < opts.limit && page <= pages);
1445
+ const shown = files.slice(0, opts.limit);
1446
+
1447
+ if (opts.format === "jsonl") {
1448
+ for (const f of shown) {
1449
+ console.log(JSON.stringify({
1450
+ id: f.id ?? null,
1451
+ name: f.name ?? f.title ?? null,
1452
+ filetype: f.filetype ?? null,
1453
+ size: f.size ?? null,
1454
+ user: f.user ?? null,
1455
+ created: f.created ?? null,
1456
+ permalink: f.permalink ?? null,
1457
+ }));
1458
+ }
1459
+ return;
1460
+ }
1461
+ for (const f of shown) {
1462
+ const id = String(f.id ?? "");
1463
+ const name = typeof f.name === "string" ? f.name : typeof f.title === "string" ? f.title : id;
1464
+ const ft = typeof f.filetype === "string" ? f.filetype : "?";
1465
+ const size = typeof f.size === "number" ? fmtSize(f.size) : "";
1466
+ console.log(`${id} ${ft.padEnd(7)} ${size.padStart(9)} ${name}`);
1467
+ }
1468
+ }
1469
+
1421
1470
  // --- download <ref> [dest] — fetch an attachment's bytes to disk (read-only) ---
1422
1471
  // ref: a file ID (F…) or a Slack file permalink (…/files/<UID>/<FID>/<name>).
1423
1472
  function parseFileId(ref: string): string | undefined {
@@ -1991,6 +2040,35 @@ async function main(): Promise<void> {
1991
2040
  await cmdUpload(tok(argv as W), args);
1992
2041
  },
1993
2042
  )
2043
+ .command(
2044
+ "files",
2045
+ "File commands",
2046
+ (y) => y
2047
+ .command(
2048
+ ["ls", "list"],
2049
+ "List files visible to you (files.list)",
2050
+ (y2) => y2
2051
+ .option("limit", { alias: "l", type: "number", default: 100, describe: "Max files to list" })
2052
+ .option("type", { alias: "t", type: "string", describe: "Slack type filter: images, pdfs, gdocs, snippets, zips, spaces, all" })
2053
+ .option("channel", { alias: "c", type: "string", describe: "Only files in this channel (#name, @user, ID, or permalink)" })
2054
+ .option("user", { alias: "u", type: "string", describe: "Only files from this raw user ID" })
2055
+ .option("format", { type: "string", choices: ["text", "jsonl"], default: "text" })
2056
+ .option("json", { type: "boolean", default: false, describe: "Alias for --format=jsonl" }),
2057
+ async (argv) => {
2058
+ const o: { limit: number; types?: string; channel?: string; user?: string; format: string } = {
2059
+ limit: argv.limit as number,
2060
+ format: argv.json ? "jsonl" : (argv.format as string),
2061
+ };
2062
+ if (argv.type) o.types = argv.type as string;
2063
+ if (argv.channel) o.channel = argv.channel as string;
2064
+ if (argv.user) o.user = argv.user as string;
2065
+ await cmdFilesList(tok(argv as W), ck(argv as W), o);
2066
+ },
2067
+ )
2068
+ .demandCommand(1, "")
2069
+ .showHelpOnFail(true),
2070
+ () => {},
2071
+ )
1994
2072
  .command(
1995
2073
  "download <ref> [dest]",
1996
2074
  "Download a file attachment (by file ID or file permalink) to disk",
package/ts/slack.ts CHANGED
@@ -213,6 +213,27 @@ export async function filesInfo(token: string, fileId: string, cookie?: string):
213
213
  return get(token, "files.info", { file: fileId }, cookie);
214
214
  }
215
215
 
216
+ // files.list — list files visible to the token. Paginated by page number (not a
217
+ // cursor); the response's `paging.pages` tells the caller how many pages exist.
218
+ // `types` is Slack's comma-separated filter (images,pdfs,gdocs,snippets,zips,
219
+ // spaces,all). Note: canvases and Slack Lists shown in the web "unified files"
220
+ // view are largely NOT returned here — those live behind internal APIs the CLI's
221
+ // token type can't reach — so this surfaces conventional file uploads.
222
+ export async function filesList(
223
+ token: string,
224
+ opts: { page?: number; count?: number; types?: string; channel?: string; user?: string } = {},
225
+ cookie?: string,
226
+ ): Promise<Json> {
227
+ const params: Record<string, string> = {
228
+ count: String(Math.min(Math.max(opts.count ?? 100, 1), 200)),
229
+ page: String(Math.max(opts.page ?? 1, 1)),
230
+ };
231
+ if (opts.types) params.types = opts.types;
232
+ if (opts.channel) params.channel = opts.channel;
233
+ if (opts.user) params.user = opts.user;
234
+ return get(token, "files.list", params, cookie);
235
+ }
236
+
216
237
  export async function searchPage(
217
238
  token: string,
218
239
  query: string,