loki-mode 6.13.0 → 6.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +221 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/templates/api-only.md +86 -28
- package/templates/e-commerce.md +1 -1
- package/templates/full-stack-demo.md +69 -30
- package/templates/simple-todo-app.md +108 -20
package/README.md
CHANGED
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with minimal human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v6.
|
|
6
|
+
# Loki Mode v6.14.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -267,4 +267,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
267
267
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
268
268
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
269
269
|
|
|
270
|
-
**v6.
|
|
270
|
+
**v6.14.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.14.0
|
package/autonomy/loki
CHANGED
|
@@ -419,6 +419,7 @@ show_help() {
|
|
|
419
419
|
echo " checkpoint|cp Save/restore session checkpoints"
|
|
420
420
|
echo " projects Multi-project registry management"
|
|
421
421
|
echo " audit [cmd] Agent audit log and quality scanning (log|scan)"
|
|
422
|
+
echo " review [dir] Run quality gates on any project (standalone, no AI needed)"
|
|
422
423
|
echo " optimize Optimize prompts based on session history"
|
|
423
424
|
echo " enterprise Enterprise feature management (tokens, OIDC)"
|
|
424
425
|
echo " metrics Prometheus/OpenMetrics metrics from dashboard"
|
|
@@ -7848,6 +7849,9 @@ main() {
|
|
|
7848
7849
|
audit)
|
|
7849
7850
|
cmd_audit "$@"
|
|
7850
7851
|
;;
|
|
7852
|
+
review)
|
|
7853
|
+
cmd_review "$@"
|
|
7854
|
+
;;
|
|
7851
7855
|
optimize)
|
|
7852
7856
|
cmd_optimize "$@"
|
|
7853
7857
|
;;
|
|
@@ -7895,6 +7899,223 @@ main() {
|
|
|
7895
7899
|
esac
|
|
7896
7900
|
}
|
|
7897
7901
|
|
|
7902
|
+
# Standalone project review - run quality gates on any codebase (v6.14.0)
|
|
7903
|
+
cmd_review() {
|
|
7904
|
+
local target_dir="."
|
|
7905
|
+
local json_output=""
|
|
7906
|
+
local verbose=""
|
|
7907
|
+
|
|
7908
|
+
while [[ $# -gt 0 ]]; do
|
|
7909
|
+
case "$1" in
|
|
7910
|
+
--json) json_output="true"; shift ;;
|
|
7911
|
+
--verbose|-v) verbose="true"; shift ;;
|
|
7912
|
+
--help|-h)
|
|
7913
|
+
echo -e "${BOLD}loki review${NC} - Run quality gates on any project (standalone)"
|
|
7914
|
+
echo ""
|
|
7915
|
+
echo "Usage: loki review [directory] [options]"
|
|
7916
|
+
echo ""
|
|
7917
|
+
echo "Arguments:"
|
|
7918
|
+
echo " directory Path to project (default: current directory)"
|
|
7919
|
+
echo ""
|
|
7920
|
+
echo "Options:"
|
|
7921
|
+
echo " --json Machine-readable JSON output"
|
|
7922
|
+
echo " --verbose, -v Show detailed output per gate"
|
|
7923
|
+
echo " --help, -h Show this help"
|
|
7924
|
+
echo ""
|
|
7925
|
+
echo "Gates: project-type, lint, tests, security, dependencies, structure"
|
|
7926
|
+
echo "Exit code: 0 if all pass, 1 if any fail"
|
|
7927
|
+
return 0
|
|
7928
|
+
;;
|
|
7929
|
+
-*) echo -e "${RED}Unknown option: $1${NC}"; return 1 ;;
|
|
7930
|
+
*) target_dir="$1"; shift ;;
|
|
7931
|
+
esac
|
|
7932
|
+
done
|
|
7933
|
+
|
|
7934
|
+
# Resolve and validate directory
|
|
7935
|
+
target_dir="$(cd "$target_dir" 2>/dev/null && pwd)" || {
|
|
7936
|
+
echo -e "${RED}Error: Directory not found: $target_dir${NC}"; return 1
|
|
7937
|
+
}
|
|
7938
|
+
|
|
7939
|
+
local project_type="unknown"
|
|
7940
|
+
local results=() # gate:status pairs
|
|
7941
|
+
local total_pass=0 total_warn=0 total_fail=0
|
|
7942
|
+
local gate_details=()
|
|
7943
|
+
|
|
7944
|
+
# Helper: record gate result
|
|
7945
|
+
_review_gate() {
|
|
7946
|
+
local gate="$1" status="$2" detail="${3:-}"
|
|
7947
|
+
results+=("$gate:$status")
|
|
7948
|
+
gate_details+=("$gate:$detail")
|
|
7949
|
+
case "$status" in
|
|
7950
|
+
PASS) total_pass=$((total_pass + 1)) ;;
|
|
7951
|
+
WARN) total_warn=$((total_warn + 1)) ;;
|
|
7952
|
+
FAIL) total_fail=$((total_fail + 1)) ;;
|
|
7953
|
+
esac
|
|
7954
|
+
}
|
|
7955
|
+
|
|
7956
|
+
# Gate 1: Detect project type
|
|
7957
|
+
if [ -f "$target_dir/package.json" ]; then
|
|
7958
|
+
project_type="node"
|
|
7959
|
+
elif [ -f "$target_dir/pyproject.toml" ] || [ -f "$target_dir/setup.py" ] || [ -f "$target_dir/requirements.txt" ]; then
|
|
7960
|
+
project_type="python"
|
|
7961
|
+
elif [ -f "$target_dir/go.mod" ]; then
|
|
7962
|
+
project_type="go"
|
|
7963
|
+
elif [ -f "$target_dir/Cargo.toml" ]; then
|
|
7964
|
+
project_type="rust"
|
|
7965
|
+
fi
|
|
7966
|
+
if [ "$project_type" != "unknown" ]; then
|
|
7967
|
+
_review_gate "project-type" "PASS" "Detected: $project_type"
|
|
7968
|
+
else
|
|
7969
|
+
_review_gate "project-type" "WARN" "Could not detect project type"
|
|
7970
|
+
fi
|
|
7971
|
+
|
|
7972
|
+
# Gate 2: Lint check
|
|
7973
|
+
local lint_output="" lint_status="PASS"
|
|
7974
|
+
case "$project_type" in
|
|
7975
|
+
node)
|
|
7976
|
+
if [ -f "$target_dir/.eslintrc.js" ] || [ -f "$target_dir/.eslintrc.json" ] || [ -f "$target_dir/.eslintrc.yml" ] || [ -f "$target_dir/eslint.config.js" ] || [ -f "$target_dir/eslint.config.mjs" ]; then
|
|
7977
|
+
lint_output=$(cd "$target_dir" && npx eslint . --max-warnings=0 2>&1) || lint_status="FAIL"
|
|
7978
|
+
else
|
|
7979
|
+
lint_output="No ESLint config found"; lint_status="WARN"
|
|
7980
|
+
fi ;;
|
|
7981
|
+
python)
|
|
7982
|
+
if command -v ruff &>/dev/null; then
|
|
7983
|
+
lint_output=$(cd "$target_dir" && ruff check . 2>&1) || lint_status="FAIL"
|
|
7984
|
+
elif command -v pylint &>/dev/null; then
|
|
7985
|
+
lint_output=$(cd "$target_dir" && pylint --recursive=y . 2>&1) || lint_status="FAIL"
|
|
7986
|
+
else
|
|
7987
|
+
lint_output="No linter available (install ruff or pylint)"; lint_status="WARN"
|
|
7988
|
+
fi ;;
|
|
7989
|
+
go)
|
|
7990
|
+
if command -v golangci-lint &>/dev/null; then
|
|
7991
|
+
lint_output=$(cd "$target_dir" && golangci-lint run 2>&1) || lint_status="FAIL"
|
|
7992
|
+
else
|
|
7993
|
+
lint_output=$(cd "$target_dir" && go vet ./... 2>&1) || lint_status="FAIL"
|
|
7994
|
+
fi ;;
|
|
7995
|
+
rust)
|
|
7996
|
+
lint_output=$(cd "$target_dir" && cargo clippy -- -D warnings 2>&1) || lint_status="FAIL"
|
|
7997
|
+
;;
|
|
7998
|
+
*) lint_output="Skipped (unknown project type)"; lint_status="WARN" ;;
|
|
7999
|
+
esac
|
|
8000
|
+
_review_gate "lint" "$lint_status" "$lint_output"
|
|
8001
|
+
|
|
8002
|
+
# Gate 3: Tests
|
|
8003
|
+
local test_output="" test_status="PASS"
|
|
8004
|
+
case "$project_type" in
|
|
8005
|
+
node)
|
|
8006
|
+
if grep -q '"test"' "$target_dir/package.json" 2>/dev/null; then
|
|
8007
|
+
test_output=$(cd "$target_dir" && npm test 2>&1) || test_status="FAIL"
|
|
8008
|
+
else
|
|
8009
|
+
test_output="No test script in package.json"; test_status="WARN"
|
|
8010
|
+
fi ;;
|
|
8011
|
+
python)
|
|
8012
|
+
if command -v pytest &>/dev/null; then
|
|
8013
|
+
test_output=$(cd "$target_dir" && pytest --tb=short 2>&1) || test_status="FAIL"
|
|
8014
|
+
else
|
|
8015
|
+
test_output="pytest not available"; test_status="WARN"
|
|
8016
|
+
fi ;;
|
|
8017
|
+
go) test_output=$(cd "$target_dir" && go test ./... 2>&1) || test_status="FAIL" ;;
|
|
8018
|
+
rust) test_output=$(cd "$target_dir" && cargo test 2>&1) || test_status="FAIL" ;;
|
|
8019
|
+
*) test_output="Skipped (unknown project type)"; test_status="WARN" ;;
|
|
8020
|
+
esac
|
|
8021
|
+
_review_gate "tests" "$test_status" "$test_output"
|
|
8022
|
+
|
|
8023
|
+
# Gate 4: Security - grep for hardcoded secrets
|
|
8024
|
+
local secret_output="" secret_status="PASS"
|
|
8025
|
+
local secret_patterns='(API_KEY|SECRET_KEY|PASSWORD|TOKEN|PRIVATE_KEY)\s*[=:]\s*["\x27][A-Za-z0-9+/=_-]{8,}'
|
|
8026
|
+
secret_output=$(grep -rEn "$secret_patterns" "$target_dir" \
|
|
8027
|
+
--include="*.js" --include="*.ts" --include="*.py" --include="*.go" --include="*.rs" \
|
|
8028
|
+
--include="*.jsx" --include="*.tsx" --include="*.java" --include="*.rb" \
|
|
8029
|
+
--exclude-dir=node_modules --exclude-dir=.git --exclude-dir=vendor \
|
|
8030
|
+
--exclude-dir=__pycache__ --exclude-dir=.venv --exclude-dir=target 2>/dev/null) || true
|
|
8031
|
+
if [ -n "$secret_output" ]; then
|
|
8032
|
+
secret_status="FAIL"
|
|
8033
|
+
secret_output="Potential hardcoded secrets found:
|
|
8034
|
+
$secret_output"
|
|
8035
|
+
else
|
|
8036
|
+
secret_output="No hardcoded secrets detected"
|
|
8037
|
+
fi
|
|
8038
|
+
_review_gate "security" "$secret_status" "$secret_output"
|
|
8039
|
+
|
|
8040
|
+
# Gate 5: Dependency audit
|
|
8041
|
+
local dep_output="" dep_status="PASS"
|
|
8042
|
+
case "$project_type" in
|
|
8043
|
+
node)
|
|
8044
|
+
if [ -f "$target_dir/package-lock.json" ] || [ -f "$target_dir/yarn.lock" ]; then
|
|
8045
|
+
dep_output=$(cd "$target_dir" && npm audit --production 2>&1) || dep_status="WARN"
|
|
8046
|
+
else
|
|
8047
|
+
dep_output="No lockfile found"; dep_status="WARN"
|
|
8048
|
+
fi ;;
|
|
8049
|
+
python)
|
|
8050
|
+
if command -v pip-audit &>/dev/null; then
|
|
8051
|
+
dep_output=$(cd "$target_dir" && pip-audit 2>&1) || dep_status="WARN"
|
|
8052
|
+
else
|
|
8053
|
+
dep_output="pip-audit not available"; dep_status="WARN"
|
|
8054
|
+
fi ;;
|
|
8055
|
+
*) dep_output="No dependency audit available for $project_type"; dep_status="WARN" ;;
|
|
8056
|
+
esac
|
|
8057
|
+
_review_gate "dependencies" "$dep_status" "$dep_output"
|
|
8058
|
+
|
|
8059
|
+
# Gate 6: Structure check
|
|
8060
|
+
local struct_output="" struct_status="PASS" struct_issues=()
|
|
8061
|
+
[ ! -f "$target_dir/README.md" ] && [ ! -f "$target_dir/README.rst" ] && [ ! -f "$target_dir/README" ] && struct_issues+=("Missing README")
|
|
8062
|
+
local file_count
|
|
8063
|
+
file_count=$(find "$target_dir" -type f -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/vendor/*' -not -path '*/__pycache__/*' -not -path '*/.venv/*' -not -path '*/target/*' 2>/dev/null | wc -l | tr -d ' ')
|
|
8064
|
+
[ "$file_count" -gt 5000 ] && struct_issues+=("Large project: $file_count files")
|
|
8065
|
+
local huge_files
|
|
8066
|
+
huge_files=$(find "$target_dir" -type f -size +1M -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/vendor/*' -not -path '*/target/*' 2>/dev/null | head -5)
|
|
8067
|
+
[ -n "$huge_files" ] && struct_issues+=("Files >1MB found: $(echo "$huge_files" | wc -l | tr -d ' ')")
|
|
8068
|
+
if [ ${#struct_issues[@]} -gt 0 ]; then
|
|
8069
|
+
struct_status="WARN"
|
|
8070
|
+
struct_output=$(printf '%s\n' "${struct_issues[@]}")
|
|
8071
|
+
else
|
|
8072
|
+
struct_output="README present, $file_count files, no oversized files"
|
|
8073
|
+
fi
|
|
8074
|
+
_review_gate "structure" "$struct_status" "$struct_output"
|
|
8075
|
+
|
|
8076
|
+
# Output results
|
|
8077
|
+
if [ -n "$json_output" ]; then
|
|
8078
|
+
local gates_json="["
|
|
8079
|
+
local first="true"
|
|
8080
|
+
for r in "${results[@]}"; do
|
|
8081
|
+
local gate="${r%%:*}" status="${r#*:}"
|
|
8082
|
+
[ "$first" = "true" ] && first="" || gates_json+=","
|
|
8083
|
+
gates_json+="{\"gate\":\"$gate\",\"status\":\"$status\"}"
|
|
8084
|
+
done
|
|
8085
|
+
gates_json+="]"
|
|
8086
|
+
printf '{"directory":"%s","project_type":"%s","pass":%d,"warn":%d,"fail":%d,"gates":%s}\n' \
|
|
8087
|
+
"$target_dir" "$project_type" "$total_pass" "$total_warn" "$total_fail" "$gates_json"
|
|
8088
|
+
else
|
|
8089
|
+
echo -e "${BOLD}Loki Review: $target_dir${NC}"
|
|
8090
|
+
echo -e "Project type: ${CYAN}$project_type${NC}"
|
|
8091
|
+
echo "---"
|
|
8092
|
+
for r in "${results[@]}"; do
|
|
8093
|
+
local gate="${r%%:*}" status="${r#*:}"
|
|
8094
|
+
case "$status" in
|
|
8095
|
+
PASS) echo -e " ${GREEN}[PASS]${NC} $gate" ;;
|
|
8096
|
+
WARN) echo -e " ${YELLOW}[WARN]${NC} $gate" ;;
|
|
8097
|
+
FAIL) echo -e " ${RED}[FAIL]${NC} $gate" ;;
|
|
8098
|
+
esac
|
|
8099
|
+
done
|
|
8100
|
+
echo "---"
|
|
8101
|
+
echo -e "Results: ${GREEN}$total_pass passed${NC}, ${YELLOW}$total_warn warnings${NC}, ${RED}$total_fail failed${NC}"
|
|
8102
|
+
|
|
8103
|
+
if [ -n "$verbose" ]; then
|
|
8104
|
+
echo ""
|
|
8105
|
+
echo -e "${BOLD}Details:${NC}"
|
|
8106
|
+
for d in "${gate_details[@]}"; do
|
|
8107
|
+
local gate="${d%%:*}" detail="${d#*:}"
|
|
8108
|
+
echo -e "\n${CYAN}[$gate]${NC}"
|
|
8109
|
+
echo "$detail" | head -30
|
|
8110
|
+
done
|
|
8111
|
+
fi
|
|
8112
|
+
fi
|
|
8113
|
+
|
|
8114
|
+
# Exit code: 1 if any failures
|
|
8115
|
+
[ "$total_fail" -gt 0 ] && return 1
|
|
8116
|
+
return 0
|
|
8117
|
+
}
|
|
8118
|
+
|
|
7898
8119
|
# Worktree management (v6.7.0)
|
|
7899
8120
|
cmd_worktree() {
|
|
7900
8121
|
local subcommand="${1:-list}"
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
package/templates/api-only.md
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
# PRD: REST API Service
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
A simple REST API for managing notes. Tests Loki Mode's backend-only capabilities.
|
|
4
|
+
A simple REST API for managing notes. Tests Loki Mode's backend-only capabilities with proper validation, error handling, and test coverage.
|
|
5
5
|
|
|
6
6
|
## Target Users
|
|
7
|
-
Developers who need a notes API
|
|
7
|
+
- Developers who need a lightweight notes API for prototyping
|
|
8
|
+
- Teams evaluating backend code generation quality
|
|
9
|
+
- Frontend developers needing a mock API to build against
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
### MVP Features
|
|
14
|
+
1. **Create Note** - Add a new note with title and content
|
|
15
|
+
2. **List Notes** - Retrieve all notes
|
|
16
|
+
3. **Get Note** - Retrieve a single note by ID
|
|
17
|
+
4. **Update Note** - Edit an existing note's title or content
|
|
18
|
+
5. **Delete Note** - Remove a note
|
|
19
|
+
6. **Health Check** - Service health endpoint
|
|
20
|
+
|
|
21
|
+
### Data Model
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
interface Note {
|
|
25
|
+
id: string;
|
|
26
|
+
title: string;
|
|
27
|
+
content: string;
|
|
28
|
+
createdAt: string; // ISO 8601 timestamp
|
|
29
|
+
updatedAt: string; // ISO 8601 timestamp
|
|
30
|
+
}
|
|
31
|
+
```
|
|
8
32
|
|
|
9
33
|
## API Endpoints
|
|
10
34
|
|
|
@@ -12,23 +36,23 @@ Developers who need a notes API.
|
|
|
12
36
|
|
|
13
37
|
#### GET /api/notes
|
|
14
38
|
- Returns list of all notes
|
|
15
|
-
- Response: `[{ id, title, content, createdAt }]`
|
|
39
|
+
- Response: `[{ id, title, content, createdAt, updatedAt }]`
|
|
16
40
|
|
|
17
41
|
#### GET /api/notes/:id
|
|
18
42
|
- Returns single note
|
|
19
|
-
- Response: `{ id, title, content, createdAt }`
|
|
43
|
+
- Response: `{ id, title, content, createdAt, updatedAt }`
|
|
20
44
|
- Error: 404 if not found
|
|
21
45
|
|
|
22
46
|
#### POST /api/notes
|
|
23
47
|
- Creates new note
|
|
24
48
|
- Body: `{ title, content }`
|
|
25
|
-
- Response: `{ id, title, content, createdAt }`
|
|
26
|
-
- Error: 400 if validation fails
|
|
49
|
+
- Response: `{ id, title, content, createdAt, updatedAt }` (201)
|
|
50
|
+
- Error: 400 if validation fails (title required, content required)
|
|
27
51
|
|
|
28
52
|
#### PUT /api/notes/:id
|
|
29
53
|
- Updates existing note
|
|
30
|
-
- Body: `{ title?, content? }`
|
|
31
|
-
- Response: `{ id, title, content, updatedAt }`
|
|
54
|
+
- Body: `{ title?, content? }` (partial update)
|
|
55
|
+
- Response: `{ id, title, content, createdAt, updatedAt }`
|
|
32
56
|
- Error: 404 if not found
|
|
33
57
|
|
|
34
58
|
#### DELETE /api/notes/:id
|
|
@@ -44,36 +68,70 @@ Developers who need a notes API.
|
|
|
44
68
|
## Tech Stack
|
|
45
69
|
- Runtime: Node.js 18+
|
|
46
70
|
- Framework: Express.js
|
|
71
|
+
- Language: TypeScript
|
|
47
72
|
- Database: In-memory (array) for simplicity
|
|
48
|
-
- Validation: zod
|
|
49
|
-
- Testing:
|
|
73
|
+
- Validation: zod
|
|
74
|
+
- Testing: Vitest + supertest
|
|
75
|
+
|
|
76
|
+
### Structure
|
|
77
|
+
```
|
|
78
|
+
/
|
|
79
|
+
├── src/
|
|
80
|
+
│ ├── index.ts # Express server setup, middleware
|
|
81
|
+
│ ├── routes/
|
|
82
|
+
│ │ ├── notes.ts # Notes CRUD handlers
|
|
83
|
+
│ │ └── health.ts # Health check endpoint
|
|
84
|
+
│ ├── middleware/
|
|
85
|
+
│ │ └── errorHandler.ts # Global error handler
|
|
86
|
+
│ ├── schemas/
|
|
87
|
+
│ │ └── note.ts # Zod validation schemas
|
|
88
|
+
│ └── types/
|
|
89
|
+
│ └── index.ts # TypeScript type definitions
|
|
90
|
+
├── tests/
|
|
91
|
+
│ ├── notes.test.ts # Notes endpoint tests
|
|
92
|
+
│ └── health.test.ts # Health check test
|
|
93
|
+
├── package.json
|
|
94
|
+
├── tsconfig.json
|
|
95
|
+
└── README.md
|
|
96
|
+
```
|
|
50
97
|
|
|
51
98
|
## Requirements
|
|
52
|
-
-
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
56
|
-
-
|
|
99
|
+
- TypeScript throughout
|
|
100
|
+
- Input validation on all endpoints using zod
|
|
101
|
+
- Proper HTTP status codes (200, 201, 204, 400, 404)
|
|
102
|
+
- JSON error responses: `{ error: "message" }`
|
|
103
|
+
- Request logging (method, path, status code)
|
|
104
|
+
- CORS enabled for development
|
|
105
|
+
|
|
106
|
+
## Testing
|
|
107
|
+
- API tests: All endpoints with valid input, invalid input, and edge cases (Vitest + supertest)
|
|
108
|
+
- Minimum test cases:
|
|
109
|
+
- `POST /api/notes` with valid data -> 201 + note object
|
|
110
|
+
- `POST /api/notes` with missing title -> 400 + error
|
|
111
|
+
- `POST /api/notes` with missing content -> 400 + error
|
|
112
|
+
- `GET /api/notes` -> 200 + array
|
|
113
|
+
- `GET /api/notes/:id` with valid id -> 200 + note
|
|
114
|
+
- `GET /api/notes/:id` with invalid id -> 404
|
|
115
|
+
- `PUT /api/notes/:id` with valid data -> 200 + updated note
|
|
116
|
+
- `PUT /api/notes/:id` with invalid id -> 404
|
|
117
|
+
- `DELETE /api/notes/:id` -> 204
|
|
118
|
+
- `DELETE /api/notes/:id` with invalid id -> 404
|
|
119
|
+
- `GET /health` -> 200 + status object
|
|
57
120
|
|
|
58
121
|
## Out of Scope
|
|
59
122
|
- Authentication
|
|
60
|
-
- Database persistence
|
|
123
|
+
- Database persistence (file or SQL)
|
|
61
124
|
- Rate limiting
|
|
62
125
|
- API documentation (OpenAPI)
|
|
63
126
|
- Deployment
|
|
64
127
|
|
|
65
|
-
##
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
GET /api/notes/:id with invalid id → 404
|
|
72
|
-
PUT /api/notes/:id with valid data → 200 + updated note
|
|
73
|
-
DELETE /api/notes/:id → 204
|
|
74
|
-
GET /health → 200 + status object
|
|
75
|
-
```
|
|
128
|
+
## Success Criteria
|
|
129
|
+
- All 6 endpoints return correct status codes and response bodies
|
|
130
|
+
- Validation rejects invalid input with descriptive error messages
|
|
131
|
+
- All tests pass
|
|
132
|
+
- Server starts without errors on `npm start`
|
|
133
|
+
- Health check returns valid response
|
|
76
134
|
|
|
77
135
|
---
|
|
78
136
|
|
|
79
|
-
**Purpose:** Tests backend agent capabilities, code review, and QA without frontend complexity.
|
|
137
|
+
**Purpose:** Tests backend agent capabilities, code review, and QA without frontend complexity. Expect ~15-20 minutes for full execution.
|
package/templates/e-commerce.md
CHANGED
|
@@ -12,7 +12,7 @@ A simple e-commerce storefront called "ShopBase" with a product catalog, shoppin
|
|
|
12
12
|
|
|
13
13
|
### MVP Features
|
|
14
14
|
1. **Product Catalog** - Browse products with images, prices, descriptions, and categories
|
|
15
|
-
2. **Product Detail** - Full product page with image gallery
|
|
15
|
+
2. **Product Detail** - Full product page with image gallery and variants (size/color)
|
|
16
16
|
3. **Shopping Cart** - Add/remove items, update quantities, persistent cart (survives refresh)
|
|
17
17
|
4. **Checkout** - Shipping address form, order summary, Stripe payment
|
|
18
18
|
5. **Order Confirmation** - Confirmation page and email receipt
|
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
# PRD: Full-Stack Demo App
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
A complete full-stack application demonstrating Loki Mode's end-to-end capabilities. A
|
|
4
|
+
A complete full-stack application demonstrating Loki Mode's end-to-end capabilities. A bookmark manager called "Stash" with tags, search, and a clean UI.
|
|
5
5
|
|
|
6
6
|
## Target Users
|
|
7
|
-
Users who want to save and organize bookmarks
|
|
7
|
+
- Users who want to save and organize bookmarks with tags
|
|
8
|
+
- Developers testing Loki Mode's full-stack generation pipeline
|
|
8
9
|
|
|
9
10
|
## Features
|
|
10
11
|
|
|
11
12
|
### Core Features
|
|
12
13
|
1. **Add Bookmark** - Save URL with title and optional tags
|
|
13
|
-
|
|
14
|
+
- Acceptance: Form validates URL format, title is required, tags are comma-separated, form clears on submit
|
|
15
|
+
2. **View Bookmarks** - List all bookmarks with search and tag filter
|
|
16
|
+
- Acceptance: Shows URL, title, tags, and creation date; search filters by title with 300ms debounce; tag chips are clickable for filtering
|
|
14
17
|
3. **Edit Bookmark** - Update title, URL, or tags
|
|
15
|
-
|
|
18
|
+
- Acceptance: Inline edit or modal form, pre-populated with current values, saves on submit
|
|
19
|
+
4. **Delete Bookmark** - Remove bookmark with confirmation
|
|
20
|
+
- Acceptance: Confirmation dialog before delete, bookmark removed from list and database
|
|
16
21
|
5. **Tag Management** - Create, view, and filter by tags
|
|
22
|
+
- Acceptance: Tag sidebar shows all tags with bookmark counts, clicking a tag filters the list, unused tags cleaned up on bookmark delete
|
|
17
23
|
|
|
18
24
|
### User Flow
|
|
19
|
-
1. User opens app
|
|
20
|
-
2. Clicks "Add Bookmark"
|
|
21
|
-
3. Enters URL, title, tags
|
|
22
|
-
4. Bookmark appears in list
|
|
23
|
-
5. Can filter by tag or search by title
|
|
25
|
+
1. User opens app -> sees bookmark list (or empty state if none)
|
|
26
|
+
2. Clicks "Add Bookmark" -> form appears
|
|
27
|
+
3. Enters URL, title, tags -> submits
|
|
28
|
+
4. Bookmark appears in list with tag chips
|
|
29
|
+
5. Can filter by tag (click tag) or search by title (search bar)
|
|
24
30
|
6. Can edit or delete any bookmark
|
|
31
|
+
7. Refreshes page -> all state persists from database
|
|
25
32
|
|
|
26
33
|
## Tech Stack
|
|
27
34
|
|
|
@@ -42,17 +49,41 @@ Users who want to save and organize bookmarks.
|
|
|
42
49
|
/
|
|
43
50
|
├── frontend/
|
|
44
51
|
│ ├── src/
|
|
52
|
+
│ │ ├── App.tsx # Main app with layout
|
|
45
53
|
│ │ ├── components/
|
|
54
|
+
│ │ │ ├── BookmarkList.tsx # List of bookmark cards
|
|
55
|
+
│ │ │ ├── BookmarkCard.tsx # Single bookmark display
|
|
56
|
+
│ │ │ ├── BookmarkForm.tsx # Add/edit form
|
|
57
|
+
│ │ │ ├── SearchBar.tsx # Search input with debounce
|
|
58
|
+
│ │ │ ├── TagSidebar.tsx # Tag list with counts
|
|
59
|
+
│ │ │ ├── TagChip.tsx # Clickable tag badge
|
|
60
|
+
│ │ │ ├── ConfirmDialog.tsx # Delete confirmation
|
|
61
|
+
│ │ │ └── EmptyState.tsx # Shown when no bookmarks
|
|
46
62
|
│ │ ├── hooks/
|
|
63
|
+
│ │ │ ├── useBookmarks.ts # CRUD operations via React Query
|
|
64
|
+
│ │ │ └── useTags.ts # Tag fetching hook
|
|
47
65
|
│ │ ├── types/
|
|
48
|
-
│ │ └──
|
|
66
|
+
│ │ │ └── index.ts # Bookmark and Tag types
|
|
67
|
+
│ │ └── main.tsx
|
|
68
|
+
│ ├── tests/
|
|
69
|
+
│ │ ├── BookmarkCard.test.tsx # Card rendering and actions
|
|
70
|
+
│ │ ├── BookmarkForm.test.tsx # Form validation and submit
|
|
71
|
+
│ │ └── SearchBar.test.tsx # Debounce and filter behavior
|
|
49
72
|
│ ├── package.json
|
|
50
73
|
│ └── vite.config.ts
|
|
51
74
|
├── backend/
|
|
52
75
|
│ ├── src/
|
|
76
|
+
│ │ ├── index.ts # Express server setup
|
|
53
77
|
│ │ ├── routes/
|
|
78
|
+
│ │ │ ├── bookmarks.ts # Bookmark CRUD handlers
|
|
79
|
+
│ │ │ └── tags.ts # Tag list handler
|
|
54
80
|
│ │ ├── db/
|
|
55
|
-
│ │ └── index.ts
|
|
81
|
+
│ │ │ └── index.ts # SQLite connection + schema init
|
|
82
|
+
│ │ └── schemas/
|
|
83
|
+
│ │ └── bookmark.ts # Zod validation schemas
|
|
84
|
+
│ ├── tests/
|
|
85
|
+
│ │ ├── bookmarks.test.ts # Bookmark API tests
|
|
86
|
+
│ │ └── tags.test.ts # Tag API tests
|
|
56
87
|
│ ├── package.json
|
|
57
88
|
│ └── tsconfig.json
|
|
58
89
|
└── README.md
|
|
@@ -62,17 +93,20 @@ Users who want to save and organize bookmarks.
|
|
|
62
93
|
|
|
63
94
|
### Bookmarks
|
|
64
95
|
- `GET /api/bookmarks` - List all (query: `?tag=`, `?search=`)
|
|
65
|
-
- `POST /api/bookmarks` - Create new
|
|
66
|
-
- `PUT /api/bookmarks/:id` - Update
|
|
67
|
-
- `DELETE /api/bookmarks/:id` - Delete
|
|
96
|
+
- `POST /api/bookmarks` - Create new (body: `{ url, title, tags? }`)
|
|
97
|
+
- `PUT /api/bookmarks/:id` - Update (body: `{ url?, title?, tags? }`)
|
|
98
|
+
- `DELETE /api/bookmarks/:id` - Delete (returns 204)
|
|
68
99
|
|
|
69
100
|
### Tags
|
|
70
|
-
- `GET /api/tags` - List all tags with counts
|
|
101
|
+
- `GET /api/tags` - List all tags with bookmark counts
|
|
102
|
+
|
|
103
|
+
### Health
|
|
104
|
+
- `GET /health` - Returns `{ status: "ok" }`
|
|
71
105
|
|
|
72
106
|
## Database Schema
|
|
73
107
|
```sql
|
|
74
108
|
CREATE TABLE bookmarks (
|
|
75
|
-
id INTEGER PRIMARY KEY,
|
|
109
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
76
110
|
url TEXT NOT NULL,
|
|
77
111
|
title TEXT NOT NULL,
|
|
78
112
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
@@ -80,29 +114,31 @@ CREATE TABLE bookmarks (
|
|
|
80
114
|
);
|
|
81
115
|
|
|
82
116
|
CREATE TABLE tags (
|
|
83
|
-
id INTEGER PRIMARY KEY,
|
|
117
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
84
118
|
name TEXT UNIQUE NOT NULL
|
|
85
119
|
);
|
|
86
120
|
|
|
87
121
|
CREATE TABLE bookmark_tags (
|
|
88
|
-
bookmark_id INTEGER REFERENCES bookmarks(id),
|
|
89
|
-
tag_id INTEGER REFERENCES tags(id),
|
|
122
|
+
bookmark_id INTEGER REFERENCES bookmarks(id) ON DELETE CASCADE,
|
|
123
|
+
tag_id INTEGER REFERENCES tags(id) ON DELETE CASCADE,
|
|
90
124
|
PRIMARY KEY (bookmark_id, tag_id)
|
|
91
125
|
);
|
|
92
126
|
```
|
|
93
127
|
|
|
94
128
|
## Requirements
|
|
95
129
|
- TypeScript throughout
|
|
96
|
-
- Input validation (frontend + backend)
|
|
97
|
-
- Error handling with user feedback
|
|
98
|
-
- Loading states
|
|
99
|
-
- Empty states
|
|
100
|
-
-
|
|
130
|
+
- Input validation (frontend + backend): URL format, title required
|
|
131
|
+
- Error handling with user-visible feedback (toast or inline messages)
|
|
132
|
+
- Loading states during API calls
|
|
133
|
+
- Empty states for no bookmarks and no search results
|
|
134
|
+
- Search debounce: 300ms delay before API call
|
|
135
|
+
- Responsive design (single-column on mobile, sidebar on desktop)
|
|
101
136
|
|
|
102
137
|
## Testing
|
|
103
|
-
- Backend:
|
|
104
|
-
- Frontend
|
|
105
|
-
-
|
|
138
|
+
- Backend API tests: Bookmark CRUD, tag listing, search/filter queries (Vitest + supertest)
|
|
139
|
+
- Frontend component tests: BookmarkCard rendering, BookmarkForm validation, SearchBar debounce (Vitest + React Testing Library)
|
|
140
|
+
- Minimum 10 test cases across frontend and backend
|
|
141
|
+
- All tests required to pass (no optional tests)
|
|
106
142
|
|
|
107
143
|
## Out of Scope
|
|
108
144
|
- User authentication
|
|
@@ -112,10 +148,13 @@ CREATE TABLE bookmark_tags (
|
|
|
112
148
|
- Real-time sync
|
|
113
149
|
|
|
114
150
|
## Success Criteria
|
|
115
|
-
- All CRUD operations work
|
|
116
|
-
- Search
|
|
151
|
+
- All CRUD operations work end-to-end (create, read, update, delete)
|
|
152
|
+
- Search filters bookmarks by title with debounce
|
|
153
|
+
- Tag filter shows only bookmarks with selected tag
|
|
154
|
+
- Tag counts are accurate
|
|
155
|
+
- Data persists across page refresh
|
|
117
156
|
- No console errors
|
|
118
|
-
-
|
|
157
|
+
- All tests pass
|
|
119
158
|
- Code review passes (all 3 reviewers)
|
|
120
159
|
|
|
121
160
|
---
|
|
@@ -1,48 +1,133 @@
|
|
|
1
1
|
# PRD: Simple Todo App
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
A minimal todo application for testing Loki Mode with a simple, well-defined scope.
|
|
4
|
+
A minimal todo application for testing Loki Mode with a simple, well-defined scope. A single-page app called "Todos" with a React frontend, Express API, and SQLite persistence.
|
|
5
5
|
|
|
6
6
|
## Target Users
|
|
7
|
-
Individual users who want a simple way to track tasks
|
|
7
|
+
- Individual users who want a simple way to track tasks
|
|
8
|
+
- Developers testing Loki Mode's core generation pipeline
|
|
8
9
|
|
|
9
10
|
## Features
|
|
10
11
|
|
|
11
12
|
### MVP Features
|
|
12
13
|
1. **Add Todo** - Users can add a new todo item with a title
|
|
13
|
-
2. **View Todos** - Display list of all todos
|
|
14
|
-
3. **Complete Todo** - Mark a todo as done
|
|
15
|
-
4. **Delete Todo** - Remove a todo from the list
|
|
14
|
+
2. **View Todos** - Display list of all todos with completion status
|
|
15
|
+
3. **Complete Todo** - Mark a todo as done (toggle)
|
|
16
|
+
4. **Delete Todo** - Remove a todo from the list with confirmation
|
|
16
17
|
|
|
17
|
-
###
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
### User Flow
|
|
19
|
+
1. User opens app -> sees todo list (or empty state if none)
|
|
20
|
+
2. Types a title in the input field -> presses Enter or clicks Add
|
|
21
|
+
3. New todo appears at the top of the list, input clears
|
|
22
|
+
4. Clicks checkbox to toggle complete -> visual strikethrough
|
|
23
|
+
5. Clicks delete icon -> confirmation prompt -> todo removed
|
|
24
|
+
6. Refreshes page -> all state persists from database
|
|
25
|
+
|
|
26
|
+
## Tech Stack
|
|
27
|
+
|
|
28
|
+
### Frontend
|
|
29
|
+
- React 18 with TypeScript
|
|
30
|
+
- Vite for bundling
|
|
31
|
+
- TailwindCSS for styling
|
|
32
|
+
|
|
33
|
+
### Backend
|
|
34
|
+
- Node.js 18+
|
|
35
|
+
- Express.js
|
|
36
|
+
- SQLite via better-sqlite3
|
|
37
|
+
- zod for input validation
|
|
38
|
+
|
|
39
|
+
### Structure
|
|
40
|
+
```
|
|
41
|
+
/
|
|
42
|
+
├── frontend/
|
|
43
|
+
│ ├── src/
|
|
44
|
+
│ │ ├── App.tsx # Main app component
|
|
45
|
+
│ │ ├── components/
|
|
46
|
+
│ │ │ ├── TodoList.tsx # List of todo items
|
|
47
|
+
│ │ │ ├── TodoItem.tsx # Single todo with checkbox/delete
|
|
48
|
+
│ │ │ ├── AddTodo.tsx # Input form for new todos
|
|
49
|
+
│ │ │ └── EmptyState.tsx # Shown when no todos exist
|
|
50
|
+
│ │ ├── hooks/
|
|
51
|
+
│ │ │ └── useTodos.ts # API fetch/mutate hook
|
|
52
|
+
│ │ ├── types/
|
|
53
|
+
│ │ │ └── index.ts # Todo type definition
|
|
54
|
+
│ │ └── main.tsx
|
|
55
|
+
│ ├── package.json
|
|
56
|
+
│ └── vite.config.ts
|
|
57
|
+
├── backend/
|
|
58
|
+
│ ├── src/
|
|
59
|
+
│ │ ├── index.ts # Express server setup
|
|
60
|
+
│ │ ├── routes/
|
|
61
|
+
│ │ │ └── todos.ts # CRUD route handlers
|
|
62
|
+
│ │ └── db/
|
|
63
|
+
│ │ └── index.ts # SQLite connection + init
|
|
64
|
+
│ ├── package.json
|
|
65
|
+
│ └── tsconfig.json
|
|
66
|
+
├── tests/
|
|
67
|
+
│ ├── todos.test.ts # API endpoint tests
|
|
68
|
+
│ └── components/
|
|
69
|
+
│ └── TodoItem.test.tsx # Component tests
|
|
70
|
+
└── README.md
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Database Schema
|
|
74
|
+
|
|
75
|
+
```sql
|
|
76
|
+
CREATE TABLE todos (
|
|
77
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
78
|
+
title TEXT NOT NULL,
|
|
79
|
+
completed INTEGER DEFAULT 0, -- 0 = false, 1 = true
|
|
80
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
81
|
+
);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## API Endpoints
|
|
85
|
+
|
|
86
|
+
### Todos
|
|
87
|
+
- `GET /api/todos` - List all todos (ordered by created_at DESC)
|
|
88
|
+
- `POST /api/todos` - Create todo (body: `{ title }`, returns created todo)
|
|
89
|
+
- `PATCH /api/todos/:id` - Toggle completion (body: `{ completed }`)
|
|
90
|
+
- `DELETE /api/todos/:id` - Delete todo (returns 204)
|
|
91
|
+
|
|
92
|
+
### Health
|
|
93
|
+
- `GET /health` - Returns `{ status: "ok" }`
|
|
22
94
|
|
|
23
95
|
## Acceptance Criteria
|
|
24
96
|
|
|
25
97
|
### Add Todo
|
|
26
98
|
- [ ] Input field for todo title
|
|
27
|
-
- [ ] Submit button
|
|
99
|
+
- [ ] Submit on Enter key or button click
|
|
28
100
|
- [ ] New todo appears in list
|
|
29
101
|
- [ ] Input clears after submit
|
|
102
|
+
- [ ] Empty title is rejected (frontend + backend validation)
|
|
30
103
|
|
|
31
104
|
### View Todos
|
|
32
105
|
- [ ] Shows all todos in a list
|
|
33
|
-
- [ ] Shows completion status
|
|
34
|
-
- [ ] Empty state when no todos
|
|
106
|
+
- [ ] Shows completion status (checkbox)
|
|
107
|
+
- [ ] Empty state message when no todos exist
|
|
35
108
|
|
|
36
109
|
### Complete Todo
|
|
37
|
-
- [ ] Checkbox
|
|
38
|
-
- [ ] Visual
|
|
39
|
-
- [ ] Persists after refresh
|
|
110
|
+
- [ ] Checkbox toggles complete/incomplete
|
|
111
|
+
- [ ] Visual strikethrough for completed items
|
|
112
|
+
- [ ] Persists after page refresh
|
|
40
113
|
|
|
41
114
|
### Delete Todo
|
|
42
115
|
- [ ] Delete button on each todo
|
|
43
116
|
- [ ] Confirmation before delete
|
|
44
117
|
- [ ] Removes from list and database
|
|
45
118
|
|
|
119
|
+
## Requirements
|
|
120
|
+
- TypeScript throughout
|
|
121
|
+
- Input validation on both frontend and backend
|
|
122
|
+
- Proper HTTP status codes (201 for create, 204 for delete, 400 for validation errors)
|
|
123
|
+
- Loading states during API calls
|
|
124
|
+
- Responsive design (usable on mobile)
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
- API tests: All 4 CRUD endpoints with valid and invalid input (Vitest + supertest)
|
|
128
|
+
- Component tests: TodoItem renders correctly, AddTodo form submission works
|
|
129
|
+
- Minimum 6 test cases covering happy path and error cases
|
|
130
|
+
|
|
46
131
|
## Out of Scope
|
|
47
132
|
- User authentication
|
|
48
133
|
- Due dates
|
|
@@ -50,11 +135,14 @@ Individual users who want a simple way to track tasks.
|
|
|
50
135
|
- Mobile app
|
|
51
136
|
- Cloud deployment
|
|
52
137
|
|
|
53
|
-
## Success
|
|
54
|
-
- All features functional
|
|
55
|
-
-
|
|
138
|
+
## Success Criteria
|
|
139
|
+
- All 4 CRUD features functional end-to-end
|
|
140
|
+
- All tests pass
|
|
56
141
|
- No console errors
|
|
142
|
+
- Empty state displays correctly
|
|
143
|
+
- Data persists across page refresh
|
|
144
|
+
- Input validation rejects empty titles
|
|
57
145
|
|
|
58
146
|
---
|
|
59
147
|
|
|
60
|
-
**Purpose:** This PRD is intentionally simple to allow quick testing of Loki Mode's core functionality without waiting for complex builds or deployments.
|
|
148
|
+
**Purpose:** This PRD is intentionally simple to allow quick testing of Loki Mode's core functionality without waiting for complex builds or deployments. Expect ~15-25 minutes for full execution.
|