feat: add project export and import functionality

- Implemented `pcli project export` command to export project hierarchy as JSON.
- Added `pcli project import` command to import project data from JSON.
- Created user client to fetch user details for comment attribution.
- Introduced new data structures for export and import processes.
- Ensured name-based references in exports and handled conflicts during imports.
- Added versioning and progress reporting for import operations.
- Updated documentation and specifications for new features.
This commit is contained in:
2026-03-04 19:53:55 +00:00
parent e352fd530f
commit e973b2ce20
49 changed files with 1492 additions and 3303 deletions
+54 -85
View File
@@ -1,6 +1,10 @@
---
name: kanban
name: planka-skill
description: Manage Planka project boards using the pcli CLI. Use when the user wants to interact with Planka boards, cards, lists, tasks, labels, or comments.
compatibility: Requires pcli binary in PATH and PLANKA_URL + PLANKA_API_KEY environment variables set
metadata:
author: steve-cliff
version: "1.0"
---
# pcli - Planka CLI
@@ -15,11 +19,11 @@ export PLANKA_URL="https://planka.example.com"
export PLANKA_API_KEY="your-api-key"
```
Ensure `jq` and `pcli` are installed and in the path.
Ensure `jq` is installed.
## Global Flags
All commands accept: `--format json|table`, `--url <url>`, `--api-key <key>`, `--log-level debug|info|warn|error`
All commands (apart from import/export) accept: `--format json|table`, `--url <url>`, `--api-key <key>`, `--log-level debug|info|warn|error`
## Commands
@@ -36,14 +40,38 @@ Returns summary of all boards, lists, and card counts (open/closed per list).
```bash
pcli project list
pcli project get <project-id>
pcli project create --name "Name" --type private # type: private or shared
pcli project delete <project-id>
# Export/Import
pcli project export <project-id-or-name> [--board <name-or-id>] > backup.json
pcli project import --file backup.json
pcli project import < backup.json
```
Export outputs a portable JSON file (names, not IDs). Import creates all resources with fresh IDs.
Import fails if the project+board name combination already exists on the target.
Comments are exported with `(Original comment by <username>)` prefix for attribution.
**Note:** Export outputs its own envelope format (`{version, exportedAt, project}`) directly — not the standard `{data, error}` envelope. Import progress and errors go to stderr.
### Boards
```bash
pcli board list
pcli board get <board-id> # includes lists and cards
pcli board actions <board-id> [--limit N]
pcli board create --project <project-id> --name "Board Name" [--position N]
pcli board delete <board-id>
```
### Lists (Board Columns)
```bash
pcli list create --board <board-id> --name "Column Name" [--type active|closed] [--position N]
pcli list get <list-id>
pcli list update <list-id> [--name "..."] [--type active|closed] [--color "..."] [--position N] [--board <board-id>]
pcli list delete <list-id>
```
### Cards
@@ -99,15 +127,6 @@ pcli task update <task-id> [--name "..."] [--position N] [--completed]
pcli task delete <task-id>
```
### Lists
```bash
pcli list create --board <board-id> --name "List Name" --position 65536 [--type active|closed]
pcli list get <list-id>
pcli list update <list-id> [--name "..."] [--position N] [--type active|closed] [--color "..."] [--board <board-id>]
pcli list delete <list-id>
```
### Labels
```bash
@@ -116,45 +135,6 @@ pcli label update <label-id> [--name "..."] [--color "..."] [--position N]
pcli label delete <label-id>
```
## API Response Structure
### Board Get Response
Board details include lists directly in `.data.lists[]`, not in an `included` section:
```bash
pcli board get <board-id> | jq '.data.lists[] | {id, name, position}'
```
### Card List Labels
Card list returns labels as **plain strings**, not objects:
```bash
# Labels are strings like "agent", NOT objects like {name: "agent"}
pcli card list --board <board-id> | jq '.data[] | select(.labels[]? == "agent")'
```
### Card Get Response
Card get includes `taskLists` and `tasks` arrays (when they exist):
```bash
pcli card get <card-id> | jq '.data.taskLists[0].id'
pcli card get <card-id> | jq '.data.tasks[] | {name, isCompleted}'
```
### Finding Boards in a Project
Use `board list --project` to find boards by project name:
```bash
pcli board list --project "<project-name>" | jq '.data[] | {id, name}'
```
## Error Handling
### Project Configuration
- Always strip quotes from yq output: `yq '.planka.project' project.yaml | tr -d '"'`
- Exit with error if configured project cannot be found or created
- The project name in project.yaml is the authoritative source
### Idempotent Operations
- Use `2>/dev/null || true` for create operations that should not fail if resources already exist
- Check for empty results before attempting operations: `if [ -z "$PROJECT_ID" ]; then`
## Extracting IDs from Output
All responses use `{"data": ..., "error": null}`. Extract IDs with jq:
@@ -165,48 +145,24 @@ pcli card create --list <id> --name "X" | jq -r '.data.id'
# Array
pcli card list --board <id> | jq -r '.data[].id'
# With error checking
RESULT=$(pcli project list | jq -r --arg name "$PROJECT_NAME" '.data[] | select(.name == $name) | .id')
if [ -z "$RESULT" ]; then
echo "Not found"
else
echo "Found: $RESULT"
fi
```
## Common Workflows
### Bootstrap Project Infrastructure
### Create a complete Kanban board
```bash
# Read project configuration
PROJECT_NAME=$(yq '.planka.project' project.yaml | tr -d '"')
BOARD_NAME=$(yq '.planka.board' project.yaml | tr -d '"')
# Create board
BOARD_ID=$(pcli board create --project <project-id> --name "Development Board" | jq -r '.data.id')
# Find or create project (exit with error if fails)
PROJECT_ID=$(pcli project list | jq -r --arg name "$PROJECT_NAME" '.data[] | select(.name == $name) | .id')
if [ -z "$PROJECT_ID" ]; then
echo "Error: Project '$PROJECT_NAME' not found and creation failed"
exit 1
fi
# Create columns
pcli list create --board $BOARD_ID --name "Backlog" --type "active" --position 0
TODO_ID=$(pcli list create --board $BOARD_ID --name "To Do" --type "active" --position 65536 | jq -r '.data.id')
PROGRESS_ID=$(pcli list create --board $BOARD_ID --name "In Progress" --type "active" --position 131072 | jq -r '.data.id')
DONE_ID=$(pcli list create --board $BOARD_ID --name "Done" --type "closed" --position 196608 | jq -r '.data.id')
# Find or create board
BOARD_ID=$(pcli board list --project "$PROJECT_NAME" | jq -r --arg name "$BOARD_NAME" '.data[] | select(.name == $name) | .id')
if [ -z "$BOARD_ID" ]; then
BOARD_ID=$(pcli board create --project $PROJECT_ID --name "$BOARD_NAME" | jq -r '.data.id')
fi
# Create required lists (skip if exists)
pcli list create --board $BOARD_ID --name "Backlog" --position 65536 2>/dev/null || true
pcli list create --board $BOARD_ID --name "To Do" --position 131072 2>/dev/null || true
pcli list create --board $BOARD_ID --name "Planning" --position 196608 2>/dev/null || true
pcli list create --board $BOARD_ID --name "In Progress" --position 262144 2>/dev/null || true
pcli list create --board $BOARD_ID --name "Review" --position 327680 2>/dev/null || true
pcli list create --board $BOARD_ID --name "Done" --position 393216 2>/dev/null || true
# Create agent label
pcli label create --board $BOARD_ID --name "agent" --color "berry-red" 2>/dev/null || true
# View the board
pcli board get $BOARD_ID --format table
```
### Create a card with a checklist
@@ -225,3 +181,16 @@ pcli card list --list <source-list-id> | jq -r '.data[].id' | while read id; do
pcli card move $id --list <target-list-id>
done
```
### Export and import a project
```bash
# Export entire project
pcli project export "My Project" > project-backup.json
# Export single board
pcli project export "My Project" --board "Sprint Board" > board-backup.json
# Import to another instance (or same instance if project+board combo doesn't exist)
pcli project import --file project-backup.json
```