@avanderhoorn/toy-box-slack 0.0.0-stage → 0.2.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/README.md +159 -2
- package/package.json +40 -4
- package/toy-box-slack +5 -0
- package/toy-box-slack-darwin-arm64 +4 -0
package/README.md
CHANGED
|
@@ -1,3 +1,160 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 💬 Toy Box Slack
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Toy Box Slack lets a [Toy Box](https://github.com/lostintangent/toy-box) channel's Copilot lead work in one Slack channel. People you allow ask the lead questions there and get answers in their threads, the lead can publish release notes on a schedule, and useful Slack activity comes back to the Toy Box channel for discussion.
|
|
4
|
+
|
|
5
|
+
It runs as one local bridge beside Toy Box on your Mac. Only the bridge holds the Slack tokens, and it connects through Socket Mode, so it needs no public URL. The lead reaches Slack only through the `toy-box-slack` CLI.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Answers in threads:** When someone you allow mentions the app, the bridge wakes the channel's lead, which reacts with 👀 as it reads the request and answers once in its thread.
|
|
10
|
+
- **Only the people you allow:** Only people on the link's allowlist, by exact Slack member ID, can make the lead act, and the bridge checks that before the lead sees anything. Only you widen access, at your terminal, while the lead can only narrow it.
|
|
11
|
+
- **Nothing lost or sent twice:** Every Slack event the bridge acknowledges survives a crash, and anything it missed while stopped is recovered or reported. A post whose delivery is uncertain is looked up in Slack, never sent again.
|
|
12
|
+
- **Release notes and digests:** Optional routines publish release notes in the Slack channel, and bring a digest of what people said there back to the Toy Box channel.
|
|
13
|
+
- **Several leads:** One bridge hosts several Slack apps, so leads that share a Slack channel each answer as their own bot.
|
|
14
|
+
- **Keeps little:** By default the bridge keeps only what allowed people say and the threads they ask in, and it forgets any Slack text 30 days after it last changed.
|
|
15
|
+
- **Stops when the channel changes:** If the channel is shared outside your organization, made public or archived, or the app is removed from it, the bridge suspends the link for you to review.
|
|
16
|
+
|
|
17
|
+
It doesn't support DMs, attachments, Slack Connect, org-wide installs, rotating tokens, or Codex and Claude Code leads.
|
|
18
|
+
|
|
19
|
+
> ⚠️ Slack text the lead reads reaches Copilot and its selected model provider. Get your company's approval before you link a workspace, and read the [reviewer guide](docs/security-review.md).
|
|
20
|
+
|
|
21
|
+
## Getting Started
|
|
22
|
+
|
|
23
|
+
You need an Apple silicon Mac with [Node 24](https://nodejs.org/en/download), and a Slack workspace you're approved to add an app to.
|
|
24
|
+
|
|
25
|
+
1. Put `~/.local/bin` on your PATH, and install Copilot, Toy Box and Toy Box Slack there:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
29
|
+
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
|
|
30
|
+
npm install --global --prefix "$HOME/.local" \
|
|
31
|
+
@github/copilot @lostintangent/toy-box @avanderhoorn/toy-box-slack
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
1. Run `copilot`, sign in with `/login`, then exit.
|
|
35
|
+
|
|
36
|
+
1. Start Toy Box from that PATH, so its leads can find `toy-box-slack`, and keep it running:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
toy-box --host 127.0.0.1
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> ⚠️ Toy Box has no authentication. Never expose it publicly or through a tunnel.
|
|
43
|
+
|
|
44
|
+
1. Create the Slack app:
|
|
45
|
+
- At <https://api.slack.com/apps>, choose **Create New App → From a manifest**, pick the approved workspace, and paste [docs/manifest.yaml](docs/manifest.yaml).
|
|
46
|
+
- Review its eight bot scopes, create the app, and install it from **OAuth & Permissions**, which then shows its **Bot User OAuth Token** (`xoxb-...`).
|
|
47
|
+
- Under **Basic Information → App-Level Tokens**, generate a token (`xapp-...`) with the `connections:write` scope.
|
|
48
|
+
- Leave token rotation off. The manifest already turns on Socket Mode, so the app needs no Request URL.
|
|
49
|
+
|
|
50
|
+
1. In another terminal, run `toy-box-slack serve` and keep it running. The first time, it asks for both tokens, without showing what you type.
|
|
51
|
+
- Paste the tokens only there, never into Toy Box, Slack or the repository.
|
|
52
|
+
- Each time it starts, `serve` installs the skill leads learn the CLI from, and names its file.
|
|
53
|
+
|
|
54
|
+
1. In Slack, invite the app to the channel with `/invite` and select **Toy Box**. Copy the channel's ID from the bottom of its details, and each allowed person's member ID from their profile.
|
|
55
|
+
|
|
56
|
+
1. Open <http://127.0.0.1:3000>, create a channel with a Copilot lead (tested with `claude-sonnet-5`), and ask it to set up Slack for those IDs. To use a lead that was already running, first ask it to read the skill file `serve` named, since Copilot reads skills when a session starts or resumes.
|
|
57
|
+
|
|
58
|
+
1. The lead creates its requests routine and gives you a `link` and an `allow` command. Run them in another terminal. Each says what it changed, with names from Slack, and `deny` or `unlink` undoes it:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
toy-box-slack link --channel TOYBOX_ID --slack-channel SLACK_ID
|
|
62
|
+
toy-box-slack allow --channel TOYBOX_ID USER_ID
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
1. Send a **new** mention, picking the app from Slack's mention menu. Within minutes, you should see 👀 on it and one answer in its thread. If not, run `toy-box-slack status` and see the [operations guide](docs/operations.md).
|
|
66
|
+
|
|
67
|
+
## Link Options
|
|
68
|
+
|
|
69
|
+
By default, an allowed person asks the lead by mentioning the app, and the lead reads only what allowed people say and the threads they ask in. To widen that, add either option to `link`, or run `link` again with it later:
|
|
70
|
+
|
|
71
|
+
- `--requests all` makes any top-level post from an allowed person a request too.
|
|
72
|
+
- `--observe channel` lets the lead read the whole channel, so digests cover everyone.
|
|
73
|
+
|
|
74
|
+
`--requests mention` and `--observe requesters` set them back.
|
|
75
|
+
|
|
76
|
+
## Routines
|
|
77
|
+
|
|
78
|
+
The lead does its Slack work in Toy Box routines it creates from the skill. Ask it for a different schedule if these don't suit you.
|
|
79
|
+
|
|
80
|
+
- **Slack requests:** The lead answers each waiting request in its Slack thread, whenever the bridge wakes it and on weekdays at 9:00. It creates this routine as it sets up Slack.
|
|
81
|
+
- **Slack digest:** If you ask for it, the lead posts what's worth the team's attention in the Toy Box channel on weekdays at 17:00.
|
|
82
|
+
- **Release notes:** If you ask for it, the lead publishes notes in the Slack channel on what the git log and completed tasks say shipped, on Fridays at 16:00 or every weekday.
|
|
83
|
+
|
|
84
|
+
## Several Leads in One Slack Channel
|
|
85
|
+
|
|
86
|
+
People tell leads apart by the app they mention, so leads that share a Slack channel each need their own Slack app, while leads in different Slack channels can share one. To add an app for another lead:
|
|
87
|
+
|
|
88
|
+
1. Create another Slack app from the manifest, changing only its `name` and `display_name`. Install it, generate its app-level token, and invite it to the channel.
|
|
89
|
+
1. In a terminal, run `toy-box-slack add-app <name>`, which asks for the app's two tokens.
|
|
90
|
+
1. Restart `serve`, which starts every app it hosts.
|
|
91
|
+
1. Ask the new lead to set up Slack. Its `link` command names the app with `--app <name>`.
|
|
92
|
+
|
|
93
|
+
Ask people there to mention the lead they mean, since a reply that mentions no one reaches every lead its author asked in that thread. Two links with `--requests all` both answer a top-level post that mentions no one, from someone they both allow. The [operations guide](docs/operations.md#add-or-remove-an-app) covers app names, Slack's limits and removing an app.
|
|
94
|
+
|
|
95
|
+
## Keeping It Running
|
|
96
|
+
|
|
97
|
+
The bridge answers only while `serve` runs, and Ctrl-C stops it. When `serve` runs again, it catches up on what it missed, within [limits](docs/operations.md#deletion-and-limits). To start it at login instead, see the [operations guide](docs/operations.md#start-the-bridge-at-login).
|
|
98
|
+
|
|
99
|
+
`serve` keeps the tokens in `~/.toy-box-slack/credentials.env`, which only you can read. The bridge reads this file, not a `.env`, and environment variables of the same names override it.
|
|
100
|
+
|
|
101
|
+
| Variable | Default | What it sets |
|
|
102
|
+
| -------------------- | ----------------------- | ---------------------------------------- |
|
|
103
|
+
| `TOY_BOX_SLACK_HOME` | `~/.toy-box-slack` | The bridge's data folder |
|
|
104
|
+
| `TOY_BOX_URL` | `http://127.0.0.1:3000` | The Toy Box whose leads the bridge wakes |
|
|
105
|
+
|
|
106
|
+
## Updating
|
|
107
|
+
|
|
108
|
+
Install the new release, then restart `serve`, or the [login job](docs/operations.md#start-the-bridge-at-login) that runs it:
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npm install --global --prefix "$HOME/.local" @avanderhoorn/toy-box-slack
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`serve` installs the new release's skill. A routine keeps the prompt it was created with, so ask each lead to set its routines again from the new skill.
|
|
115
|
+
|
|
116
|
+
## Uninstalling
|
|
117
|
+
|
|
118
|
+
1. Ask each lead to delete its Slack routines.
|
|
119
|
+
1. Stop `serve`, or stop the [login job](docs/operations.md#start-the-bridge-at-login) and delete its plist.
|
|
120
|
+
1. Uninstall the CLI, and delete its data folder and skill:
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
npm uninstall --global --prefix "$HOME/.local" @avanderhoorn/toy-box-slack
|
|
124
|
+
rm -rf ~/.toy-box-slack ~/.copilot/skills/toy-box-slack
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
1. Uninstall each Slack app at <https://api.slack.com/apps>.
|
|
128
|
+
|
|
129
|
+
Copies outside the bridge stay, such as Toy Box transcripts and posts already in Slack, as the [reviewer guide](docs/security-review.md#retention-and-deletion) explains.
|
|
130
|
+
|
|
131
|
+
## Commands
|
|
132
|
+
|
|
133
|
+
| Command | Who runs it | What it does |
|
|
134
|
+
| ----------- | --------------- | ------------------------------------------------------------- |
|
|
135
|
+
| `serve` | You | Run the bridge and install its skill |
|
|
136
|
+
| `add-app` | You | Add another Slack app for the bridge to host |
|
|
137
|
+
| `link` | You | Link a Toy Box channel to a Slack channel, or change the link |
|
|
138
|
+
| `allow` | You | Let people make the lead act, by Slack member ID |
|
|
139
|
+
| `resume` | You | Answer and post again after a pause or suspension |
|
|
140
|
+
| `status` | You or the lead | Show the link, Slack's connection, requests and wakes |
|
|
141
|
+
| `deny` | You or the lead | Disallow people, and cancel their requests |
|
|
142
|
+
| `pause` | You or the lead | Stop answering and posting in Slack until you resume |
|
|
143
|
+
| `unlink` | You or the lead | Remove the link and delete what the bridge kept for it |
|
|
144
|
+
| `inbox` | The lead | Read waiting requests, with their threads so far |
|
|
145
|
+
| `reply` | The lead | Answer a request in its Slack thread, once |
|
|
146
|
+
| `dismiss` | The lead | End a request that needs no answer |
|
|
147
|
+
| `activity` | The lead | Read what's new in the Slack channel |
|
|
148
|
+
| `mark-read` | The lead | Mark activity read, so the next read starts after it |
|
|
149
|
+
| `publish` | The lead | Post once in Slack for a routine's latest scheduled run |
|
|
150
|
+
| `retract` | The lead | Delete one of its confirmed posts from Slack |
|
|
151
|
+
|
|
152
|
+
Run `toy-box-slack <command> --help` for its options. The [operations guide](docs/operations.md) covers status, pauses, uncertain posts, deletion and starting at login, and [research](docs/research) holds the evidence behind the design.
|
|
153
|
+
|
|
154
|
+
## Developing
|
|
155
|
+
|
|
156
|
+
1. Install [Bun](https://bun.com/docs/installation) 1.4.4, which CI uses, and clone this repo
|
|
157
|
+
1. Run `bun install`, which also points Git at the pre-commit hook
|
|
158
|
+
1. Run `bun run check` and `bun test`
|
|
159
|
+
|
|
160
|
+
`./cli/index.ts` runs the CLI from source. `bun run build` compiles the binary the npm package ships, and `./toy-box-slack` runs it as npm installs it. [AGENTS.md](AGENTS.md) covers the architecture, testing and releasing.
|
package/package.json
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@avanderhoorn/toy-box-slack",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Let a Toy Box channel's lead watch and answer a Slack channel",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/avanderhoorn/toy-box-connectors.git"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"toy-box-slack": "toy-box-slack"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"toy-box-slack",
|
|
14
|
+
"toy-box-slack-darwin-arm64"
|
|
15
|
+
],
|
|
16
|
+
"os": [
|
|
17
|
+
"darwin"
|
|
18
|
+
],
|
|
19
|
+
"cpu": [
|
|
20
|
+
"arm64"
|
|
21
|
+
],
|
|
22
|
+
"type": "module",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "bun build cli/index.ts --compile --minify --target=bun-darwin-arm64 --no-compile-autoload-dotenv --no-compile-autoload-bunfig --outfile toy-box-slack-darwin-arm64",
|
|
28
|
+
"check": "bun fmt --check && oxlint && bun check",
|
|
29
|
+
"prepare": "git config core.hooksPath .githooks 2>/dev/null || true"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@slack/socket-mode": "3.1.0",
|
|
34
|
+
"@slack/web-api": "8.2.0",
|
|
35
|
+
"bun-types": "^1.4.4",
|
|
36
|
+
"citty": "^0.2.2",
|
|
37
|
+
"cron-parser": "^5.10.2",
|
|
38
|
+
"oxlint": "^1.90.0",
|
|
39
|
+
"oxlint-tsgolint": "^7.0.2005",
|
|
40
|
+
"zod": "^4.6.7"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/toy-box-slack
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# The command npm installs, which runs the compiled CLI beside it. Toy Box sets BUN_BE_BUN in every
|
|
3
|
+
# agent's shell, and a compiled Bun program run with it set runs as Bun instead, so it's cleared here.
|
|
4
|
+
unset BUN_BE_BUN
|
|
5
|
+
exec "$(dirname "$(realpath "$0")")/toy-box-slack-darwin-arm64" "$@"
|