Signed-off-by: Max <ai-agent@topdoglabs.com>

This commit is contained in:
Max 2026-02-24 17:55:38 -06:00
parent 8a828e72c8
commit 8d6a108aa2
2 changed files with 91 additions and 193 deletions

View File

@ -1,210 +1,90 @@
# CLI Integration Standard # CLI Integration Standard (API Passthrough)
Standard for adding programmatic CLI access to all projects so AI agents can work without browser automation. Standard for exposing reliable CLI access to a web app without duplicating business logic.
## Rule: CLI Tools Live INSIDE the Project ## Core rule
**Location:** `{project-root}/scripts/` - API/server is the single source of truth for domain logic.
- CLI is a client of that API.
- CLI must not call the database directly.
**Why:** If behavior is missing for CLI, add endpoint/service logic in API first, then call it from CLI.
- Version controlled with the project
- Self-documenting (API + CLI in same repo)
- Portable (clone repo, CLI works immediately)
- Project-specific logic stays with project
- No hunting around workspace folders
## Required File Structure ## Required project structure
``` ```text
project-root/ project-root/
├── src/app/api/... # API routes
├── src/lib/server/... # business/domain logic
├── scripts/ ├── scripts/
│ ├── crud.sh # Main CRUD operations │ ├── lib/
│ ├── attach-file.sh # File attachments │ │ └── api_client.sh # shared transport helper
│ ├── README.md # Usage documentation │ ├── <resource>.sh # task/project/sprint style command groups
│ └── .env.example # Required environment variables │ ├── <wrapper>.sh # optional umbrella script
├── api/ # REST API routes (used by CLI) │ ├── README.md # command docs
│ └── items/ │ └── tests/
│ ├── route.ts │ ├── *.test.ts # unit tests for shared logic
│ └── [id]/ │ └── *.sh # mocked CLI contract tests
│ ├── route.ts └── README.md
│ └── attachments/
│ └── route.ts
└── README.md # Project README with CLI section
``` ```
## Required CLI Commands ## CLI responsibilities
Every project MUST implement these: - Parse args and flags.
- Resolve user-friendly names to IDs (via API calls).
- Call API endpoints.
- Format output and errors.
```bash Do not implement:
# From project root:
./scripts/crud.sh list [filters] # List all items
./scripts/crud.sh get <id> # Get single item
./scripts/crud.sh create <json> # Create item
./scripts/crud.sh update <id> <field> <value> # Update field
./scripts/crud.sh delete <id> # Delete item
./scripts/attach-file.sh <id> <path> # Attach file to item
```
## Environment Variables - status/sprint/date/business transition logic
- server-side validation rules
- persistence logic
- auth policy logic
Each project's CLI needs these in `scripts/.env` (gitignored): ## Configuration
```bash Preferred runtime variables:
# Supabase direct access (for bypassing auth)
SUPABASE_URL=https://xxxx.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
# Or API-based access - `API_URL` (for example `http://localhost:3000/api`)
API_URL=http://localhost:3000/api - `GANTT_COOKIE_FILE` (or equivalent session cookie path)
API_KEY=secret_key_for_cli_access
```
## Supabase Direct Pattern (Recommended) Do not require service-role DB keys in CLI scripts.
For Supabase projects, use direct DB access with service role key: ## Testing requirements
**File:** `scripts/crud.sh` Every CLI-enabled project must include:
```bash
#!/bin/bash
set -e
# Load env from scripts/.env 1. API/domain unit tests
source "$(dirname "$0")/.env" 2. API route/integration tests
3. CLI contract tests with mocked transport
action=$1 ## CLI contract mock pattern
shift
case $action in For shell CLIs:
list)
curl -s "${SUPABASE_URL}/rest/v1/items?select=*" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.'
;;
get)
id=$1
curl -s "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.[0]'
;;
create)
data=$1
curl -s -X POST "${SUPABASE_URL}/rest/v1/items" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Content-Type: application/json" \
-d "$data" | jq '.'
;;
update)
id=$1
field=$2
value=$3
curl -s -X PATCH "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Content-Type: application/json" \
-d "{\"${field}\": \"${value}\"}" | jq '.'
;;
delete)
id=$1
curl -s -X DELETE "${SUPABASE_URL}/rest/v1/items?id=eq.${id}" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}"
echo "Deleted ${id}"
;;
*)
echo "Usage: $0 {list|get <id>|create <json>|update <id> <field> <value>|delete <id>}"
exit 1
;;
esac
```
## File Attachment Pattern - mock `curl` via `PATH` override
- log `METHOD URL PAYLOAD`
- return fixture JSON + HTTP codes
- fail on unhandled endpoint calls
- assert expected endpoint calls were made
**File:** `scripts/attach-file.sh` Also assert no direct DB references remain in `scripts/` (for example `rest/v1`, service keys).
```bash
#!/bin/bash
set -e
source "$(dirname "$0")/.env" ## Verification checklist
ITEM_ID=$1 - [ ] CLI scripts only call API
FILE_PATH=$2 - [ ] No direct DB credentials/queries in CLI
- [ ] Missing CLI behavior added to API first
- [ ] Tests added/updated (unit + mocked contract)
- [ ] Refactor suite runs in CI
- [ ] `scripts/README.md` and root `README.md` are updated
if [ -z "$ITEM_ID" ] || [ -z "$FILE_PATH" ]; then ## Migration guide (direct DB CLI -> API passthrough CLI)
echo "Usage: $0 <item-id> <file-path>"
exit 1
fi
if [ ! -f "$FILE_PATH" ]; then 1. Inventory commands and duplicated logic.
echo "Error: File not found: $FILE_PATH" 2. Implement needed behavior in API/server modules.
exit 1 3. Replace CLI DB calls with `api_call` helper.
fi 4. Add mocked contract tests that cover all command families.
5. Remove old DB code and env vars from scripts.
# Read and encode file 6. Update docs and CI gates.
mime=$(file -b --mime-type "$FILE_PATH")
base64=$(base64 -i "$FILE_PATH")
filename=$(basename "$FILE_PATH")
size=$(stat -f%z "$FILE_PATH" 2>/dev/null || stat -c%s "$FILE_PATH")
# Build attachment JSON
attachment=$(jq -n \
--arg id "$(uuidgen | tr '[:upper:]' '[:lower:]')" \
--arg name "$filename" \
--arg type "$mime" \
--arg data "data:${mime};base64,${base64}" \
--argjson size "$size" \
'{id: $id, name: $name, type: $type, dataUrl: $data, size: $size}')
# Get current attachments, append new one
current=$(curl -s "${SUPABASE_URL}/rest/v1/items?id=eq.${ITEM_ID}&select=attachments" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" | jq '.[0].attachments // []')
updated=$(echo "$current" | jq ". + [$attachment]")
# Update item
curl -s -X PATCH "${SUPABASE_URL}/rest/v1/items?id=eq.${ITEM_ID}" \
-H "apikey: ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Authorization: Bearer ${SUPABASE_SERVICE_ROLE_KEY}" \
-H "Content-Type: application/json" \
-d "{\"attachments\": $updated}" | jq '.'
echo "✅ Attached ${filename} (${size} bytes) to item ${ITEM_ID}"
```
## Per-Project Reference
### Gantt Board
- **Location:** `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/`
- **Scripts:** `gantt-task-crud.sh`, `attach-file.sh`, `view-attachment.sh`
- **Auth:** Supabase service role key
- **Table:** `public.tasks`
### Adding CLI to a New Project
1. Create `scripts/` directory in project root
2. Copy template scripts from gantt-board
3. Update table names and fields for your project
4. Create `scripts/.env` with Supabase credentials
5. Test: `./scripts/crud.sh list`
6. Commit to git: `git add scripts/ && git commit -m "Add CLI tools for AI access"`
7. Update project's README.md with CLI usage section
## Agent Instructions
When working on a project:
1. Check for `scripts/` directory in project root
2. If CLI exists, use it: `./scripts/crud.sh list`
3. If CLI doesn't exist, create it using patterns above
4. NEVER create files in workspace scripts folder for project-specific tools
## Verification Checklist
Before saying a task is done:
- [ ] CLI tools are in `{project}/scripts/`, NOT workspace
- [ ] Scripts are executable (`chmod +x`)
- [ ] `.env` file exists with credentials (gitignored)
- [ ] Scripts work: `./scripts/crud.sh list` returns data
- [ ] Changes are committed to git
- [ ] Project README documents CLI usage

View File

@ -35,6 +35,14 @@ Task and sprint board built with Next.js + Zustand and Supabase-backed API persi
- Task detail now includes explicit Project + Sprint selection; selecting a sprint auto-aligns `projectId`. - Task detail now includes explicit Project + Sprint selection; selecting a sprint auto-aligns `projectId`.
- API validation now accepts UUID-shaped IDs used by existing data and returns clearer error payloads for failed writes. - API validation now accepts UUID-shaped IDs used by existing data and returns clearer error payloads for failed writes.
### Feb 24, 2026 updates
- Standardized CLI tools to API passthrough mode only (no direct DB logic in scripts).
- Consolidated shared CLI transport into `scripts/lib/api_client.sh`.
- Added refactor safety tests:
- sprint selection unit tests
- mocked CLI API-contract tests across task/project/sprint/auth/debug command paths
### Sprint date semantics (important) ### Sprint date semantics (important)
- Sprint dates are treated as local calendar-day boundaries: - Sprint dates are treated as local calendar-day boundaries:
@ -254,21 +262,31 @@ npm run lint
Located in `scripts/` directory. These allow programmatic access without browser automation. Located in `scripts/` directory. These allow programmatic access without browser automation.
```bash ```bash
# Task CRUD # Full wrapper
./scripts/gantt-task-crud.sh list [status] # List all tasks ./scripts/gantt.sh task list open
./scripts/gantt-task-crud.sh get <task-id> # Get specific task ./scripts/gantt.sh task create "Fix login issue" todo high p1
./scripts/gantt-task-crud.sh create "Title" [status] [priority] [project-id] [assignee-id] ./scripts/gantt.sh sprint close <sprint-id>
./scripts/gantt-task-crud.sh update <task-id> <field> <value> ./scripts/gantt.sh auth session
./scripts/gantt-task-crud.sh delete <task-id>
# File Attachments # Focused helpers
./scripts/attach-file.sh <task-id> <file-path> # Attach file to task ./scripts/task.sh list --json
./scripts/view-attachment.sh <task-id> [index] # View attachment content ./scripts/project.sh list --json
./scripts/sprint.sh list --active --json
./scripts/attach-file.sh <task-id> <file-path>
./scripts/view-attachment.sh <task-id> [index]
``` ```
**Requires:** `scripts/.env` with `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` **Architecture:** CLI is API passthrough only. Business logic lives in API/server code.
See: `STANDARD_CLI_INTEGRATION.md` in workspace for full pattern. **Docs:**
- `scripts/README.md` (command details and env vars)
- `docs/API_CLI_PASSTHROUGH_PATTERN.md` (refactor/architecture standard)
**Refactor test suite:**
```bash
npm run test:refactor
```
## Notes ## Notes