prodboard 0.0.0 → 0.1.1
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/CHANGELOG.md +22 -0
- package/LICENSE +21 -0
- package/README.md +302 -0
- package/bin/prodboard.ts +4 -0
- package/config.schema.json +100 -0
- package/package.json +47 -6
- package/src/commands/comments.ts +86 -0
- package/src/commands/daemon.ts +112 -0
- package/src/commands/init.ts +83 -0
- package/src/commands/install.ts +127 -0
- package/src/commands/issues.ts +268 -0
- package/src/commands/schedules.ts +276 -0
- package/src/config.ts +155 -0
- package/src/confirm.ts +14 -0
- package/src/cron.ts +121 -0
- package/src/db.ts +157 -0
- package/src/format.ts +99 -0
- package/src/ids.ts +5 -0
- package/src/index.ts +227 -0
- package/src/invocation.ts +102 -0
- package/src/logger.ts +84 -0
- package/src/mcp.ts +543 -0
- package/src/queries/comments.ts +31 -0
- package/src/queries/issues.ts +155 -0
- package/src/queries/runs.ts +159 -0
- package/src/queries/schedules.ts +115 -0
- package/src/scheduler.ts +411 -0
- package/src/templates.ts +43 -0
- package/src/types.ts +82 -0
- package/templates/CLAUDE.md +12 -0
- package/templates/config.jsonc +38 -0
- package/templates/mcp.json +8 -0
- package/templates/system-prompt-nogit.md +33 -0
- package/templates/system-prompt.md +31 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# prodboard
|
|
2
|
+
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1aa4d25: Add `prodboard install` and `prodboard uninstall` commands to manage a user-level systemd service for the daemon
|
|
8
|
+
|
|
9
|
+
## 0.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- dc917e9: Initial release of prodboard — a self-hosted, CLI-first issue tracker and cron scheduler for AI coding agents.
|
|
14
|
+
|
|
15
|
+
Features:
|
|
16
|
+
|
|
17
|
+
- Full CLI for issue tracking (add, ls, show, edit, mv, rm, comment)
|
|
18
|
+
- MCP server with 14 tools for AI agent integration
|
|
19
|
+
- Cron-based scheduler daemon for automated agent runs
|
|
20
|
+
- SQLite-backed persistent storage
|
|
21
|
+
- Configurable via JSONC config file
|
|
22
|
+
- Template engine for schedule prompts with board context injection
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 prodboard contributors
|
|
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,302 @@
|
|
|
1
|
+
# prodboard
|
|
2
|
+
|
|
3
|
+
Give Claude Code a persistent task board and a cron scheduler so it can manage work across sessions.
|
|
4
|
+
|
|
5
|
+
**The problem:** Claude Code loses context between sessions. It can't remember what tasks exist, what's in progress, or what to work on next. There's no way to schedule it to run recurring jobs like daily triage or nightly CI.
|
|
6
|
+
|
|
7
|
+
**The solution:** prodboard is a local issue tracker backed by SQLite that Claude Code can read and write through MCP tools. It also includes a cron daemon that spawns Claude Code on a schedule to work through tasks autonomously.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
You (CLI) ──┐
|
|
11
|
+
├──▶ SQLite DB ◀── MCP Server ◀── Claude Code
|
|
12
|
+
Cron Daemon ──┘
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What You Get
|
|
16
|
+
|
|
17
|
+
- **An issue board Claude Code can use** — Claude reads, creates, updates, and completes issues via MCP tools during any session
|
|
18
|
+
- **Scheduled Claude Code runs** — Define cron jobs that spawn Claude Code to triage issues, run maintenance, or work through the backlog
|
|
19
|
+
- **A CLI you can use too** — Same board, human-friendly commands. Add issues, check status, review what Claude did
|
|
20
|
+
- **Everything local** — Single SQLite file at `~/.prodboard/db.sqlite`. No servers, no accounts, no cloud
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Install
|
|
26
|
+
bun install -g prodboard
|
|
27
|
+
|
|
28
|
+
# Initialize
|
|
29
|
+
prodboard init
|
|
30
|
+
|
|
31
|
+
# Connect Claude Code to the board
|
|
32
|
+
claude mcp add prodboard -- bunx prodboard mcp
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That's it. Open Claude Code and start talking to it:
|
|
36
|
+
|
|
37
|
+
## Things You Can Say to Claude Code
|
|
38
|
+
|
|
39
|
+
Once connected, you can manage your board entirely through conversation:
|
|
40
|
+
|
|
41
|
+
### Setting Up Cron Jobs
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
"Every hour, tail the nginx access and error logs. If you see
|
|
45
|
+
anything unusual — spikes in 5xx errors, suspicious request
|
|
46
|
+
patterns, or unexpected traffic — create a new issue to investigate"
|
|
47
|
+
|
|
48
|
+
"Every 2 hours, pick up the next todo issue and try to fix it.
|
|
49
|
+
Open a PR with your changes, comment the PR link on the issue,
|
|
50
|
+
and move the issue to review"
|
|
51
|
+
|
|
52
|
+
"Every 2 hours, pick up the next issue in review. Check out the
|
|
53
|
+
PR, verify the code is correct and tests pass. If everything
|
|
54
|
+
looks good, merge it. If not, add a review comment on the PR
|
|
55
|
+
explaining what needs to change and move the issue back to todo"
|
|
56
|
+
|
|
57
|
+
"Create a cron job that runs every 6 hours to check for
|
|
58
|
+
and fix any TypeScript type errors in the project"
|
|
59
|
+
|
|
60
|
+
"Set up a daily schedule at 9 AM on weekdays to review
|
|
61
|
+
the board and work on the highest priority task"
|
|
62
|
+
|
|
63
|
+
"Add a cron job that runs every night at midnight to
|
|
64
|
+
run the test suite and create issues for any failures"
|
|
65
|
+
|
|
66
|
+
"Schedule a weekly cleanup every Friday at 5 PM to
|
|
67
|
+
archive all done issues and summarize what was accomplished"
|
|
68
|
+
|
|
69
|
+
"Create a schedule that runs every 30 minutes to monitor
|
|
70
|
+
the API health endpoint and create an issue if it's down"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Managing Tasks
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
"Add a task to fix the authentication timeout bug in the API"
|
|
77
|
+
|
|
78
|
+
"What's on the board right now?"
|
|
79
|
+
|
|
80
|
+
"Pick up the next task and start working on it"
|
|
81
|
+
|
|
82
|
+
"Mark the login bug as done, I fixed it manually"
|
|
83
|
+
|
|
84
|
+
"Create an issue to refactor the database layer, mark it as todo"
|
|
85
|
+
|
|
86
|
+
"Show me all in-progress issues"
|
|
87
|
+
|
|
88
|
+
"Add a comment to the auth bug — we need to check the session TTL"
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Reviewing Activity
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
"Show me what the last cron run did"
|
|
95
|
+
|
|
96
|
+
"What tasks did you complete this week?"
|
|
97
|
+
|
|
98
|
+
"Show the schedule stats for the daily triage job"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Claude Code handles all the MCP tool calls behind the scenes — you just talk to it naturally.
|
|
102
|
+
|
|
103
|
+
## Adding Tasks from the CLI
|
|
104
|
+
|
|
105
|
+
You can also manage the board directly:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
prodboard add "Fix login bug" -d "OAuth callback URL is wrong" -s todo
|
|
109
|
+
prodboard add "Add dark mode" -s todo
|
|
110
|
+
prodboard add "Write API tests" -s todo
|
|
111
|
+
prodboard ls
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Starting the Scheduler
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Start the cron daemon (keeps running in foreground)
|
|
118
|
+
prodboard daemon
|
|
119
|
+
|
|
120
|
+
# Or preview what's scheduled without running anything
|
|
121
|
+
prodboard daemon --dry-run
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## CLI Reference
|
|
125
|
+
|
|
126
|
+
### Issues
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
prodboard add "Fix bug" -d "description" -s todo # Create
|
|
130
|
+
prodboard ls # List (table)
|
|
131
|
+
prodboard ls --status todo --status in-progress # Filter by status
|
|
132
|
+
prodboard ls --search "login" --json # Search + JSON output
|
|
133
|
+
prodboard show <id> # Details + comments
|
|
134
|
+
prodboard edit <id> --title "New title" -s review # Update fields
|
|
135
|
+
prodboard mv <id> done # Change status
|
|
136
|
+
prodboard rm <id> --force # Delete
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Comments
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
prodboard comment <id> "Looking into this" # Add comment
|
|
143
|
+
prodboard comment <id> "Fixed" --author claude # With author
|
|
144
|
+
prodboard comments <id> # List comments
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Schedules
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
prodboard schedule add --name "job" --cron "0 9 * * *" --prompt "Do X"
|
|
151
|
+
prodboard schedule ls # List schedules
|
|
152
|
+
prodboard schedule edit <id> --cron "0 10 * * *" # Edit
|
|
153
|
+
prodboard schedule enable <id> # Enable
|
|
154
|
+
prodboard schedule disable <id> # Disable
|
|
155
|
+
prodboard schedule rm <id> --force # Delete
|
|
156
|
+
prodboard schedule run <id> # Run immediately
|
|
157
|
+
prodboard schedule logs # Run history
|
|
158
|
+
prodboard schedule stats --days 7 # Statistics
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Daemon
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
prodboard daemon # Start (foreground)
|
|
165
|
+
prodboard daemon --dry-run # Preview schedules
|
|
166
|
+
prodboard daemon status # Check if running
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Other
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
prodboard config # Show configuration
|
|
173
|
+
prodboard version # Show version
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
IDs support prefix matching — use `a3f9` instead of the full `a3f9b2c1d4e5f678`.
|
|
177
|
+
|
|
178
|
+
## MCP Tools
|
|
179
|
+
|
|
180
|
+
These are the tools Claude Code sees when connected to the board:
|
|
181
|
+
|
|
182
|
+
| Tool | What Claude Uses It For |
|
|
183
|
+
|------|------------------------|
|
|
184
|
+
| `board_summary` | See issue counts and recent activity |
|
|
185
|
+
| `list_issues` | Browse issues with filters |
|
|
186
|
+
| `get_issue` | Read full issue details and comments |
|
|
187
|
+
| `create_issue` | Log a new task or bug |
|
|
188
|
+
| `update_issue` | Change title, description, or status |
|
|
189
|
+
| `delete_issue` | Remove an issue |
|
|
190
|
+
| `add_comment` | Leave notes on issues (default author: "claude") |
|
|
191
|
+
| `pick_next_issue` | Claim the oldest todo, move to in-progress |
|
|
192
|
+
| `complete_issue` | Mark done with an optional summary comment |
|
|
193
|
+
| `list_schedules` | See scheduled jobs |
|
|
194
|
+
| `create_schedule` | Set up a new cron job |
|
|
195
|
+
| `update_schedule` | Modify a schedule |
|
|
196
|
+
| `delete_schedule` | Remove a schedule |
|
|
197
|
+
| `list_runs` | Check run history and results |
|
|
198
|
+
|
|
199
|
+
MCP resources: `prodboard://issues` (board summary) and `prodboard://schedules` (active schedules).
|
|
200
|
+
|
|
201
|
+
## Configuration
|
|
202
|
+
|
|
203
|
+
Config file: `~/.prodboard/config.jsonc`
|
|
204
|
+
|
|
205
|
+
```jsonc
|
|
206
|
+
{
|
|
207
|
+
"general": {
|
|
208
|
+
"statuses": ["todo", "in-progress", "review", "done", "archived"],
|
|
209
|
+
"defaultStatus": "todo",
|
|
210
|
+
"idPrefix": ""
|
|
211
|
+
},
|
|
212
|
+
"daemon": {
|
|
213
|
+
"maxConcurrentRuns": 2,
|
|
214
|
+
"maxTurns": 50,
|
|
215
|
+
"hardMaxTurns": 200,
|
|
216
|
+
"runTimeoutSeconds": 1800,
|
|
217
|
+
"runRetentionDays": 30,
|
|
218
|
+
"logLevel": "info",
|
|
219
|
+
"useWorktrees": "auto"
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Scheduler Details
|
|
225
|
+
|
|
226
|
+
### Cron Syntax
|
|
227
|
+
|
|
228
|
+
Standard 5-field cron:
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
┌───────────── minute (0-59)
|
|
232
|
+
│ ┌─────────── hour (0-23)
|
|
233
|
+
│ │ ┌───────── day of month (1-31)
|
|
234
|
+
│ │ │ ┌─────── month (1-12)
|
|
235
|
+
│ │ │ │ ┌───── day of week (0-6, Sun=0)
|
|
236
|
+
│ │ │ │ │
|
|
237
|
+
* * * * *
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
| Expression | Meaning |
|
|
241
|
+
|-----------|---------|
|
|
242
|
+
| `0 9 * * 1-5` | Weekdays at 9 AM |
|
|
243
|
+
| `*/15 * * * *` | Every 15 minutes |
|
|
244
|
+
| `0 0 1 * *` | First of every month |
|
|
245
|
+
| `0 9,17 * * *` | 9 AM and 5 PM daily |
|
|
246
|
+
|
|
247
|
+
### Template Variables
|
|
248
|
+
|
|
249
|
+
Use in schedule prompts to inject board context:
|
|
250
|
+
|
|
251
|
+
| Variable | Value |
|
|
252
|
+
|----------|-------|
|
|
253
|
+
| `{{board_summary}}` | "3 todo, 1 in-progress, 0 review" |
|
|
254
|
+
| `{{todo_count}}` | Number of todo issues |
|
|
255
|
+
| `{{in_progress_count}}` | Number of in-progress issues |
|
|
256
|
+
| `{{datetime}}` | Current ISO 8601 timestamp |
|
|
257
|
+
| `{{schedule_name}}` | Name of the schedule |
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
prodboard schedule add \
|
|
261
|
+
--name "morning-standup" \
|
|
262
|
+
--cron "0 9 * * 1-5" \
|
|
263
|
+
--prompt "Board: {{board_summary}}. Pick the next todo and work on it."
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Running as a systemd Service
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
# Install and start as a user-level systemd service (no sudo needed)
|
|
270
|
+
prodboard install
|
|
271
|
+
|
|
272
|
+
# Check status
|
|
273
|
+
systemctl --user status prodboard
|
|
274
|
+
|
|
275
|
+
# Remove the service
|
|
276
|
+
prodboard uninstall
|
|
277
|
+
|
|
278
|
+
# Reinstall (e.g. after updating prodboard)
|
|
279
|
+
prodboard install --force
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Troubleshooting
|
|
283
|
+
|
|
284
|
+
**"prodboard is not initialized"** — Run `prodboard init`.
|
|
285
|
+
|
|
286
|
+
**MCP not connecting** — Verify `claude mcp add prodboard -- bunx prodboard mcp` was run, or check `~/.prodboard/mcp.json`.
|
|
287
|
+
|
|
288
|
+
**Daemon not starting** — Check `~/.prodboard/logs/daemon.log`. Make sure `claude` CLI is installed and `ANTHROPIC_API_KEY` is set.
|
|
289
|
+
|
|
290
|
+
**Stale PID file** — The daemon crashed. Run `prodboard daemon` to restart (auto-cleans stale PIDs).
|
|
291
|
+
|
|
292
|
+
## Development
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
bun install
|
|
296
|
+
bun test
|
|
297
|
+
bun run typecheck
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## License
|
|
301
|
+
|
|
302
|
+
MIT
|
package/bin/prodboard.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "prodboard Configuration",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"properties": {
|
|
6
|
+
"general": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"properties": {
|
|
9
|
+
"statuses": {
|
|
10
|
+
"type": "array",
|
|
11
|
+
"items": { "type": "string" },
|
|
12
|
+
"default": ["todo", "in-progress", "review", "done", "archived"],
|
|
13
|
+
"description": "Issue statuses in display order"
|
|
14
|
+
},
|
|
15
|
+
"defaultStatus": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"default": "todo",
|
|
18
|
+
"description": "Default status for new issues"
|
|
19
|
+
},
|
|
20
|
+
"idPrefix": {
|
|
21
|
+
"type": "string",
|
|
22
|
+
"default": "",
|
|
23
|
+
"description": "Optional prefix for issue IDs"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"additionalProperties": false
|
|
27
|
+
},
|
|
28
|
+
"daemon": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"properties": {
|
|
31
|
+
"maxConcurrentRuns": {
|
|
32
|
+
"type": "integer",
|
|
33
|
+
"minimum": 1,
|
|
34
|
+
"default": 2,
|
|
35
|
+
"description": "Maximum concurrent scheduled runs"
|
|
36
|
+
},
|
|
37
|
+
"maxTurns": {
|
|
38
|
+
"type": "integer",
|
|
39
|
+
"minimum": 1,
|
|
40
|
+
"default": 50,
|
|
41
|
+
"description": "Default max turns for Claude invocations"
|
|
42
|
+
},
|
|
43
|
+
"hardMaxTurns": {
|
|
44
|
+
"type": "integer",
|
|
45
|
+
"minimum": 1,
|
|
46
|
+
"default": 200,
|
|
47
|
+
"description": "Absolute max turns (cannot be overridden)"
|
|
48
|
+
},
|
|
49
|
+
"runTimeoutSeconds": {
|
|
50
|
+
"type": "integer",
|
|
51
|
+
"minimum": 60,
|
|
52
|
+
"default": 1800,
|
|
53
|
+
"description": "Timeout per run in seconds"
|
|
54
|
+
},
|
|
55
|
+
"runRetentionDays": {
|
|
56
|
+
"type": "integer",
|
|
57
|
+
"minimum": 1,
|
|
58
|
+
"default": 30,
|
|
59
|
+
"description": "Days to retain run history"
|
|
60
|
+
},
|
|
61
|
+
"logLevel": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": ["debug", "info", "warn", "error"],
|
|
64
|
+
"default": "info",
|
|
65
|
+
"description": "Daemon log level"
|
|
66
|
+
},
|
|
67
|
+
"logMaxSizeMb": {
|
|
68
|
+
"type": "number",
|
|
69
|
+
"minimum": 1,
|
|
70
|
+
"default": 10,
|
|
71
|
+
"description": "Max log file size in MB"
|
|
72
|
+
},
|
|
73
|
+
"logMaxFiles": {
|
|
74
|
+
"type": "integer",
|
|
75
|
+
"minimum": 1,
|
|
76
|
+
"default": 5,
|
|
77
|
+
"description": "Max number of rotated log files"
|
|
78
|
+
},
|
|
79
|
+
"defaultAllowedTools": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"items": { "type": "string" },
|
|
82
|
+
"description": "Default tools allowed for scheduled runs"
|
|
83
|
+
},
|
|
84
|
+
"nonGitDefaultAllowedTools": {
|
|
85
|
+
"type": "array",
|
|
86
|
+
"items": { "type": "string" },
|
|
87
|
+
"description": "Default tools for non-git environments"
|
|
88
|
+
},
|
|
89
|
+
"useWorktrees": {
|
|
90
|
+
"type": "string",
|
|
91
|
+
"enum": ["auto", "always", "never"],
|
|
92
|
+
"default": "auto",
|
|
93
|
+
"description": "Worktree usage strategy"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"additionalProperties": false
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"additionalProperties": false
|
|
100
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,52 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prodboard",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Self-hosted, CLI-first issue tracker and cron scheduler for AI coding agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/G4brym/prodboard"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/G4brym/prodboard#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/G4brym/prodboard/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cli",
|
|
17
|
+
"issue-tracker",
|
|
18
|
+
"mcp",
|
|
19
|
+
"ai-agents",
|
|
20
|
+
"scheduler",
|
|
21
|
+
"cron",
|
|
22
|
+
"sqlite"
|
|
23
|
+
],
|
|
24
|
+
"bin": {
|
|
25
|
+
"prodboard": "bin/prodboard.ts"
|
|
26
|
+
},
|
|
6
27
|
"scripts": {
|
|
7
|
-
"
|
|
28
|
+
"dev": "bun run bin/prodboard.ts",
|
|
29
|
+
"test": "bun test",
|
|
30
|
+
"typecheck": "bun x tsc --noEmit",
|
|
31
|
+
"changeset": "changeset",
|
|
32
|
+
"version": "changeset version",
|
|
33
|
+
"release": "bun run test && bun run typecheck && npm publish"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"bun": ">=1.0.0"
|
|
8
40
|
},
|
|
9
|
-
"
|
|
10
|
-
|
|
41
|
+
"files": [
|
|
42
|
+
"bin/",
|
|
43
|
+
"src/",
|
|
44
|
+
"templates/",
|
|
45
|
+
"config.schema.json",
|
|
46
|
+
"CHANGELOG.md"
|
|
47
|
+
],
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@changesets/cli": "^2.29.8",
|
|
50
|
+
"@types/bun": "^1.3.9"
|
|
51
|
+
}
|
|
11
52
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { ensureDb } from "../db.ts";
|
|
3
|
+
import { getIssueByPrefix } from "../queries/issues.ts";
|
|
4
|
+
import { createComment, listComments } from "../queries/comments.ts";
|
|
5
|
+
import { renderTable, formatDate, jsonOutput } from "../format.ts";
|
|
6
|
+
|
|
7
|
+
function parseArgs(args: string[]): { flags: Record<string, string | boolean>; positional: string[] } {
|
|
8
|
+
const flags: Record<string, string | boolean> = {};
|
|
9
|
+
const positional: string[] = [];
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < args.length; i++) {
|
|
12
|
+
const arg = args[i];
|
|
13
|
+
if (arg.startsWith("--")) {
|
|
14
|
+
const key = arg.slice(2);
|
|
15
|
+
if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
16
|
+
flags[key] = args[++i];
|
|
17
|
+
} else {
|
|
18
|
+
flags[key] = true;
|
|
19
|
+
}
|
|
20
|
+
} else if (arg.startsWith("-") && arg.length === 2) {
|
|
21
|
+
const key = arg.slice(1);
|
|
22
|
+
if (i + 1 < args.length && !args[i + 1].startsWith("-")) {
|
|
23
|
+
flags[key] = args[++i];
|
|
24
|
+
} else {
|
|
25
|
+
flags[key] = true;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
positional.push(arg);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { flags, positional };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function comment(args: string[], dbOverride?: Database): Promise<void> {
|
|
35
|
+
const { flags, positional } = parseArgs(args);
|
|
36
|
+
const issueIdOrPrefix = positional[0];
|
|
37
|
+
const body = positional.slice(1).join(" ");
|
|
38
|
+
|
|
39
|
+
if (!issueIdOrPrefix || !body) {
|
|
40
|
+
console.error("Usage: prodboard comment <issue-id> <body> [--author/-a author]");
|
|
41
|
+
throw new Error("Invalid arguments");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const db = dbOverride ?? ensureDb();
|
|
45
|
+
const issue = getIssueByPrefix(db, issueIdOrPrefix);
|
|
46
|
+
|
|
47
|
+
const author = (flags.author ?? flags.a) as string | undefined;
|
|
48
|
+
const c = createComment(db, {
|
|
49
|
+
issue_id: issue.id,
|
|
50
|
+
body,
|
|
51
|
+
author: typeof author === "string" ? author : undefined,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log(`Added comment by ${c.author} on issue ${issue.id}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function comments(args: string[], dbOverride?: Database): Promise<void> {
|
|
58
|
+
const { flags, positional } = parseArgs(args);
|
|
59
|
+
const issueIdOrPrefix = positional[0];
|
|
60
|
+
|
|
61
|
+
if (!issueIdOrPrefix) {
|
|
62
|
+
console.error("Usage: prodboard comments <issue-id> [--json]");
|
|
63
|
+
throw new Error("Invalid arguments");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const db = dbOverride ?? ensureDb();
|
|
67
|
+
const issue = getIssueByPrefix(db, issueIdOrPrefix);
|
|
68
|
+
const cmts = listComments(db, issue.id);
|
|
69
|
+
|
|
70
|
+
if (flags.json) {
|
|
71
|
+
console.log(jsonOutput(cmts));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (cmts.length === 0) {
|
|
76
|
+
console.log("No comments.");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const table = renderTable(
|
|
81
|
+
["Author", "Date", "Comment"],
|
|
82
|
+
cmts.map((c) => [c.author, formatDate(c.created_at), c.body]),
|
|
83
|
+
{ maxWidths: [12, 18, 60] }
|
|
84
|
+
);
|
|
85
|
+
console.log(table);
|
|
86
|
+
}
|