slackhive 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.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @fileoverview `slackhive init` — clone, configure, and start SlackHive.
3
+ *
4
+ * @module cli/commands/init
5
+ */
6
+ interface InitOptions {
7
+ dir: string;
8
+ skipStart?: boolean;
9
+ }
10
+ /**
11
+ * Runs `slackhive init` — interactive setup wizard.
12
+ *
13
+ * @param {InitOptions} opts - CLI options.
14
+ */
15
+ export declare function init(opts: InitOptions): Promise<void>;
16
+ export {};
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview `slackhive init` — clone, configure, and start SlackHive.
4
+ *
5
+ * @module cli/commands/init
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.init = init;
12
+ const child_process_1 = require("child_process");
13
+ const fs_1 = require("fs");
14
+ const path_1 = require("path");
15
+ const chalk_1 = __importDefault(require("chalk"));
16
+ const ora_1 = __importDefault(require("ora"));
17
+ const prompts_1 = __importDefault(require("prompts"));
18
+ const REPO_URL = 'https://github.com/amansrivastava17/slackhive.git';
19
+ /**
20
+ * Runs `slackhive init` — interactive setup wizard.
21
+ *
22
+ * @param {InitOptions} opts - CLI options.
23
+ */
24
+ async function init(opts) {
25
+ const dir = (0, path_1.resolve)(opts.dir);
26
+ console.log('');
27
+ console.log(chalk_1.default.bold(' 🐝 SlackHive Setup'));
28
+ console.log(chalk_1.default.gray(' Build, deploy, and orchestrate AI agent teams on Slack'));
29
+ console.log('');
30
+ // ── Check prerequisites ────────────────────────────────────────────────────
31
+ const checks = [
32
+ { name: 'Docker', cmd: 'docker --version' },
33
+ { name: 'Docker Compose', cmd: 'docker compose version' },
34
+ { name: 'Git', cmd: 'git --version' },
35
+ ];
36
+ for (const check of checks) {
37
+ try {
38
+ (0, child_process_1.execSync)(check.cmd, { stdio: 'ignore' });
39
+ console.log(chalk_1.default.green(' ✓') + ` ${check.name} found`);
40
+ }
41
+ catch {
42
+ console.log(chalk_1.default.red(` ✗ ${check.name} not found. Please install it first.`));
43
+ process.exit(1);
44
+ }
45
+ }
46
+ console.log('');
47
+ // ── Clone ──────────────────────────────────────────────────────────────────
48
+ if ((0, fs_1.existsSync)(dir)) {
49
+ console.log(chalk_1.default.yellow(` Directory ${opts.dir} already exists. Using existing.`));
50
+ }
51
+ else {
52
+ const spinner = (0, ora_1.default)('Cloning SlackHive repository...').start();
53
+ try {
54
+ (0, child_process_1.execSync)(`git clone ${REPO_URL} "${dir}"`, { stdio: 'ignore' });
55
+ spinner.succeed('Repository cloned');
56
+ }
57
+ catch (e) {
58
+ spinner.fail('Failed to clone repository');
59
+ process.exit(1);
60
+ }
61
+ }
62
+ // ── Configure .env ─────────────────────────────────────────────────────────
63
+ const envPath = (0, path_1.join)(dir, '.env');
64
+ const envExamplePath = (0, path_1.join)(dir, '.env.example');
65
+ if (!(0, fs_1.existsSync)(envPath) && (0, fs_1.existsSync)(envExamplePath)) {
66
+ console.log('');
67
+ console.log(chalk_1.default.bold(' Configure environment:'));
68
+ console.log('');
69
+ // Auth mode selection
70
+ const authMode = await (0, prompts_1.default)({
71
+ type: 'select',
72
+ name: 'mode',
73
+ message: 'How do you want to authenticate with Claude?',
74
+ choices: [
75
+ { title: 'API Key — pay-per-use via Anthropic API', value: 'apikey' },
76
+ { title: 'Subscription — Claude Max plan (run `claude login` first)', value: 'subscription' },
77
+ ],
78
+ });
79
+ if (!authMode.mode) {
80
+ console.log(chalk_1.default.red('\n Setup cancelled.'));
81
+ process.exit(1);
82
+ }
83
+ const questions = [];
84
+ if (authMode.mode === 'apikey') {
85
+ questions.push({
86
+ type: 'text',
87
+ name: 'anthropicKey',
88
+ message: 'Anthropic API key',
89
+ validate: (v) => v.startsWith('sk-') ? true : 'Must start with sk-',
90
+ });
91
+ }
92
+ else {
93
+ // Check if ~/.claude exists
94
+ const claudeDir = (0, path_1.join)(process.env.HOME || '~', '.claude');
95
+ if (!(0, fs_1.existsSync)(claudeDir)) {
96
+ console.log(chalk_1.default.yellow('\n ⚠ ~/.claude not found. Run `claude login` first, then re-run `slackhive init`.'));
97
+ process.exit(1);
98
+ }
99
+ console.log(chalk_1.default.green(' ✓') + ' Found ~/.claude credentials');
100
+ }
101
+ questions.push({
102
+ type: 'text',
103
+ name: 'adminUsername',
104
+ message: 'Admin username',
105
+ initial: 'admin',
106
+ }, {
107
+ type: 'password',
108
+ name: 'adminPassword',
109
+ message: 'Admin password',
110
+ validate: (v) => v.length >= 6 ? true : 'At least 6 characters',
111
+ }, {
112
+ type: 'text',
113
+ name: 'postgresPassword',
114
+ message: 'Postgres password',
115
+ initial: 'slackhive',
116
+ });
117
+ const response = await (0, prompts_1.default)(questions);
118
+ if (authMode.mode === 'apikey' && !response.anthropicKey) {
119
+ console.log(chalk_1.default.red('\n Setup cancelled.'));
120
+ process.exit(1);
121
+ }
122
+ if (!response.adminPassword) {
123
+ console.log(chalk_1.default.red('\n Setup cancelled.'));
124
+ process.exit(1);
125
+ }
126
+ let envContent = (0, fs_1.readFileSync)(envExamplePath, 'utf-8');
127
+ if (authMode.mode === 'apikey') {
128
+ envContent += `\nANTHROPIC_API_KEY=${response.anthropicKey}`;
129
+ }
130
+ else {
131
+ envContent += `\n# Using Claude Code subscription — credentials from ~/.claude`;
132
+ }
133
+ envContent += `\nADMIN_USERNAME=${response.adminUsername}`;
134
+ envContent += `\nADMIN_PASSWORD=${response.adminPassword}`;
135
+ envContent += `\nPOSTGRES_PASSWORD=${response.postgresPassword}`;
136
+ envContent += `\nAUTH_SECRET=${randomSecret()}`;
137
+ envContent += '\n';
138
+ (0, fs_1.writeFileSync)(envPath, envContent);
139
+ console.log(chalk_1.default.green('\n ✓') + ' .env file created');
140
+ }
141
+ else if ((0, fs_1.existsSync)(envPath)) {
142
+ console.log(chalk_1.default.yellow(' .env already exists, skipping configuration'));
143
+ }
144
+ // ── Start services ─────────────────────────────────────────────────────────
145
+ if (!opts.skipStart) {
146
+ console.log('');
147
+ const spinner = (0, ora_1.default)('Starting SlackHive services (this may take a few minutes on first run)...').start();
148
+ try {
149
+ (0, child_process_1.execSync)('docker compose up -d --build', { cwd: dir, stdio: 'ignore', timeout: 600000 });
150
+ spinner.succeed('All services started');
151
+ }
152
+ catch {
153
+ spinner.fail('Failed to start services');
154
+ console.log(chalk_1.default.gray(' Try running manually: cd ' + opts.dir + ' && docker compose up -d --build'));
155
+ process.exit(1);
156
+ }
157
+ // Wait for web to be ready
158
+ const webSpinner = (0, ora_1.default)('Waiting for web UI...').start();
159
+ let ready = false;
160
+ for (let i = 0; i < 30; i++) {
161
+ try {
162
+ (0, child_process_1.execSync)('curl -s -o /dev/null -w "%{http_code}" http://localhost:3001/login | grep -q 200', { stdio: 'ignore' });
163
+ ready = true;
164
+ break;
165
+ }
166
+ catch {
167
+ await sleep(2000);
168
+ }
169
+ }
170
+ if (ready) {
171
+ webSpinner.succeed('Web UI ready');
172
+ }
173
+ else {
174
+ webSpinner.warn('Web UI may still be starting — check http://localhost:3001');
175
+ }
176
+ }
177
+ // ── Done ───────────────────────────────────────────────────────────────────
178
+ console.log('');
179
+ console.log(chalk_1.default.bold.green(' ✅ SlackHive is ready!'));
180
+ console.log('');
181
+ console.log(` ${chalk_1.default.bold('Web UI:')} http://localhost:3001`);
182
+ console.log(` ${chalk_1.default.bold('Login:')} http://localhost:3001/login`);
183
+ console.log(` ${chalk_1.default.bold('Project dir:')} ${dir}`);
184
+ console.log('');
185
+ console.log(chalk_1.default.gray(' Commands:'));
186
+ console.log(chalk_1.default.gray(' slackhive start Start services'));
187
+ console.log(chalk_1.default.gray(' slackhive stop Stop services'));
188
+ console.log(chalk_1.default.gray(' slackhive status Show container status'));
189
+ console.log(chalk_1.default.gray(' slackhive logs Tail runner logs'));
190
+ console.log(chalk_1.default.gray(' slackhive update Pull latest & rebuild'));
191
+ console.log('');
192
+ }
193
+ function randomSecret() {
194
+ const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
195
+ let result = '';
196
+ for (let i = 0; i < 32; i++) {
197
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
198
+ }
199
+ return result;
200
+ }
201
+ function sleep(ms) {
202
+ return new Promise(resolve => setTimeout(resolve, ms));
203
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @fileoverview Management commands — start, stop, status, logs, update.
3
+ *
4
+ * All commands look for docker-compose.yml in the current directory
5
+ * or the `slackhive` subdirectory.
6
+ *
7
+ * @module cli/commands/manage
8
+ */
9
+ /**
10
+ * Start all SlackHive services.
11
+ */
12
+ export declare function start(): Promise<void>;
13
+ /**
14
+ * Stop all SlackHive services.
15
+ */
16
+ export declare function stop(): Promise<void>;
17
+ /**
18
+ * Show running SlackHive containers.
19
+ */
20
+ export declare function status(): Promise<void>;
21
+ /**
22
+ * Tail runner service logs.
23
+ */
24
+ export declare function logs(opts: {
25
+ follow?: boolean;
26
+ }): Promise<void>;
27
+ /**
28
+ * Pull latest changes and rebuild.
29
+ */
30
+ export declare function update(): Promise<void>;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /**
3
+ * @fileoverview Management commands — start, stop, status, logs, update.
4
+ *
5
+ * All commands look for docker-compose.yml in the current directory
6
+ * or the `slackhive` subdirectory.
7
+ *
8
+ * @module cli/commands/manage
9
+ */
10
+ var __importDefault = (this && this.__importDefault) || function (mod) {
11
+ return (mod && mod.__esModule) ? mod : { "default": mod };
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.start = start;
15
+ exports.stop = stop;
16
+ exports.status = status;
17
+ exports.logs = logs;
18
+ exports.update = update;
19
+ const child_process_1 = require("child_process");
20
+ const fs_1 = require("fs");
21
+ const path_1 = require("path");
22
+ const chalk_1 = __importDefault(require("chalk"));
23
+ const ora_1 = __importDefault(require("ora"));
24
+ /**
25
+ * Finds the SlackHive project directory.
26
+ * Checks cwd first, then ./slackhive subdirectory.
27
+ *
28
+ * @returns {string} Path to the project directory.
29
+ */
30
+ function findProjectDir() {
31
+ if ((0, fs_1.existsSync)((0, path_1.join)(process.cwd(), 'docker-compose.yml'))) {
32
+ return process.cwd();
33
+ }
34
+ const sub = (0, path_1.join)(process.cwd(), 'slackhive');
35
+ if ((0, fs_1.existsSync)((0, path_1.join)(sub, 'docker-compose.yml'))) {
36
+ return sub;
37
+ }
38
+ console.log(chalk_1.default.red(' Could not find SlackHive project.'));
39
+ console.log(chalk_1.default.gray(' Run this command from the SlackHive directory, or run `slackhive init` first.'));
40
+ process.exit(1);
41
+ }
42
+ /**
43
+ * Start all SlackHive services.
44
+ */
45
+ async function start() {
46
+ const dir = findProjectDir();
47
+ const spinner = (0, ora_1.default)('Starting SlackHive services...').start();
48
+ try {
49
+ (0, child_process_1.execSync)('docker compose up -d', { cwd: dir, stdio: 'ignore' });
50
+ spinner.succeed('All services started');
51
+ console.log(chalk_1.default.gray(' Web UI: http://localhost:3001'));
52
+ }
53
+ catch {
54
+ spinner.fail('Failed to start services');
55
+ }
56
+ }
57
+ /**
58
+ * Stop all SlackHive services.
59
+ */
60
+ async function stop() {
61
+ const dir = findProjectDir();
62
+ const spinner = (0, ora_1.default)('Stopping SlackHive services...').start();
63
+ try {
64
+ (0, child_process_1.execSync)('docker compose stop', { cwd: dir, stdio: 'ignore' });
65
+ spinner.succeed('All services stopped');
66
+ }
67
+ catch {
68
+ spinner.fail('Failed to stop services');
69
+ }
70
+ }
71
+ /**
72
+ * Show running SlackHive containers.
73
+ */
74
+ async function status() {
75
+ const dir = findProjectDir();
76
+ try {
77
+ const output = (0, child_process_1.execSync)('docker compose ps', { cwd: dir, encoding: 'utf-8' });
78
+ console.log('');
79
+ console.log(chalk_1.default.bold(' SlackHive Status'));
80
+ console.log('');
81
+ console.log(output);
82
+ }
83
+ catch {
84
+ console.log(chalk_1.default.red(' Failed to get status'));
85
+ }
86
+ }
87
+ /**
88
+ * Tail runner service logs.
89
+ */
90
+ async function logs(opts) {
91
+ const dir = findProjectDir();
92
+ const args = ['compose', 'logs', 'runner'];
93
+ if (opts.follow !== false)
94
+ args.push('-f');
95
+ const proc = (0, child_process_1.spawn)('docker', args, { cwd: dir, stdio: 'inherit' });
96
+ proc.on('error', () => console.log(chalk_1.default.red(' Failed to tail logs')));
97
+ }
98
+ /**
99
+ * Pull latest changes and rebuild.
100
+ */
101
+ async function update() {
102
+ const dir = findProjectDir();
103
+ const pullSpinner = (0, ora_1.default)('Pulling latest changes...').start();
104
+ try {
105
+ (0, child_process_1.execSync)('git pull', { cwd: dir, stdio: 'ignore' });
106
+ pullSpinner.succeed('Code updated');
107
+ }
108
+ catch {
109
+ pullSpinner.fail('Failed to pull — do you have uncommitted changes?');
110
+ return;
111
+ }
112
+ const buildSpinner = (0, ora_1.default)('Rebuilding services (this may take a minute)...').start();
113
+ try {
114
+ (0, child_process_1.execSync)('docker compose up -d --build', { cwd: dir, stdio: 'ignore', timeout: 600000 });
115
+ buildSpinner.succeed('Services rebuilt and restarted');
116
+ console.log(chalk_1.default.gray(' Web UI: http://localhost:3001'));
117
+ }
118
+ catch {
119
+ buildSpinner.fail('Failed to rebuild');
120
+ }
121
+ }
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @fileoverview SlackHive CLI — install, configure, and manage SlackHive.
4
+ *
5
+ * Commands:
6
+ * slackhive init — Clone repo, configure .env, start services
7
+ * slackhive start — Start all Docker Compose services
8
+ * slackhive stop — Stop all services
9
+ * slackhive status — Show running containers
10
+ * slackhive logs — Tail runner logs
11
+ * slackhive update — Pull latest changes and rebuild
12
+ *
13
+ * @module cli
14
+ */
15
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * @fileoverview SlackHive CLI — install, configure, and manage SlackHive.
5
+ *
6
+ * Commands:
7
+ * slackhive init — Clone repo, configure .env, start services
8
+ * slackhive start — Start all Docker Compose services
9
+ * slackhive stop — Stop all services
10
+ * slackhive status — Show running containers
11
+ * slackhive logs — Tail runner logs
12
+ * slackhive update — Pull latest changes and rebuild
13
+ *
14
+ * @module cli
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ const commander_1 = require("commander");
18
+ const init_1 = require("./commands/init");
19
+ const manage_1 = require("./commands/manage");
20
+ const program = new commander_1.Command();
21
+ program
22
+ .name('slackhive')
23
+ .description('CLI to install and manage SlackHive — AI agent teams on Slack')
24
+ .version('0.1.0');
25
+ program
26
+ .command('init')
27
+ .description('Clone SlackHive repo, configure environment, and start services')
28
+ .option('-d, --dir <path>', 'Directory to install into', 'slackhive')
29
+ .option('--skip-start', 'Skip starting services after init')
30
+ .action(init_1.init);
31
+ program
32
+ .command('start')
33
+ .description('Start all SlackHive services')
34
+ .action(manage_1.start);
35
+ program
36
+ .command('stop')
37
+ .description('Stop all SlackHive services')
38
+ .action(manage_1.stop);
39
+ program
40
+ .command('status')
41
+ .description('Show running SlackHive containers')
42
+ .action(manage_1.status);
43
+ program
44
+ .command('logs')
45
+ .description('Tail runner service logs')
46
+ .option('-f, --follow', 'Follow log output', true)
47
+ .action(manage_1.logs);
48
+ program
49
+ .command('update')
50
+ .description('Pull latest changes and rebuild')
51
+ .action(manage_1.update);
52
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "slackhive",
3
+ "version": "0.1.0",
4
+ "description": "CLI to install and manage SlackHive — AI agent teams on Slack",
5
+ "bin": {
6
+ "slackhive": "./dist/index.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "dev": "ts-node src/index.ts"
11
+ },
12
+ "keywords": ["slack", "ai", "agents", "claude", "claude-code", "slackhive"],
13
+ "author": "Aman Srivastava",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/amansrivastava17/slackhive"
18
+ },
19
+ "dependencies": {
20
+ "chalk": "^4.1.2",
21
+ "commander": "^12.0.0",
22
+ "ora": "^5.4.1",
23
+ "prompts": "^2.4.2"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.0.0",
27
+ "@types/prompts": "^2.4.9",
28
+ "typescript": "^5.3.0"
29
+ },
30
+ "engines": {
31
+ "node": ">=18.0.0"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ]
36
+ }