@circlesac/holla 26.2.17 → 26.2.19

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/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # holla-cli
2
+
3
+ CLI for interacting with Slack from the terminal.
4
+
5
+ ```
6
+ holla slack <command> <action> [--flags]
7
+ ```
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ # From source
13
+ bun install
14
+ bun run build # outputs dist/holla
15
+
16
+ # Or run directly
17
+ bun run src/index.ts
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ # Authenticate via OAuth (opens browser)
24
+ holla slack auth login
25
+
26
+ # Or paste a token directly
27
+ holla slack auth login --token xoxb-...
28
+ ```
29
+
30
+ ## Commands
31
+
32
+ ### Auth
33
+
34
+ ```bash
35
+ holla slack auth login # OAuth login (default) or --token
36
+ holla slack auth logout # Remove stored credentials
37
+ holla slack auth status # Show auth status for all workspaces
38
+ ```
39
+
40
+ ### Channels
41
+
42
+ ```bash
43
+ holla slack channels list # List channels
44
+ holla slack channels info --channel #general # Channel details
45
+ holla slack channels history --channel #general # Message history
46
+ holla slack channels create --name new-channel # Create channel
47
+ holla slack channels join --channel #general # Join channel
48
+ holla slack channels leave --channel #general # Leave channel
49
+ holla slack channels topic --channel #general --topic "New topic"
50
+ ```
51
+
52
+ ### Chat
53
+
54
+ ```bash
55
+ holla slack chat send --channel #general --message "Hello!"
56
+ echo "piped message" | holla slack chat send --channel #general
57
+ holla slack chat edit --channel #general --ts 1234 --message "Updated"
58
+ holla slack chat delete --channel #general --ts 1234
59
+ holla slack chat schedule --channel #general --message "Later" --post-at 1735689600
60
+ ```
61
+
62
+ ### Search
63
+
64
+ ```bash
65
+ holla slack search messages --query "deploy"
66
+ holla slack search files --query "report"
67
+ ```
68
+
69
+ ### Users
70
+
71
+ ```bash
72
+ holla slack users list
73
+ holla slack users info --user @john
74
+ holla slack users find --email john@example.com
75
+ holla slack users profile --user @john
76
+ ```
77
+
78
+ ### Reactions
79
+
80
+ ```bash
81
+ holla slack reactions add --channel #general --ts 1234 --name thumbsup
82
+ holla slack reactions remove --channel #general --ts 1234 --name thumbsup
83
+ ```
84
+
85
+ ### Files
86
+
87
+ ```bash
88
+ holla slack files upload --channel #general --file ./report.pdf
89
+ holla slack files list
90
+ holla slack files delete --file F1234
91
+ ```
92
+
93
+ ### Other Commands
94
+
95
+ ```bash
96
+ holla slack pins add/list/remove
97
+ holla slack stars add/list/remove
98
+ holla slack bookmarks add/edit/list/remove
99
+ holla slack reminders add/list/info/complete/delete
100
+ holla slack dnd status/snooze/unsnooze/end
101
+ holla slack groups create/list/update/enable/disable/members/set-members
102
+ holla slack emoji list
103
+ holla slack team info/profile
104
+ ```
105
+
106
+ ### Raw API Passthrough
107
+
108
+ For any Slack API method not covered by the commands above:
109
+
110
+ ```bash
111
+ holla slack api conversations.requestSharedInvite.approve --invite-id I123
112
+ holla slack api chat.scheduledMessages.list
113
+ holla slack api admin.conversations.restrictAccess.addGroup --channel-id C123
114
+ ```
115
+
116
+ ## Name Resolution
117
+
118
+ Use `#channel` and `@user` syntax — they resolve to IDs automatically:
119
+
120
+ ```bash
121
+ holla slack chat send --channel #general --message "Hello!"
122
+ holla slack users info --user @john
123
+ ```
124
+
125
+ Raw IDs work too: `--channel C01234567`
126
+
127
+ ## Output Formats
128
+
129
+ ```bash
130
+ holla slack channels list # table (default)
131
+ holla slack channels list --json # JSON output
132
+ holla slack channels list --plain # tab-separated, no color
133
+ ```
134
+
135
+ ## Multi-Workspace
136
+
137
+ ```bash
138
+ # With one workspace, --workspace can be omitted
139
+ holla slack channels list
140
+
141
+ # With multiple workspaces, specify which one
142
+ holla slack channels list --workspace circles
143
+ ```
144
+
145
+ ## Environment Variables
146
+
147
+ | Variable | Description |
148
+ |----------|-------------|
149
+ | `SLACK_TOKEN` | Override token for all commands |
150
+ | `SLACK_CLIENT_ID` | Custom OAuth client ID |
151
+ | `SLACK_CLIENT_SECRET` | Custom OAuth client secret |
package/bin/holla CHANGED
@@ -1,16 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { execFileSync, existsSync } = require("child_process") || {};
4
- const { join } = require("path");
3
+ import { spawnSync } from "child_process";
4
+ import { existsSync } from "fs";
5
+ import { fileURLToPath } from "url";
6
+ import path from "path";
5
7
 
6
- const bin = join(__dirname, "native", "holla");
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const bin = path.join(__dirname, "native", "holla");
7
10
 
8
11
  if (!existsSync(bin)) {
9
- require("../install.js");
10
- }
11
-
12
- try {
13
- execFileSync(bin, process.argv.slice(2), { stdio: "inherit" });
14
- } catch (err) {
15
- process.exit(err.status ?? 1);
12
+ await import("./install.js");
16
13
  }
14
+ const result = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
15
+ process.exit(result.status ?? 1);
package/bin/install.js ADDED
@@ -0,0 +1,63 @@
1
+ import https from "https";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import { execSync } from "child_process";
5
+ import { fileURLToPath } from "url";
6
+ import { createRequire } from "module";
7
+
8
+ const require = createRequire(import.meta.url);
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+
11
+ const REPO = "circlesac/holla-cli";
12
+
13
+ const PLATFORMS = {
14
+ "darwin-x64": { artifact: "holla-darwin-x64", ext: ".tar.gz" },
15
+ "darwin-arm64": { artifact: "holla-darwin-arm64", ext: ".tar.gz" },
16
+ "linux-x64": { artifact: "holla-linux-x64", ext: ".tar.gz" },
17
+ "linux-arm64": { artifact: "holla-linux-arm64", ext: ".tar.gz" },
18
+ };
19
+
20
+ function download(url) {
21
+ return new Promise((resolve, reject) => {
22
+ https.get(url, (res) => {
23
+ if (res.statusCode === 302 || res.statusCode === 301) {
24
+ return download(res.headers.location).then(resolve).catch(reject);
25
+ }
26
+ if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`));
27
+ const chunks = [];
28
+ res.on("data", (c) => chunks.push(c));
29
+ res.on("end", () => resolve(Buffer.concat(chunks)));
30
+ res.on("error", reject);
31
+ });
32
+ });
33
+ }
34
+
35
+ const nativeDir = path.join(__dirname, "native");
36
+ const binPath = path.join(nativeDir, "holla");
37
+
38
+ if (!fs.existsSync(binPath)) {
39
+ const { version } = require("../package.json");
40
+ if (version) {
41
+ const platform = `${process.platform}-${process.arch}`;
42
+ const info = PLATFORMS[platform];
43
+ if (!info) {
44
+ console.error(`Unsupported platform: ${platform}`);
45
+ process.exit(1);
46
+ }
47
+
48
+ const { artifact, ext } = info;
49
+ const url = `https://github.com/${REPO}/releases/download/v${version}/${artifact}${ext}`;
50
+ console.info(`Downloading holla v${version} for ${platform}...`);
51
+
52
+ const data = await download(url);
53
+ fs.mkdirSync(nativeDir, { recursive: true });
54
+
55
+ const tmp = path.join(nativeDir, `tmp${ext}`);
56
+ fs.writeFileSync(tmp, data);
57
+ execSync(`tar xzf "${tmp}"`, { cwd: nativeDir });
58
+ fs.unlinkSync(tmp);
59
+
60
+ fs.chmodSync(binPath, 0o755);
61
+ console.info("Installed successfully.");
62
+ }
63
+ }
package/bin/install.sh ADDED
@@ -0,0 +1,24 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ REPO="circlesac/holla-cli"
5
+ INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
6
+
7
+ OS=$(uname -s | tr '[:upper:]' '[:lower:]')
8
+ ARCH=$(uname -m)
9
+
10
+ case "$OS-$ARCH" in
11
+ darwin-arm64) TARGET="holla-darwin-arm64" ;;
12
+ darwin-x86_64) TARGET="holla-darwin-x64" ;;
13
+ linux-aarch64) TARGET="holla-linux-arm64" ;;
14
+ linux-x86_64) TARGET="holla-linux-x64" ;;
15
+ *) echo "Unsupported platform: $OS-$ARCH"; exit 1 ;;
16
+ esac
17
+
18
+ VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" | grep '"tag_name"' | cut -d'"' -f4)
19
+ URL="https://github.com/$REPO/releases/download/$VERSION/$TARGET.tar.gz"
20
+
21
+ echo "Installing holla $VERSION..."
22
+ curl -fsSL "$URL" | tar xz -C "$INSTALL_DIR"
23
+ chmod +x "$INSTALL_DIR/holla"
24
+ echo "Installed to $INSTALL_DIR/holla"
package/package.json CHANGED
@@ -2,19 +2,42 @@
2
2
  "bin": {
3
3
  "holla": "bin/holla"
4
4
  },
5
+ "dependencies": {
6
+ "@circlesac/mack": "^26.2.4",
7
+ "@slack/web-api": "^7.13.0",
8
+ "citty": "^0.2.0"
9
+ },
5
10
  "description": "CLI tool that acts as you on messaging platforms",
11
+ "devDependencies": {
12
+ "@types/bun": "latest",
13
+ "@vitest/coverage-v8": "^4.0.18",
14
+ "vitest": "^4.0.18"
15
+ },
6
16
  "files": [
7
- "bin/holla",
8
- "install.js"
17
+ "bin",
18
+ "skills"
9
19
  ],
10
20
  "license": "MIT",
21
+ "module": "src/index.ts",
11
22
  "name": "@circlesac/holla",
23
+ "peerDependencies": {
24
+ "typescript": "^5"
25
+ },
26
+ "pi": {
27
+ "skills": [
28
+ "./skills"
29
+ ]
30
+ },
12
31
  "repository": {
13
32
  "type": "git",
14
33
  "url": "https://github.com/circlesac/holla-cli"
15
34
  },
16
35
  "scripts": {
17
- "postinstall": "node install.js"
36
+ "build": "bun build --compile --outfile=dist/holla src/index.ts",
37
+ "dev": "bun run src/index.ts",
38
+ "postinstall": "node bin/install.js",
39
+ "test": "vitest run"
18
40
  },
19
- "version": "26.2.17"
41
+ "type": "module",
42
+ "version": "26.2.19"
20
43
  }
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: slack
3
+ description: Use holla CLI to interact with Slack — send messages, read threads, search, manage canvases, and more
4
+ ---
5
+
6
+ holla is a CLI tool that lets you interact with Slack as yourself (using your user token). All commands require `--workspace <name>` (or `-w`).
7
+
8
+ ## Prerequisites
9
+
10
+ Authenticate first: `holla slack auth login --workspace <name>`
11
+
12
+ Check status: `holla slack auth whoami --workspace <name>`
13
+
14
+ ## Sending messages
15
+
16
+ ```bash
17
+ # Send to a channel
18
+ holla slack chat send --channel "#general" --text "Hello" -w <ws>
19
+
20
+ # Reply to a thread
21
+ holla slack chat reply --channel "#general" --ts 1234567890.123456 --text "Reply" -w <ws>
22
+
23
+ # Multiline via stdin
24
+ cat <<'EOF' | holla slack chat send --channel "#general" -w <ws>
25
+ Line one
26
+ Line two
27
+ EOF
28
+
29
+ # Edit a message
30
+ holla slack chat edit --channel "#general" --ts 1234567890.123456 --text "Updated" -w <ws>
31
+
32
+ # Delete a message
33
+ holla slack chat delete --channel "#general" --ts 1234567890.123456 -w <ws>
34
+ ```
35
+
36
+ `--text` accepts standard markdown (converted to Slack blocks automatically). Use `--json` to get `{ ts, channel, text }` back after sending.
37
+
38
+ ## Reading messages
39
+
40
+ ```bash
41
+ # Channel history
42
+ holla slack channels history --channel "#general" -w <ws> --json
43
+
44
+ # Thread replies
45
+ holla slack channels history --channel "#general" --thread 1234567890.123456 -w <ws> --json
46
+
47
+ # Single message
48
+ holla slack chat get --channel "#general" --ts 1234567890.123456 -w <ws> --json
49
+ ```
50
+
51
+ Use `--all` to auto-paginate. Use `--limit <n>` to control count.
52
+
53
+ ## Searching
54
+
55
+ ```bash
56
+ holla slack search messages --query "keyword" -w <ws> --json
57
+ ```
58
+
59
+ Options: `--sort timestamp|score`, `--sort-dir asc|desc`, `--limit <n>`, `--page <n>`
60
+
61
+ ## Canvases
62
+
63
+ ```bash
64
+ # Create (with optional auto-share)
65
+ holla slack canvases create --title "Title" --markdown "content" --channel "#general" -w <ws>
66
+
67
+ # Edit
68
+ holla slack canvases edit --canvas <id> --operation insert_at_end --markdown "more" -w <ws>
69
+
70
+ # Share
71
+ holla slack canvases access-set --canvas <id> --level read --channels "#general" -w <ws>
72
+ ```
73
+
74
+ Operations: `insert_at_start`, `insert_at_end`, `insert_before`, `insert_after`, `replace`, `delete`
75
+
76
+ ## Channels
77
+
78
+ ```bash
79
+ holla slack channels list -w <ws> --json # List channels
80
+ holla slack channels info --channel "#general" -w <ws> # Channel info
81
+ holla slack channels members --channel "#general" -w <ws> --json # Members
82
+ holla slack channels topic --channel "#general" --topic "New topic" -w <ws>
83
+ ```
84
+
85
+ ## Other commands
86
+
87
+ ```bash
88
+ holla slack reactions add --channel <ch> --ts <ts> --name thumbsup -w <ws>
89
+ holla slack pins add --channel <ch> --ts <ts> -w <ws>
90
+ holla slack stars add --channel <ch> --ts <ts> -w <ws>
91
+ holla slack bookmarks add --channel <ch> --title "Link" --link "https://..." -w <ws>
92
+ holla slack reminders add --text "Do thing" --time "in 1 hour" -w <ws>
93
+ holla slack files upload --channels "#general" --file ./doc.pdf -w <ws>
94
+ holla slack users info --user @username -w <ws> --json
95
+ holla slack api <method> --body '{"key":"value"}' -w <ws> # Raw API passthrough
96
+ ```
97
+
98
+ ## Output formats
99
+
100
+ All read commands support: `--json` (structured), `--plain` (tab-separated), or table (default).
101
+
102
+ ## Name resolution
103
+
104
+ Channels accept `#name` or ID. Users accept `@name` or ID. Fuzzy matching suggests corrections on typos.
package/install.js DELETED
@@ -1,41 +0,0 @@
1
- const { execSync } = require("child_process");
2
- const { createWriteStream, existsSync, mkdirSync, chmodSync } = require("fs");
3
- const { join } = require("path");
4
- const https = require("https");
5
-
6
- const REPO = "circlesac/holla-cli";
7
- const BIN_DIR = join(__dirname, "bin", "native");
8
- const BIN_PATH = join(BIN_DIR, "holla");
9
-
10
- const PLATFORM_MAP = {
11
- "darwin-arm64": "holla-darwin-arm64",
12
- "darwin-x64": "holla-darwin-x64",
13
- "linux-arm64": "holla-linux-arm64",
14
- "linux-x64": "holla-linux-x64",
15
- };
16
-
17
- async function install() {
18
- if (existsSync(BIN_PATH)) return;
19
-
20
- const platform = `${process.platform}-${process.arch}`;
21
- const name = PLATFORM_MAP[platform];
22
- if (!name) {
23
- console.error(`Unsupported platform: ${platform}`);
24
- process.exit(1);
25
- }
26
-
27
- const version = require("./package.json").version;
28
- const url = `https://github.com/${REPO}/releases/download/v${version}/${name}.tar.gz`;
29
-
30
- mkdirSync(BIN_DIR, { recursive: true });
31
-
32
- console.log(`Downloading holla v${version} for ${platform}...`);
33
- execSync(`curl -fsSL "${url}" | tar xz -C "${BIN_DIR}"`, { stdio: "inherit" });
34
- chmodSync(BIN_PATH, 0o755);
35
- console.log("Installed successfully.");
36
- }
37
-
38
- install().catch((err) => {
39
- console.error("Failed to install holla:", err.message);
40
- process.exit(1);
41
- });