From 8d6a108aa2c398ca7192774aa2012b059a5a44b6 Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 24 Feb 2026 17:55:38 -0600 Subject: [PATCH] Signed-off-by: Max --- CLI_STANDARD.md | 244 ++++++++++++------------------------------------ README.md | 40 +++++--- 2 files changed, 91 insertions(+), 193 deletions(-) diff --git a/CLI_STANDARD.md b/CLI_STANDARD.md index 1ddb330..ecffae9 100644 --- a/CLI_STANDARD.md +++ b/CLI_STANDARD.md @@ -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:** -- 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 +If behavior is missing for CLI, add endpoint/service logic in API first, then call it from CLI. -## Required File Structure +## Required project structure -``` +```text project-root/ +├── src/app/api/... # API routes +├── src/lib/server/... # business/domain logic ├── scripts/ -│ ├── crud.sh # Main CRUD operations -│ ├── attach-file.sh # File attachments -│ ├── README.md # Usage documentation -│ └── .env.example # Required environment variables -├── api/ # REST API routes (used by CLI) -│ └── items/ -│ ├── route.ts -│ └── [id]/ -│ ├── route.ts -│ └── attachments/ -│ └── route.ts -└── README.md # Project README with CLI section +│ ├── lib/ +│ │ └── api_client.sh # shared transport helper +│ ├── .sh # task/project/sprint style command groups +│ ├── .sh # optional umbrella script +│ ├── README.md # command docs +│ └── tests/ +│ ├── *.test.ts # unit tests for shared logic +│ └── *.sh # mocked CLI contract tests +└── README.md ``` -## 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 -# From project root: -./scripts/crud.sh list [filters] # List all items -./scripts/crud.sh get # Get single item -./scripts/crud.sh create # Create item -./scripts/crud.sh update # Update field -./scripts/crud.sh delete # Delete item -./scripts/attach-file.sh # Attach file to item -``` +Do not implement: -## 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 -# Supabase direct access (for bypassing auth) -SUPABASE_URL=https://xxxx.supabase.co -SUPABASE_SERVICE_ROLE_KEY=eyJ... +Preferred runtime variables: -# Or API-based access -API_URL=http://localhost:3000/api -API_KEY=secret_key_for_cli_access -``` +- `API_URL` (for example `http://localhost:3000/api`) +- `GANTT_COOKIE_FILE` (or equivalent session cookie path) -## 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` -```bash -#!/bin/bash -set -e +Every CLI-enabled project must include: -# Load env from scripts/.env -source "$(dirname "$0")/.env" +1. API/domain unit tests +2. API route/integration tests +3. CLI contract tests with mocked transport -action=$1 -shift +## CLI contract mock pattern -case $action in - 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 |create |update |delete }" - exit 1 - ;; -esac -``` +For shell CLIs: -## 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` -```bash -#!/bin/bash -set -e +Also assert no direct DB references remain in `scripts/` (for example `rest/v1`, service keys). -source "$(dirname "$0")/.env" +## Verification checklist -ITEM_ID=$1 -FILE_PATH=$2 +- [ ] CLI scripts only call API +- [ ] 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 - echo "Usage: $0 " - exit 1 -fi +## Migration guide (direct DB CLI -> API passthrough CLI) -if [ ! -f "$FILE_PATH" ]; then - echo "Error: File not found: $FILE_PATH" - exit 1 -fi - -# Read and encode file -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 +1. Inventory commands and duplicated logic. +2. Implement needed behavior in API/server modules. +3. Replace CLI DB calls with `api_call` helper. +4. Add mocked contract tests that cover all command families. +5. Remove old DB code and env vars from scripts. +6. Update docs and CI gates. diff --git a/README.md b/README.md index 098acab..3fd006b 100644 --- a/README.md +++ b/README.md @@ -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`. - 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 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. ```bash -# Task CRUD -./scripts/gantt-task-crud.sh list [status] # List all tasks -./scripts/gantt-task-crud.sh get # Get specific task -./scripts/gantt-task-crud.sh create "Title" [status] [priority] [project-id] [assignee-id] -./scripts/gantt-task-crud.sh update -./scripts/gantt-task-crud.sh delete +# Full wrapper +./scripts/gantt.sh task list open +./scripts/gantt.sh task create "Fix login issue" todo high p1 +./scripts/gantt.sh sprint close +./scripts/gantt.sh auth session -# File Attachments -./scripts/attach-file.sh # Attach file to task -./scripts/view-attachment.sh [index] # View attachment content +# Focused helpers +./scripts/task.sh list --json +./scripts/project.sh list --json +./scripts/sprint.sh list --active --json +./scripts/attach-file.sh +./scripts/view-attachment.sh [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