Add mandatory CLI standard - all web projects must have scripts/ folder
This commit is contained in:
parent
6ddac4a21c
commit
ef6cb4e116
74
MEMORY.md
74
MEMORY.md
@ -25,7 +25,42 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. NEVER CLOSE/MARK TASKS AS DONE — MATT DOES THIS
|
### 2. EVERY WEB PROJECT MUST HAVE CLI TOOLS IN scripts/ — MANDATORY
|
||||||
|
❌ **FORBIDDEN:** Creating a web app without programmatic CLI access
|
||||||
|
✅ **REQUIRED:** Every project gets `./scripts/` folder with CRUD + attachment capability
|
||||||
|
|
||||||
|
**The Rule - Non-Negotiable:**
|
||||||
|
```
|
||||||
|
/Users/mattbruce/Documents/Projects/OpenClaw/Web/{project-name}/
|
||||||
|
├── scripts/ # MUST EXIST
|
||||||
|
│ ├── crud.sh # MUST support: list, get, create, update, delete
|
||||||
|
│ ├── attach-file.sh # MUST support: attach files to items
|
||||||
|
│ └── .env.example # MUST document required env vars
|
||||||
|
```
|
||||||
|
|
||||||
|
**Implementation Pattern (Copy-Paste from Gantt Board):**
|
||||||
|
1. Copy `scripts/` from gantt-board: `cp -r /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts ./`
|
||||||
|
2. Update table names in scripts (e.g., `items` → `tasks` or `projects`)
|
||||||
|
3. Create `scripts/.env` with Supabase credentials
|
||||||
|
4. Test: `./scripts/crud.sh list` must return data
|
||||||
|
5. Commit: `git add scripts/ && git commit -m "Add CLI tools for AI access"`
|
||||||
|
6. Document: Add CLI section to README.md
|
||||||
|
|
||||||
|
**Why:** If I can't access it via CLI, I can't work on it when Matt's remote. Browser automation requiring clicks is UNACCEPTABLE.
|
||||||
|
|
||||||
|
**Project Readiness Checklist (BEFORE saying "project is ready"):**
|
||||||
|
- [ ] `./scripts/crud.sh` exists and is executable
|
||||||
|
- [ ] `./scripts/attach-file.sh` exists and is executable
|
||||||
|
- [ ] `./scripts/crud.sh list` returns data successfully
|
||||||
|
- [ ] `./scripts/.env` exists with working credentials
|
||||||
|
- [ ] CLI usage documented in README.md
|
||||||
|
- [ ] Scripts committed to git
|
||||||
|
|
||||||
|
**If any item unchecked → PROJECT IS NOT READY.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. NEVER CLOSE/MARK TASKS AS DONE — MATT DOES THIS
|
||||||
❌ **FORBIDDEN:** Changing task status to "done" or "complete"
|
❌ **FORBIDDEN:** Changing task status to "done" or "complete"
|
||||||
✅ **ALLOWED:** Attaching files, updating descriptions, adding comments
|
✅ **ALLOWED:** Attaching files, updating descriptions, adding comments
|
||||||
|
|
||||||
@ -173,31 +208,34 @@ First question: "How will I (Max) interact with this programmatically without Ma
|
|||||||
|
|
||||||
**✅ CORRECTLY PLACED:** These scripts are now in the gantt-board project repo and committed.
|
**✅ CORRECTLY PLACED:** These scripts are now in the gantt-board project repo and committed.
|
||||||
|
|
||||||
### Task CRUD
|
### Reference Implementation (Gantt Board)
|
||||||
|
|
||||||
|
**Source of truth for the pattern:**
|
||||||
|
- **Location:** `/Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts/`
|
||||||
|
- **Files:** `gantt-task-crud.sh`, `attach-file.sh`, `view-attachment.sh`
|
||||||
|
- **Usage:**
|
||||||
```bash
|
```bash
|
||||||
./scripts/gantt-task-crud.sh list [status] # List all tasks
|
./scripts/gantt-task-crud.sh list [status] # List all tasks
|
||||||
./scripts/gantt-task-crud.sh get <task-id> # Get specific task
|
./scripts/gantt-task-crud.sh get <task-id> # Get specific task
|
||||||
./scripts/gantt-task-crud.sh create "Title" [status] [priority] # Create task
|
./scripts/gantt-task-crud.sh create "Title" [status] [priority]
|
||||||
./scripts/gantt-task-crud.sh update <task-id> <field> <value> # Update task
|
./scripts/gantt-task-crud.sh update <task-id> <field> <value>
|
||||||
./scripts/gantt-task-crud.sh delete <task-id> # Delete task
|
./scripts/gantt-task-crud.sh delete <task-id>
|
||||||
|
./scripts/attach-file.sh <task-id> <file-path> # Attach file
|
||||||
|
./scripts/view-attachment.sh <task-id> [index] # View attachment
|
||||||
```
|
```
|
||||||
|
|
||||||
### File Attachments (NO BROWSER NEEDED)
|
**How it works:** Uses Supabase service role key directly. Files stored as base64 data URLs.
|
||||||
```bash
|
|
||||||
./scripts/attach-file.sh <task-id> <file-path> # Attach file to task
|
|
||||||
./scripts/view-attachment.sh <task-id> [index] # View attachment content
|
|
||||||
```
|
|
||||||
|
|
||||||
**How it works:** Uses Supabase service role key directly. Files stored as base64 data URLs in the attachments array. No storage bucket needed.
|
**To copy to new project:**
|
||||||
|
|
||||||
**Verification:**
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/gantt-task-crud.sh get <task-id> | jq '.attachments | length'
|
cp -r /Users/mattbruce/Documents/Projects/OpenClaw/Web/gantt-board/scripts \
|
||||||
|
/Users/mattbruce/Documents/Projects/OpenClaw/Web/{new-project}/
|
||||||
|
# Then update table names in the scripts
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## CLI/API Architecture Pattern (Apply to ALL Projects)
|
## CLI/API Implementation Guide (Reference for Rule #2)
|
||||||
|
|
||||||
**Every app I build MUST have programmatic access without browser automation.** This is non-negotiable.
|
**Every app I build MUST have programmatic access without browser automation.** This is non-negotiable.
|
||||||
|
|
||||||
@ -227,7 +265,7 @@ First question: "How will I (Max) interact with this programmatically without Ma
|
|||||||
- Project-specific logic stays with project
|
- Project-specific logic stays with project
|
||||||
- I can run `./scripts/crud.sh` from the project root
|
- I can run `./scripts/crud.sh` from the project root
|
||||||
|
|
||||||
**Exception:** Cross-project utilities (like git helpers) can live in workspace scripts, but app-specific CRUD must be in the app repo.
|
**NO EXCEPTIONS:** Every web project gets this. No excuses.
|
||||||
|
|
||||||
### Required Capabilities Checklist
|
### Required Capabilities Checklist
|
||||||
|
|
||||||
@ -450,12 +488,16 @@ task_id=$(./scripts/crud.sh create '{"title":"Test"}' | jq -r '.id')
|
|||||||
- [ ] API routes exist for CRUD operations
|
- [ ] API routes exist for CRUD operations
|
||||||
- [ ] CLI scripts created in `scripts/` directory
|
- [ ] CLI scripts created in `scripts/` directory
|
||||||
- [ ] API client module in `lib/api-client.ts`
|
- [ ] API client module in `lib/api-client.ts`
|
||||||
|
- [ ] `scripts/README.md` with usage docs (copy from `CLI_README_TEMPLATE.md`)
|
||||||
|
- [ ] `.env.example` documenting required env vars
|
||||||
- [ ] Test: Can I list items via CLI without browser?
|
- [ ] Test: Can I list items via CLI without browser?
|
||||||
- [ ] Test: Can I attach a file via CLI?
|
- [ ] Test: Can I attach a file via CLI?
|
||||||
- [ ] Test: Can I verify operations via CLI get?
|
- [ ] Test: Can I verify operations via CLI get?
|
||||||
|
|
||||||
**If any check fails → NOT READY.**
|
**If any check fails → NOT READY.**
|
||||||
|
|
||||||
|
**Template to copy:** `/Users/mattbruce/.openclaw/workspace/CLI_README_TEMPLATE.md`
|
||||||
|
|
||||||
## Quick Commands
|
## Quick Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
210
STANDARD_CLI_INTEGRATION.md
Normal file
210
STANDARD_CLI_INTEGRATION.md
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
# CLI Integration Standard
|
||||||
|
|
||||||
|
Standard for adding programmatic CLI access to all projects so AI agents can work without browser automation.
|
||||||
|
|
||||||
|
## Rule: CLI Tools Live INSIDE the Project
|
||||||
|
|
||||||
|
**Location:** `{project-root}/scripts/`
|
||||||
|
|
||||||
|
**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
|
||||||
|
|
||||||
|
## Required File Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
project-root/
|
||||||
|
├── 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Required CLI Commands
|
||||||
|
|
||||||
|
Every project MUST implement these:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 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
|
||||||
|
|
||||||
|
Each project's CLI needs these in `scripts/.env` (gitignored):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Supabase direct access (for bypassing auth)
|
||||||
|
SUPABASE_URL=https://xxxx.supabase.co
|
||||||
|
SUPABASE_SERVICE_ROLE_KEY=eyJ...
|
||||||
|
|
||||||
|
# Or API-based access
|
||||||
|
API_URL=http://localhost:3000/api
|
||||||
|
API_KEY=secret_key_for_cli_access
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supabase Direct Pattern (Recommended)
|
||||||
|
|
||||||
|
For Supabase projects, use direct DB access with service role key:
|
||||||
|
|
||||||
|
**File:** `scripts/crud.sh`
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Load env from scripts/.env
|
||||||
|
source "$(dirname "$0")/.env"
|
||||||
|
|
||||||
|
action=$1
|
||||||
|
shift
|
||||||
|
|
||||||
|
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 <id>|create <json>|update <id> <field> <value>|delete <id>}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
## File Attachment Pattern
|
||||||
|
|
||||||
|
**File:** `scripts/attach-file.sh`
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
source "$(dirname "$0")/.env"
|
||||||
|
|
||||||
|
ITEM_ID=$1
|
||||||
|
FILE_PATH=$2
|
||||||
|
|
||||||
|
if [ -z "$ITEM_ID" ] || [ -z "$FILE_PATH" ]; then
|
||||||
|
echo "Usage: $0 <item-id> <file-path>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
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
|
||||||
Loading…
Reference in New Issue
Block a user