@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 +151 -0
- package/bin/holla +9 -10
- package/bin/install.js +63 -0
- package/bin/install.sh +24 -0
- package/package.json +27 -4
- package/skills/slack/SKILL.md +104 -0
- package/install.js +0 -41
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
|
-
|
|
4
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
8
|
-
"
|
|
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
|
-
"
|
|
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
|
-
"
|
|
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
|
-
});
|