geekbot-cli 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.
- package/LICENSE +21 -0
- package/README.md +517 -0
- package/package.json +50 -0
- package/scripts/postinstall.mjs +27 -0
- package/skills/geekbot/SKILL.md +281 -0
- package/skills/geekbot/check-cli.sh +36 -0
- package/skills/geekbot/cli-commands.md +382 -0
- package/skills/geekbot/error-recovery.md +95 -0
- package/skills/geekbot/manager-workflows.md +408 -0
- package/skills/geekbot/reporter-workflows.md +275 -0
- package/skills/geekbot/standup-templates.json +244 -0
- package/src/auth/keychain.ts +38 -0
- package/src/auth/resolver.ts +44 -0
- package/src/cli/commands/auth.ts +56 -0
- package/src/cli/commands/me.ts +34 -0
- package/src/cli/commands/poll.ts +91 -0
- package/src/cli/commands/report.ts +66 -0
- package/src/cli/commands/standup.ts +234 -0
- package/src/cli/commands/team.ts +40 -0
- package/src/cli/globals.ts +31 -0
- package/src/cli/index.ts +94 -0
- package/src/errors/cli-error.ts +16 -0
- package/src/errors/error-handler.ts +63 -0
- package/src/errors/exit-codes.ts +14 -0
- package/src/errors/not-found-helper.ts +86 -0
- package/src/handlers/auth-handlers.ts +152 -0
- package/src/handlers/me-handlers.ts +27 -0
- package/src/handlers/poll-handlers.ts +187 -0
- package/src/handlers/report-handlers.ts +87 -0
- package/src/handlers/standup-handlers.ts +534 -0
- package/src/handlers/team-handlers.ts +38 -0
- package/src/http/authenticated-client.ts +17 -0
- package/src/http/client.ts +138 -0
- package/src/http/errors.ts +134 -0
- package/src/output/envelope.ts +50 -0
- package/src/output/formatter.ts +12 -0
- package/src/schemas/common.ts +13 -0
- package/src/schemas/poll.ts +89 -0
- package/src/schemas/report.ts +124 -0
- package/src/schemas/standup.ts +64 -0
- package/src/schemas/team.ts +11 -0
- package/src/schemas/user.ts +70 -0
- package/src/types.ts +30 -0
- package/src/utils/constants.ts +24 -0
- package/src/utils/input-parsers.ts +234 -0
- package/src/utils/receipt.ts +94 -0
- package/src/utils/validation.ts +128 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Geekbot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
# geekbot-cli
|
|
2
|
+
|
|
3
|
+
A cross-platform CLI tool for interacting with the Geekbot API, designed for AI agents and humans. Built with Bun and TypeScript.
|
|
4
|
+
|
|
5
|
+
Manage standups, reports, polls, teams, and user profiles programmatically with structured JSON output, machine-readable exit codes, and actionable error messages.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
### Prerequisites
|
|
10
|
+
|
|
11
|
+
- [Bun](https://bun.sh/) runtime (v1.3.5 or later)
|
|
12
|
+
|
|
13
|
+
### Install via npm
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
npm install -g geekbot-cli
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This installs the `geekbot` binary globally. The postinstall script checks for Bun and prints a hint about skill registration.
|
|
20
|
+
|
|
21
|
+
> **Note:** `npx geekbot-cli` also requires Bun on PATH — the CLI uses a `#!/usr/bin/env bun` shebang, so it is not a Node.js fallback.
|
|
22
|
+
|
|
23
|
+
Verify the installation:
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
geekbot --version
|
|
27
|
+
# 0.1.0
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Register the AI agent skill
|
|
31
|
+
|
|
32
|
+
To register the Geekbot skill with your AI coding agents (Claude Code, Cursor, Windsurf, Copilot, etc.):
|
|
33
|
+
|
|
34
|
+
```shell
|
|
35
|
+
npx skills add geekbot-com/geekbot-cli
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This uses the [Vercel Skills](https://github.com/vercel-labs/skills) ecosystem to detect installed agents and register the skill with all of them.
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary>Manual skill installation (without npx skills)</summary>
|
|
42
|
+
|
|
43
|
+
If you prefer not to use `npx skills`, copy the `skills/geekbot/` directory into your agent's skill directory:
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
# Claude Code
|
|
47
|
+
cp -r node_modules/geekbot-cli/skills/geekbot ~/.claude/skills/geekbot
|
|
48
|
+
|
|
49
|
+
# Universal (.agents/skills/ — works with Cursor, Codex, Gemini CLI, etc.)
|
|
50
|
+
mkdir -p .agents/skills
|
|
51
|
+
cp -r node_modules/geekbot-cli/skills/geekbot .agents/skills/geekbot
|
|
52
|
+
|
|
53
|
+
# Windsurf
|
|
54
|
+
cp -r node_modules/geekbot-cli/skills/geekbot ~/.codeium/windsurf/skills/geekbot
|
|
55
|
+
|
|
56
|
+
# Roo Code
|
|
57
|
+
cp -r node_modules/geekbot-cli/skills/geekbot ~/.roo/skills/geekbot
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The skill directory must contain `SKILL.md` and its sibling reference files (`cli-commands.md`, `manager-workflows.md`, etc.) — they are loaded by relative path.
|
|
61
|
+
|
|
62
|
+
</details>
|
|
63
|
+
|
|
64
|
+
### Install from source (for development)
|
|
65
|
+
|
|
66
|
+
```shell
|
|
67
|
+
git clone https://github.com/geekbot-com/geekbot-cli.git
|
|
68
|
+
cd geekbot-cli
|
|
69
|
+
bun install
|
|
70
|
+
bun link
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Platform support
|
|
74
|
+
|
|
75
|
+
| Platform | Status |
|
|
76
|
+
|----------|--------|
|
|
77
|
+
| macOS (x64, ARM64) | Supported |
|
|
78
|
+
| Linux (x64, ARM64) | Supported |
|
|
79
|
+
| Windows (x64) | Supported (requires Bun >= 1.3.5) |
|
|
80
|
+
| Windows (ARM64) | Not supported (Bun does not yet ship ARM64 Windows binaries) |
|
|
81
|
+
|
|
82
|
+
## Authentication
|
|
83
|
+
|
|
84
|
+
The CLI resolves API credentials using a three-level priority chain. The first source found wins:
|
|
85
|
+
|
|
86
|
+
1. **`--api-key` flag** (highest priority) -- per-command override, useful for scripts and CI
|
|
87
|
+
2. **`GEEKBOT_API_KEY` environment variable** -- session or shell-level credential
|
|
88
|
+
3. **OS keychain** (lowest priority) -- persistent, secure storage via `geekbot auth setup`
|
|
89
|
+
|
|
90
|
+
### OS Keychain Storage
|
|
91
|
+
|
|
92
|
+
The CLI uses [`@napi-rs/keyring`](https://github.com/nicola-nicolo/keyring) to store your API key in the platform-native credential store:
|
|
93
|
+
|
|
94
|
+
- **macOS**: Keychain
|
|
95
|
+
- **Windows**: Credential Vault
|
|
96
|
+
- **Linux**: Secret Service (GNOME Keyring / KDE Wallet)
|
|
97
|
+
|
|
98
|
+
Store a key interactively:
|
|
99
|
+
|
|
100
|
+
```shell
|
|
101
|
+
geekbot auth setup
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or non-interactively:
|
|
105
|
+
|
|
106
|
+
```shell
|
|
107
|
+
geekbot auth setup --api-key YOUR_API_KEY
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The setup command validates the key against the Geekbot API before storing it.
|
|
111
|
+
|
|
112
|
+
### Verify credentials
|
|
113
|
+
|
|
114
|
+
```shell
|
|
115
|
+
geekbot auth status
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Remove stored key
|
|
119
|
+
|
|
120
|
+
```shell
|
|
121
|
+
geekbot auth remove
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Global Options
|
|
125
|
+
|
|
126
|
+
These options apply to all commands:
|
|
127
|
+
|
|
128
|
+
| Option | Description | Default |
|
|
129
|
+
|--------|-------------|---------|
|
|
130
|
+
| `--api-key <key>` | Geekbot API key (overrides `GEEKBOT_API_KEY` env var) | -- |
|
|
131
|
+
| `--output <format>` | Output format (`json` only) | `json` |
|
|
132
|
+
| `--debug` | Show debug output on stderr | `false` |
|
|
133
|
+
| `-v, --version` | Print version number | -- |
|
|
134
|
+
| `--help` | Show help text | -- |
|
|
135
|
+
|
|
136
|
+
## Commands
|
|
137
|
+
|
|
138
|
+
The CLI follows a noun-verb pattern: `geekbot <resource> <action> [options]`.
|
|
139
|
+
|
|
140
|
+
### `standup` -- Manage standups
|
|
141
|
+
|
|
142
|
+
| Subcommand | Syntax | Description |
|
|
143
|
+
|------------|--------|-------------|
|
|
144
|
+
| `list` | `geekbot standup list [options]` | List standups you participate in |
|
|
145
|
+
| `get` | `geekbot standup get <id>` | Get a standup by ID |
|
|
146
|
+
| `create` | `geekbot standup create --name <name> --channel <channel> [options]` | Create a new standup |
|
|
147
|
+
| `update` | `geekbot standup update <id> [options]` | Partially update a standup (PATCH) |
|
|
148
|
+
| `replace` | `geekbot standup replace <id> --name <name> --channel <channel> [options]` | Fully replace a standup (PUT) |
|
|
149
|
+
| `delete` | `geekbot standup delete <id> --yes` | Delete a standup |
|
|
150
|
+
| `duplicate` | `geekbot standup duplicate <id> --name <name>` | Duplicate an existing standup |
|
|
151
|
+
| `start` | `geekbot standup start <id> [--users <ids>]` | Trigger a standup immediately |
|
|
152
|
+
|
|
153
|
+
#### `standup list` options
|
|
154
|
+
|
|
155
|
+
| Option | Default | Description |
|
|
156
|
+
|--------|---------|-------------|
|
|
157
|
+
| `--admin` | `false` | Include all team standups (admin only) |
|
|
158
|
+
| `--brief` | `false` | Return only id, name, channel, time, timezone, days |
|
|
159
|
+
| `--name <name>` | -- | Filter by name (case-insensitive substring match) |
|
|
160
|
+
| `--channel <channel>` | -- | Filter by channel (case-insensitive substring match) |
|
|
161
|
+
| `--mine` | `false` | Show only standups you are a member of |
|
|
162
|
+
|
|
163
|
+
#### `standup create` options
|
|
164
|
+
|
|
165
|
+
| Option | Required | Default | Description |
|
|
166
|
+
|--------|----------|---------|-------------|
|
|
167
|
+
| `--name <name>` | Yes | -- | Standup name |
|
|
168
|
+
| `--channel <channel>` | Yes | -- | Slack channel name |
|
|
169
|
+
| `--time <time>` | No | `10:00` | Time in HH:MM 24-hour format |
|
|
170
|
+
| `--timezone <tz>` | No | `UTC` | IANA timezone |
|
|
171
|
+
| `--days <days>` | No | `Mon,Tue,Wed,Thu,Fri` | Comma-separated days |
|
|
172
|
+
| `--questions <json>` | Yes | -- | Questions as JSON array |
|
|
173
|
+
| `--users <ids>` | No | -- | Comma-separated user IDs |
|
|
174
|
+
| `--wait-time <minutes>` | No | `0` | Minutes between users |
|
|
175
|
+
|
|
176
|
+
#### `standup update` options
|
|
177
|
+
|
|
178
|
+
| Option | Required | Description |
|
|
179
|
+
|--------|----------|-------------|
|
|
180
|
+
| `--name <name>` | No | New standup name |
|
|
181
|
+
| `--channel <channel>` | No | New channel |
|
|
182
|
+
| `--time <time>` | No | New time (HH:MM) |
|
|
183
|
+
| `--timezone <tz>` | No | New timezone |
|
|
184
|
+
| `--days <days>` | No | New days (comma-separated) |
|
|
185
|
+
| `--wait-time <minutes>` | No | New wait time in minutes |
|
|
186
|
+
|
|
187
|
+
#### `standup replace` options
|
|
188
|
+
|
|
189
|
+
Same options as `create`. `--name` and `--channel` are required; all other options have the same defaults as `create`.
|
|
190
|
+
|
|
191
|
+
#### `standup delete` options
|
|
192
|
+
|
|
193
|
+
| Option | Description |
|
|
194
|
+
|--------|-------------|
|
|
195
|
+
| `--yes` | Confirm deletion (required; deletion fails with an error if omitted) |
|
|
196
|
+
|
|
197
|
+
### `report` -- Manage reports
|
|
198
|
+
|
|
199
|
+
| Subcommand | Syntax | Description |
|
|
200
|
+
|------------|--------|-------------|
|
|
201
|
+
| `list` | `geekbot report list [options]` | List reports with optional filters |
|
|
202
|
+
| `create` | `geekbot report create --standup-id <id> --answers <json>` | Submit a report for a standup |
|
|
203
|
+
|
|
204
|
+
#### `report list` options
|
|
205
|
+
|
|
206
|
+
| Option | Description |
|
|
207
|
+
|--------|-------------|
|
|
208
|
+
| `--standup-id <id>` | Filter by standup ID |
|
|
209
|
+
| `--user-id <id>` | Filter by user ID |
|
|
210
|
+
| `--before <date>` | Reports before date (ISO 8601 or unix timestamp) |
|
|
211
|
+
| `--after <date>` | Reports after date (ISO 8601 or unix timestamp) |
|
|
212
|
+
| `--limit <n>` | Max number of reports to return |
|
|
213
|
+
|
|
214
|
+
#### `report create` options
|
|
215
|
+
|
|
216
|
+
| Option | Required | Description |
|
|
217
|
+
|--------|----------|-------------|
|
|
218
|
+
| `--standup-id <id>` | Yes | Standup ID to report on |
|
|
219
|
+
| `--answers <json>` | Yes | Answers as JSON object: `{"question_id": "answer", ...}` |
|
|
220
|
+
|
|
221
|
+
### `poll` -- Manage polls (Slack teams only)
|
|
222
|
+
|
|
223
|
+
Polls are only available for Slack-connected teams. Non-Slack teams will receive a platform error.
|
|
224
|
+
|
|
225
|
+
| Subcommand | Syntax | Description |
|
|
226
|
+
|------------|--------|-------------|
|
|
227
|
+
| `list` | `geekbot poll list` | List all polls |
|
|
228
|
+
| `get` | `geekbot poll get <id>` | Get a poll by ID |
|
|
229
|
+
| `create` | `geekbot poll create --name <name> --channel <channel> --question <text> --choices <json>` | Create a new poll |
|
|
230
|
+
| `votes` | `geekbot poll votes <id> [--after <date>] [--before <date>]` | Get voting results for a poll |
|
|
231
|
+
|
|
232
|
+
#### `poll create` options
|
|
233
|
+
|
|
234
|
+
| Option | Required | Description |
|
|
235
|
+
|--------|----------|-------------|
|
|
236
|
+
| `--name <name>` | Yes | Poll name |
|
|
237
|
+
| `--channel <channel>` | Yes | Slack channel |
|
|
238
|
+
| `--question <text>` | Yes | Poll question text |
|
|
239
|
+
| `--choices <json>` | Yes | Choices as JSON array of strings |
|
|
240
|
+
|
|
241
|
+
#### `poll votes` options
|
|
242
|
+
|
|
243
|
+
| Option | Description |
|
|
244
|
+
|--------|-------------|
|
|
245
|
+
| `--after <date>` | Votes after date |
|
|
246
|
+
| `--before <date>` | Votes before date |
|
|
247
|
+
|
|
248
|
+
### `me` -- View your profile and teams
|
|
249
|
+
|
|
250
|
+
| Subcommand | Syntax | Description |
|
|
251
|
+
|------------|--------|-------------|
|
|
252
|
+
| `show` | `geekbot me show` | Show your Geekbot profile |
|
|
253
|
+
| `teams` | `geekbot me teams` | List teams you belong to |
|
|
254
|
+
|
|
255
|
+
### `team` -- View team information
|
|
256
|
+
|
|
257
|
+
| Subcommand | Syntax | Description |
|
|
258
|
+
|------------|--------|-------------|
|
|
259
|
+
| `list` | `geekbot team list` | List all teams with members |
|
|
260
|
+
|
|
261
|
+
### `auth` -- Manage authentication
|
|
262
|
+
|
|
263
|
+
| Subcommand | Syntax | Description |
|
|
264
|
+
|------------|--------|-------------|
|
|
265
|
+
| `setup` | `geekbot auth setup [--api-key <key>]` | Interactively configure and store API key |
|
|
266
|
+
| `status` | `geekbot auth status` | Verify stored credentials work |
|
|
267
|
+
| `remove` | `geekbot auth remove` | Remove stored API key from OS keychain |
|
|
268
|
+
|
|
269
|
+
## Output Format
|
|
270
|
+
|
|
271
|
+
All command output is written to **stdout** as a JSON envelope. Diagnostic messages (debug output, Commander.js help/errors) go to **stderr**.
|
|
272
|
+
|
|
273
|
+
### JSON Envelope
|
|
274
|
+
|
|
275
|
+
Every response follows this structure:
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
interface OutputEnvelope<T> {
|
|
279
|
+
ok: boolean;
|
|
280
|
+
data: T | null;
|
|
281
|
+
error: ErrorObject | null;
|
|
282
|
+
metadata: MetadataObject;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### Success Response
|
|
287
|
+
|
|
288
|
+
```json
|
|
289
|
+
{
|
|
290
|
+
"ok": true,
|
|
291
|
+
"data": {
|
|
292
|
+
"id": 123,
|
|
293
|
+
"name": "Daily Standup",
|
|
294
|
+
"channel": "#engineering",
|
|
295
|
+
"time": "10:00",
|
|
296
|
+
"timezone": "America/New_York",
|
|
297
|
+
"days": ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
298
|
+
"questions": [
|
|
299
|
+
{ "id": 101, "text": "What did you do yesterday?" },
|
|
300
|
+
{ "id": 102, "text": "What will you do today?" }
|
|
301
|
+
]
|
|
302
|
+
},
|
|
303
|
+
"error": null,
|
|
304
|
+
"metadata": {
|
|
305
|
+
"timestamp": "2026-03-17T10:30:00.000Z"
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Error Response
|
|
311
|
+
|
|
312
|
+
```json
|
|
313
|
+
{
|
|
314
|
+
"ok": false,
|
|
315
|
+
"data": null,
|
|
316
|
+
"error": {
|
|
317
|
+
"code": "standup_not_found",
|
|
318
|
+
"message": "Standup 999 not found",
|
|
319
|
+
"retryable": false,
|
|
320
|
+
"suggestion": "Available standups: 123 (Daily Standup), 456 (Weekly Sync). Run `geekbot standup list` to see all."
|
|
321
|
+
},
|
|
322
|
+
"metadata": {
|
|
323
|
+
"timestamp": "2026-03-17T10:30:00.000Z"
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## Exit Codes
|
|
329
|
+
|
|
330
|
+
The CLI uses specific exit codes for programmatic error handling:
|
|
331
|
+
|
|
332
|
+
| Code | Name | Meaning |
|
|
333
|
+
|------|------|---------|
|
|
334
|
+
| 0 | `SUCCESS` | Operation completed successfully |
|
|
335
|
+
| 1 | `GENERAL` | Unexpected or unclassified error |
|
|
336
|
+
| 2 | `USAGE` | Invalid command syntax or missing required options |
|
|
337
|
+
| 3 | `NOT_FOUND` | Requested resource does not exist |
|
|
338
|
+
| 4 | `AUTH` | Authentication failed (missing or invalid API key) |
|
|
339
|
+
| 5 | `FORBIDDEN` | Insufficient permissions for the operation |
|
|
340
|
+
| 6 | `VALIDATION` | Input validation failed (bad format, invalid values) |
|
|
341
|
+
| 7 | `NETWORK` | Network error (DNS failure, timeout, connection refused) |
|
|
342
|
+
| 8 | `CONFLICT` | Resource conflict (duplicate name, concurrent modification) |
|
|
343
|
+
| 9 | `API_ERROR` | Geekbot API returned an unexpected error |
|
|
344
|
+
|
|
345
|
+
## Error Handling
|
|
346
|
+
|
|
347
|
+
Errors include machine-readable fields designed for programmatic consumption:
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
interface ErrorObject {
|
|
351
|
+
code: string; // Machine-readable error code (e.g., "standup_not_found")
|
|
352
|
+
message: string; // Human-readable description
|
|
353
|
+
retryable: boolean; // Whether retrying may succeed (e.g., network errors)
|
|
354
|
+
suggestion: string | null; // Actionable next step
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Key behaviors:
|
|
359
|
+
|
|
360
|
+
- **Not-found errors suggest alternatives**: When a resource ID is not found, the CLI queries for valid IDs and includes them in the `suggestion` field.
|
|
361
|
+
- **Retryable flag**: Network errors and rate limits are marked `retryable: true`. Auth and validation errors are not.
|
|
362
|
+
- **Structured output on failure**: Even errors produce a valid JSON envelope on stdout, so parsers never encounter unexpected output.
|
|
363
|
+
|
|
364
|
+
## Examples
|
|
365
|
+
|
|
366
|
+
### List standups
|
|
367
|
+
|
|
368
|
+
```shell
|
|
369
|
+
geekbot standup list --output json
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"ok": true,
|
|
375
|
+
"data": [
|
|
376
|
+
{ "id": 123, "name": "Daily Standup", "channel": "#engineering", "time": "10:00", "timezone": "UTC" },
|
|
377
|
+
{ "id": 456, "name": "Weekly Sync", "channel": "#team", "time": "09:00", "timezone": "America/New_York" }
|
|
378
|
+
],
|
|
379
|
+
"error": null,
|
|
380
|
+
"metadata": { "timestamp": "2026-03-17T10:00:00.000Z" }
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
### Create a standup
|
|
385
|
+
|
|
386
|
+
```shell
|
|
387
|
+
geekbot standup create \
|
|
388
|
+
--name "Sprint Retro" \
|
|
389
|
+
--channel "#engineering" \
|
|
390
|
+
--time "15:00" \
|
|
391
|
+
--timezone "America/Chicago" \
|
|
392
|
+
--days "Fri" \
|
|
393
|
+
--questions '[{"question": "What went well?"}, {"question": "What could improve?"}]'
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"ok": true,
|
|
399
|
+
"data": {
|
|
400
|
+
"id": 789,
|
|
401
|
+
"name": "Sprint Retro",
|
|
402
|
+
"channel": "#engineering",
|
|
403
|
+
"time": "15:00",
|
|
404
|
+
"timezone": "America/Chicago",
|
|
405
|
+
"days": ["Fri"]
|
|
406
|
+
},
|
|
407
|
+
"error": null,
|
|
408
|
+
"metadata": {
|
|
409
|
+
"timestamp": "2026-03-17T10:05:00.000Z",
|
|
410
|
+
"operation": "created",
|
|
411
|
+
"undo": "geekbot standup delete 789 --yes"
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
### Submit a report
|
|
417
|
+
|
|
418
|
+
```shell
|
|
419
|
+
geekbot report create \
|
|
420
|
+
--standup-id 123 \
|
|
421
|
+
--answers '{"101": "Finished auth module", "102": "Starting API tests"}'
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
```json
|
|
425
|
+
{
|
|
426
|
+
"ok": true,
|
|
427
|
+
"data": {
|
|
428
|
+
"id": 5001,
|
|
429
|
+
"standup_id": 123,
|
|
430
|
+
"questions": [
|
|
431
|
+
{ "id": 101, "text": "What did you do yesterday?", "answer": "Finished auth module" },
|
|
432
|
+
{ "id": 102, "text": "What will you do today?", "answer": "Starting API tests" }
|
|
433
|
+
]
|
|
434
|
+
},
|
|
435
|
+
"error": null,
|
|
436
|
+
"metadata": { "timestamp": "2026-03-17T10:10:00.000Z" }
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Handle a not-found error
|
|
441
|
+
|
|
442
|
+
```shell
|
|
443
|
+
geekbot standup get 999
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
```json
|
|
447
|
+
{
|
|
448
|
+
"ok": false,
|
|
449
|
+
"data": null,
|
|
450
|
+
"error": {
|
|
451
|
+
"code": "standup_not_found",
|
|
452
|
+
"message": "Standup 999 not found",
|
|
453
|
+
"retryable": false,
|
|
454
|
+
"suggestion": "Available standups: 123 (Daily Standup), 456 (Weekly Sync). Run `geekbot standup list` to see all."
|
|
455
|
+
},
|
|
456
|
+
"metadata": { "timestamp": "2026-03-17T10:15:00.000Z" }
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Exit code: `3` (NOT_FOUND)
|
|
461
|
+
|
|
462
|
+
### Create a poll (Slack only)
|
|
463
|
+
|
|
464
|
+
```shell
|
|
465
|
+
geekbot poll create \
|
|
466
|
+
--name "Team Lunch" \
|
|
467
|
+
--channel "#general" \
|
|
468
|
+
--question "Where should we eat?" \
|
|
469
|
+
--choices '["Pizza", "Sushi", "Tacos"]'
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Use environment variable for auth
|
|
473
|
+
|
|
474
|
+
```shell
|
|
475
|
+
export GEEKBOT_API_KEY=your-api-key
|
|
476
|
+
geekbot standup list
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Development
|
|
480
|
+
|
|
481
|
+
### Run tests
|
|
482
|
+
|
|
483
|
+
```shell
|
|
484
|
+
bun test
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### Lint
|
|
488
|
+
|
|
489
|
+
```shell
|
|
490
|
+
bun run lint
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### Format
|
|
494
|
+
|
|
495
|
+
```shell
|
|
496
|
+
bun run format
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Lint and auto-fix
|
|
500
|
+
|
|
501
|
+
```shell
|
|
502
|
+
bun run check
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Integration tests
|
|
506
|
+
|
|
507
|
+
Integration tests run against the live Geekbot API and require a valid API key:
|
|
508
|
+
|
|
509
|
+
```shell
|
|
510
|
+
GEEKBOT_INTEGRATION_TEST_API_KEY=your-key bun test:integration
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Tests are automatically skipped when `GEEKBOT_INTEGRATION_TEST_API_KEY` is not set. Tests that require a Slack channel (`#geekbot-skill-tests`) will gracefully skip with a warning if the channel does not exist in the workspace.
|
|
514
|
+
|
|
515
|
+
## License
|
|
516
|
+
|
|
517
|
+
See LICENSE.
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "geekbot-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/geekbot-com/geekbot-cli"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"geekbot": "./src/cli/index.ts"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"src/",
|
|
15
|
+
"skills/",
|
|
16
|
+
"scripts/"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"postinstall": "node scripts/postinstall.mjs",
|
|
20
|
+
"dev": "bun run src/cli/index.ts",
|
|
21
|
+
"test": "bun test",
|
|
22
|
+
"test:integration": "bun test tests/integration/",
|
|
23
|
+
"lint": "bunx biome check .",
|
|
24
|
+
"format": "bunx biome format --write .",
|
|
25
|
+
"check": "bunx biome check --write ."
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"provenance": true
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"geekbot",
|
|
33
|
+
"standup",
|
|
34
|
+
"cli",
|
|
35
|
+
"ai-agent",
|
|
36
|
+
"skill"
|
|
37
|
+
],
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@biomejs/biome": "^2.4.7",
|
|
40
|
+
"@types/bun": "^1.3.10"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"typescript": "^5"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@napi-rs/keyring": "^1.2.0",
|
|
47
|
+
"commander": "^14.0.3",
|
|
48
|
+
"zod": "^4.3.6"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Runs after npm install. Checks for Bun and hints about skill registration.
|
|
2
|
+
// Must work in plain Node.js (no Bun, no dependencies).
|
|
3
|
+
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
import { platform } from "node:os";
|
|
6
|
+
|
|
7
|
+
// ── Bun availability check ──────────────────────────────────────────────────
|
|
8
|
+
// The geekbot CLI binary requires Bun. Warn early if it's missing.
|
|
9
|
+
try {
|
|
10
|
+
execSync("bun --version", { stdio: "ignore" });
|
|
11
|
+
} catch {
|
|
12
|
+
const installCmd =
|
|
13
|
+
platform() === "win32"
|
|
14
|
+
? 'powershell -c "irm bun.sh/install.ps1 | iex"'
|
|
15
|
+
: "curl -fsSL https://bun.sh/install | bash";
|
|
16
|
+
console.warn(
|
|
17
|
+
"geekbot: warning: Bun runtime not found. The geekbot CLI requires Bun.\n" +
|
|
18
|
+
`geekbot: Install it: ${installCmd}\n` +
|
|
19
|
+
"geekbot: Then the `geekbot` command will work.",
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ── Skill registration hint ─────────────────────────────────────────────────
|
|
24
|
+
console.log(
|
|
25
|
+
"geekbot: to register the skill with your AI agents, run:\n" +
|
|
26
|
+
"geekbot: npx skills add geekbot-com/geekbot-cli",
|
|
27
|
+
);
|