Released v1

This commit is contained in:
Steve Cliff
2026-02-12 10:37:19 +00:00
commit b07572fed5
77 changed files with 19518 additions and 0 deletions
@@ -0,0 +1,133 @@
## 1. Project Scaffolding
- [x] 1.1 Initialize Go module (`go mod init github.com/dcgsteve/pcli`)
- [x] 1.2 Create directory structure: `cmd/`, `client/`, `model/`, `output/`, `logging/`
- [x] 1.3 Add Cobra dependency (`go get github.com/spf13/cobra`)
- [x] 1.4 Create `main.go` entry point that calls `cmd.Execute()`
## 2. Logging
- [x] 2.1 Implement `logging/logging.go``NewLogger(level string) *slog.Logger` that parses level string, creates JSON handler writing to stderr
## 3. Model Types
- [x] 3.1 Define `model/types.go` — Project, Board, List, Card, Comment, TaskList, Task, Label, Action, CardLabel, CardMembership structs with JSON tags and pointer types for nullable fields
- [x] 3.2 Define `Envelope` struct (`Data any`, `Error *string`) in `model/types.go`
- [x] 3.3 Define `APIError` struct (StatusCode int, Message string) implementing the `error` interface
## 4. Output Formatting
- [x] 4.1 Implement `output/output.go``Print(data any, format string, w io.Writer)` function that switches on format
- [x] 4.2 Implement JSON output mode — marshal `Envelope{Data: data, Error: nil}` to stdout
- [x] 4.3 Implement error output — `PrintError(err error, format string, w io.Writer)` that writes `Envelope{Data: nil, Error: msg}` for JSON, or error to stderr for table
- [x] 4.4 Implement table output mode — tabwriter-based rendering with per-resource column definitions
## 5. Base HTTP Client
- [x] 5.1 Implement `client/client.go``Client` struct with BaseURL, Token, HTTPClient, Logger fields
- [x] 5.2 Implement `NewClient(baseURL, token string, logger *slog.Logger) *Client`
- [x] 5.3 Implement `Do(ctx, method, path string, body any) (json.RawMessage, error)` — URL construction, bearer header, JSON marshal/unmarshal, DEBUG logging with method/path/status/duration
- [x] 5.4 Implement `APIError` handling — map 4xx/5xx responses to APIError, WARN logging on errors
- [x] 5.5 Implement `DoNoBody(ctx, method, path string) (json.RawMessage, error)` convenience method for GET/DELETE
## 6. Root Command and Global Flags
- [x] 6.1 Implement `cmd/root.go` — root Cobra command with `--format`, `--url`, `--token`, `--log-level` persistent flags
- [x] 6.2 Implement `PersistentPreRunE` — resolve URL/token from flags or env vars (flag > env), validate both present, initialize logger, create client instance
- [x] 6.3 Wire output format into a shared variable accessible by all subcommands
## 7. Client — Project Operations
- [x] 7.1 Implement `client/projects.go``ListProjects(ctx) ([]model.Project, error)`
- [x] 7.2 Implement `GetProject(ctx, id string) (*model.Project, error)`
## 8. Client — Board Operations
- [x] 8.1 Implement `client/boards.go``GetBoard(ctx, id string) (*model.Board, error)`
- [x] 8.2 Implement `ListBoardActions(ctx, boardId string, limit int) ([]model.Action, error)` with cursor-based pagination using `beforeId`
## 9. Client — Card Operations
- [x] 9.1 Implement `client/cards.go``GetCard(ctx, id string) (*model.Card, error)`
- [x] 9.2 Implement `CreateCard(ctx, listId string, fields) (*model.Card, error)`
- [x] 9.3 Implement `UpdateCard(ctx, id string, fields) (*model.Card, error)`
- [x] 9.4 Implement `DeleteCard(ctx, id string) error`
- [x] 9.5 Implement `DuplicateCard(ctx, id string, name *string, position *float64) (*model.Card, error)`
- [x] 9.6 Implement `ListCards(ctx, listId string, limit int) ([]model.Card, error)` with cursor-based pagination using `before`
- [x] 9.7 Implement `ListCardActions(ctx, cardId string, limit int) ([]model.Action, error)` with cursor-based pagination using `beforeId`
- [x] 9.8 Implement `ListCardsByBoard(ctx, boardId string, limit int) ([]model.CardWithList, error)` — multi-call enrichment: get board → get cards per list → inject listName
- [x] 9.9 Implement `AddCardLabel(ctx, cardId, labelId string) error`
- [x] 9.10 Implement `RemoveCardLabel(ctx, cardId, labelId string) error`
- [x] 9.11 Implement `AddCardMember(ctx, cardId, userId string) error`
- [x] 9.12 Implement `RemoveCardMember(ctx, cardId, userId string) error`
## 10. Client — Comment Operations
- [x] 10.1 Implement `client/comments.go``ListComments(ctx, cardId string, limit int) ([]model.Comment, error)` with cursor-based pagination using `beforeId`
- [x] 10.2 Implement `CreateComment(ctx, cardId, text string) (*model.Comment, error)`
- [x] 10.3 Implement `UpdateComment(ctx, id, text string) (*model.Comment, error)`
- [x] 10.4 Implement `DeleteComment(ctx, id string) error`
## 11. Client — Task List Operations
- [x] 11.1 Implement `client/task_lists.go``CreateTaskList(ctx, cardId string, fields) (*model.TaskList, error)`
- [x] 11.2 Implement `GetTaskList(ctx, id string) (*model.TaskList, error)`
- [x] 11.3 Implement `UpdateTaskList(ctx, id string, fields) (*model.TaskList, error)`
- [x] 11.4 Implement `DeleteTaskList(ctx, id string) error`
## 12. Client — Task Operations
- [x] 12.1 Implement `client/tasks.go``CreateTask(ctx, taskListId string, fields) (*model.Task, error)`
- [x] 12.2 Implement `UpdateTask(ctx, id string, fields) (*model.Task, error)`
- [x] 12.3 Implement `DeleteTask(ctx, id string) error`
## 13. Client — Label Operations
- [x] 13.1 Implement `client/labels.go``CreateLabel(ctx, boardId string, fields) (*model.Label, error)`
- [x] 13.2 Implement `UpdateLabel(ctx, id string, fields) (*model.Label, error)`
- [x] 13.3 Implement `DeleteLabel(ctx, id string) error`
## 14. CLI — Project Commands
- [x] 14.1 Implement `cmd/project.go``project` parent command, `project list` subcommand, `project get <id>` subcommand
## 15. CLI — Board Commands
- [x] 15.1 Implement `cmd/board.go``board` parent command, `board get <id>` subcommand, `board actions <id>` subcommand with `--limit` flag
## 16. CLI — Card Commands
- [x] 16.1 Implement `cmd/card.go``card` parent command
- [x] 16.2 Implement `card list` subcommand with mutually required `--board` / `--list` flags and `--limit`
- [x] 16.3 Implement `card get <id>` subcommand
- [x] 16.4 Implement `card create` subcommand with `--list`, `--name` (required), `--description`, `--type`, `--position`, `--due-date`, `--due-completed` flags
- [x] 16.5 Implement `card update <id>` subcommand with optional update flags
- [x] 16.6 Implement `card delete <id>` subcommand
- [x] 16.7 Implement `card duplicate <id>` subcommand with optional `--name`, `--position`
- [x] 16.8 Implement `card move <id>` subcommand with required `--list` and optional `--position`
- [x] 16.9 Implement `card assign <id>` and `card unassign <id>` subcommands with required `--user`
- [x] 16.10 Implement `card add-label <id>` and `card remove-label <id>` subcommands with required `--label`
- [x] 16.11 Implement `card actions <id>` subcommand with `--limit`
## 17. CLI — Comment Commands
- [x] 17.1 Implement `cmd/comment.go``comment` parent command, `comment list` with `--card` and `--limit`, `comment create` with `--card` and `--text`, `comment update <id>` with `--text`, `comment delete <id>`
## 18. CLI — Task List Commands
- [x] 18.1 Implement `cmd/task_list.go``task-list` parent command, `task-list create` with `--card`, `--name`, optional flags, `task-list get <id>`, `task-list update <id>`, `task-list delete <id>`
## 19. CLI — Task Commands
- [x] 19.1 Implement `cmd/task.go``task` parent command, `task create` with `--task-list`, `--name`, optional flags, `task update <id>` with optional flags, `task delete <id>`
## 20. CLI — Label Commands
- [x] 20.1 Implement `cmd/label.go``label` parent command, `label create` with `--board`, `--name`, optional `--color`, `--position`, `label update <id>`, `label delete <id>`
## 21. Build and Verify
- [x] 21.1 Verify `go build` produces a clean binary
- [x] 21.2 Verify `pcli --help` displays all commands and global flags
- [x] 21.3 Verify error output when `PLANKA_URL` / `PLANKA_TOKEN` are missing
- [x] 21.4 Add README.md with installation, configuration, and usage examples