loki-mode 6.12.5 → 6.13.1
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 +204 -244
- 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.13.1
|
|
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.13.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.13.1
|
package/autonomy/loki
CHANGED
|
@@ -5597,293 +5597,253 @@ cmd_sandbox() {
|
|
|
5597
5597
|
exec "$SANDBOX_SH" "$subcommand" "$@"
|
|
5598
5598
|
}
|
|
5599
5599
|
|
|
5600
|
-
# Demo mode -
|
|
5600
|
+
# Demo mode - build a real project from a bundled PRD template
|
|
5601
5601
|
cmd_demo() {
|
|
5602
5602
|
# Handle --help
|
|
5603
5603
|
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
|
5604
|
-
echo -e "${BOLD}loki demo${NC} -
|
|
5604
|
+
echo -e "${BOLD}loki demo${NC} - Build a real project from a bundled template"
|
|
5605
5605
|
echo ""
|
|
5606
|
-
echo "
|
|
5607
|
-
echo "
|
|
5606
|
+
echo "Creates a temporary directory, copies the Simple Todo App PRD, and"
|
|
5607
|
+
echo "runs 'loki start' to build it end-to-end. Shows a summary when done"
|
|
5608
|
+
echo "and offers to open the result in a browser."
|
|
5608
5609
|
echo ""
|
|
5609
|
-
echo "Usage: loki demo"
|
|
5610
|
+
echo "Usage: loki demo [options]"
|
|
5611
|
+
echo ""
|
|
5612
|
+
echo "Options:"
|
|
5613
|
+
echo " --dir PATH Use a specific directory instead of a temp dir"
|
|
5614
|
+
echo " --keep Keep the temp directory on exit (default: kept)"
|
|
5615
|
+
echo " --provider P AI provider to use (default: claude)"
|
|
5616
|
+
echo " --dry-run Show what would happen without running"
|
|
5617
|
+
echo ""
|
|
5618
|
+
echo "Examples:"
|
|
5619
|
+
echo " loki demo # Build todo app in temp dir"
|
|
5620
|
+
echo " loki demo --dir ~/demo-project # Build in specific directory"
|
|
5621
|
+
echo " loki demo --provider codex # Use Codex instead of Claude"
|
|
5610
5622
|
return 0
|
|
5611
5623
|
fi
|
|
5612
5624
|
|
|
5613
|
-
local version
|
|
5614
|
-
|
|
5625
|
+
local version
|
|
5626
|
+
version=$(get_version)
|
|
5615
5627
|
local demo_prd="$SKILL_DIR/templates/simple-todo-app.md"
|
|
5628
|
+
local demo_dir=""
|
|
5629
|
+
local provider=""
|
|
5630
|
+
local dry_run=false
|
|
5631
|
+
local start_args=()
|
|
5616
5632
|
|
|
5617
|
-
#
|
|
5633
|
+
# Parse arguments
|
|
5634
|
+
while [[ $# -gt 0 ]]; do
|
|
5635
|
+
case "$1" in
|
|
5636
|
+
--dir)
|
|
5637
|
+
if [[ -z "${2:-}" ]]; then
|
|
5638
|
+
echo -e "${RED}Error: --dir requires a path${NC}"
|
|
5639
|
+
return 1
|
|
5640
|
+
fi
|
|
5641
|
+
demo_dir="$2"
|
|
5642
|
+
shift 2
|
|
5643
|
+
;;
|
|
5644
|
+
--dir=*)
|
|
5645
|
+
demo_dir="${1#*=}"
|
|
5646
|
+
shift
|
|
5647
|
+
;;
|
|
5648
|
+
--provider)
|
|
5649
|
+
if [[ -z "${2:-}" ]]; then
|
|
5650
|
+
echo -e "${RED}Error: --provider requires a value${NC}"
|
|
5651
|
+
return 1
|
|
5652
|
+
fi
|
|
5653
|
+
provider="$2"
|
|
5654
|
+
shift 2
|
|
5655
|
+
;;
|
|
5656
|
+
--provider=*)
|
|
5657
|
+
provider="${1#*=}"
|
|
5658
|
+
shift
|
|
5659
|
+
;;
|
|
5660
|
+
--keep)
|
|
5661
|
+
# kept by default now, accepted for compat
|
|
5662
|
+
shift
|
|
5663
|
+
;;
|
|
5664
|
+
--dry-run)
|
|
5665
|
+
dry_run=true
|
|
5666
|
+
shift
|
|
5667
|
+
;;
|
|
5668
|
+
*)
|
|
5669
|
+
echo -e "${RED}Unknown option: $1${NC}"
|
|
5670
|
+
echo "Run 'loki demo --help' for usage."
|
|
5671
|
+
return 1
|
|
5672
|
+
;;
|
|
5673
|
+
esac
|
|
5674
|
+
done
|
|
5675
|
+
|
|
5676
|
+
# Fall back to examples/ if templates/ doesn't exist
|
|
5618
5677
|
if [ ! -f "$demo_prd" ]; then
|
|
5619
5678
|
demo_prd="$SKILL_DIR/examples/simple-todo-app.md"
|
|
5620
5679
|
fi
|
|
5621
5680
|
|
|
5622
5681
|
if [ ! -f "$demo_prd" ]; then
|
|
5623
5682
|
echo -e "${RED}Error: Demo PRD not found${NC}"
|
|
5624
|
-
echo "Expected at: $
|
|
5625
|
-
|
|
5683
|
+
echo "Expected at: $SKILL_DIR/templates/simple-todo-app.md"
|
|
5684
|
+
return 1
|
|
5626
5685
|
fi
|
|
5627
5686
|
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
echo ""
|
|
5636
|
-
|
|
5637
|
-
# Track if we created .loki for cleanup
|
|
5638
|
-
local demo_created_loki=false
|
|
5639
|
-
if [ ! -d "$LOKI_DIR" ]; then
|
|
5640
|
-
demo_created_loki=true
|
|
5687
|
+
# Set up the demo directory
|
|
5688
|
+
if [ -z "$demo_dir" ]; then
|
|
5689
|
+
demo_dir=$(mktemp -d "${TMPDIR:-/tmp}/loki-demo-XXXXXX")
|
|
5690
|
+
else
|
|
5691
|
+
# Expand ~ if present
|
|
5692
|
+
demo_dir="${demo_dir/#\~/$HOME}"
|
|
5693
|
+
mkdir -p "$demo_dir"
|
|
5641
5694
|
fi
|
|
5642
5695
|
|
|
5643
|
-
|
|
5644
|
-
|
|
5696
|
+
echo -e "${BOLD}Loki Mode v$version - Demo${NC}"
|
|
5697
|
+
echo ""
|
|
5698
|
+
echo -e " PRD: Simple Todo App"
|
|
5699
|
+
echo -e " Directory: ${CYAN}$demo_dir${NC}"
|
|
5700
|
+
if [ -n "$provider" ]; then
|
|
5701
|
+
echo -e " Provider: $provider"
|
|
5702
|
+
else
|
|
5703
|
+
echo -e " Provider: claude (default)"
|
|
5704
|
+
fi
|
|
5705
|
+
echo ""
|
|
5645
5706
|
|
|
5646
|
-
#
|
|
5647
|
-
|
|
5648
|
-
local start_time
|
|
5649
|
-
start_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
5650
|
-
cat > "$LOKI_DIR/session.json" << SESSEOF
|
|
5651
|
-
{
|
|
5652
|
-
"status": "running",
|
|
5653
|
-
"pid": $demo_pid,
|
|
5654
|
-
"provider": "claude",
|
|
5655
|
-
"started": "$start_time",
|
|
5656
|
-
"project": "$(pwd)",
|
|
5657
|
-
"mode": "demo"
|
|
5658
|
-
}
|
|
5659
|
-
SESSEOF
|
|
5660
|
-
echo "$demo_pid" > "$LOKI_DIR/loki.pid"
|
|
5661
|
-
|
|
5662
|
-
# Start dashboard server
|
|
5663
|
-
local dashboard_started=false
|
|
5664
|
-
if command -v python3 &> /dev/null && [ -f "$SKILL_DIR/dashboard/server.py" ]; then
|
|
5665
|
-
# Kill any existing dashboard on this port
|
|
5666
|
-
local existing_pids
|
|
5667
|
-
existing_pids=$(lsof -ti :57374 2>/dev/null || true)
|
|
5668
|
-
if [ -n "$existing_pids" ]; then
|
|
5669
|
-
echo "$existing_pids" | xargs kill 2>/dev/null || true
|
|
5670
|
-
sleep 1
|
|
5671
|
-
fi
|
|
5707
|
+
# Copy PRD into demo directory
|
|
5708
|
+
cp "$demo_prd" "$demo_dir/prd.md"
|
|
5672
5709
|
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
local demo_python="$DASHBOARD_PYTHON"
|
|
5710
|
+
# Initialize git repo if not already one
|
|
5711
|
+
if [ ! -d "$demo_dir/.git" ]; then
|
|
5712
|
+
git -C "$demo_dir" init -q 2>/dev/null || true
|
|
5713
|
+
fi
|
|
5678
5714
|
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
echo "
|
|
5715
|
+
if [ "$dry_run" = true ]; then
|
|
5716
|
+
echo -e "${YELLOW}[dry-run] Would run:${NC}"
|
|
5717
|
+
echo " cd $demo_dir"
|
|
5718
|
+
echo -n " loki start prd.md --simple --yes"
|
|
5719
|
+
[ -n "$provider" ] && echo -n " --provider $provider"
|
|
5720
|
+
echo ""
|
|
5721
|
+
echo ""
|
|
5722
|
+
echo -e "${DIM}PRD copied to: $demo_dir/prd.md${NC}"
|
|
5723
|
+
return 0
|
|
5724
|
+
fi
|
|
5683
5725
|
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
if curl -s http://127.0.0.1:57374/health &>/dev/null; then
|
|
5688
|
-
dashboard_started=true
|
|
5689
|
-
echo -e "${GREEN}Dashboard started${NC} at http://127.0.0.1:57374"
|
|
5690
|
-
break
|
|
5691
|
-
fi
|
|
5692
|
-
sleep 0.5
|
|
5693
|
-
wait_count=$((wait_count + 1))
|
|
5694
|
-
done
|
|
5726
|
+
echo -e "${DIM}Starting autonomous build...${NC}"
|
|
5727
|
+
echo -e "${DIM}(Press Ctrl+C to stop at any time)${NC}"
|
|
5728
|
+
echo ""
|
|
5695
5729
|
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
|
|
5730
|
+
# Build start args
|
|
5731
|
+
start_args+=("prd.md" "--simple" "--yes")
|
|
5732
|
+
if [ -n "$provider" ]; then
|
|
5733
|
+
start_args+=("--provider" "$provider")
|
|
5699
5734
|
fi
|
|
5700
5735
|
|
|
5736
|
+
# Run loki start from the demo directory
|
|
5737
|
+
local start_exit=0
|
|
5738
|
+
(cd "$demo_dir" && cmd_start "${start_args[@]}") || start_exit=$?
|
|
5739
|
+
|
|
5701
5740
|
echo ""
|
|
5702
|
-
echo -e "${DIM}
|
|
5741
|
+
echo -e "${DIM}---------------------------------------${NC}"
|
|
5742
|
+
echo -e "${BOLD}Demo Complete${NC}"
|
|
5743
|
+
echo -e "${DIM}---------------------------------------${NC}"
|
|
5703
5744
|
echo ""
|
|
5704
5745
|
|
|
5705
|
-
#
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
local agents=("planner" "architect" "frontend-dev" "backend-dev" "test-engineer" "reviewer-1" "reviewer-2" "reviewer-3" "qa-engineer" "deploy-engineer")
|
|
5709
|
-
local tasks=("Analyze PRD requirements" "Design system architecture" "Scaffold React frontend" "Create Express API server" "Set up SQLite database" "Implement todo CRUD operations" "Write unit tests" "Run code review (3 reviewers)" "Quality gate validation" "Prepare deployment artifacts")
|
|
5710
|
-
|
|
5711
|
-
local iteration=1
|
|
5712
|
-
local completed_tasks=0
|
|
5713
|
-
local total_tasks=${#tasks[@]}
|
|
5714
|
-
local elapsed=0
|
|
5715
|
-
local task_idx=0
|
|
5716
|
-
|
|
5717
|
-
# Cleanup handler (guard against double-run)
|
|
5718
|
-
local _demo_cleaned=false
|
|
5719
|
-
cleanup_demo() {
|
|
5720
|
-
if [ "$_demo_cleaned" = true ]; then return; fi
|
|
5721
|
-
_demo_cleaned=true
|
|
5722
|
-
echo ""
|
|
5723
|
-
echo -e "${DIM}------- Demo Session Complete -------${NC}"
|
|
5724
|
-
echo ""
|
|
5746
|
+
# Show summary of what was generated
|
|
5747
|
+
echo -e "${BOLD}Project Directory:${NC} $demo_dir"
|
|
5748
|
+
echo ""
|
|
5725
5749
|
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5750
|
+
if [ -d "$demo_dir" ]; then
|
|
5751
|
+
# Count generated files (exclude .git and .loki)
|
|
5752
|
+
local file_count
|
|
5753
|
+
file_count=$(find "$demo_dir" -type f \
|
|
5754
|
+
-not -path "$demo_dir/.git/*" \
|
|
5755
|
+
-not -path "$demo_dir/.loki/*" \
|
|
5756
|
+
-not -name "prd.md" \
|
|
5757
|
+
2>/dev/null | wc -l | tr -d ' ')
|
|
5758
|
+
|
|
5759
|
+
local dir_count
|
|
5760
|
+
dir_count=$(find "$demo_dir" -type d \
|
|
5761
|
+
-not -path "$demo_dir/.git" \
|
|
5762
|
+
-not -path "$demo_dir/.git/*" \
|
|
5763
|
+
-not -path "$demo_dir/.loki" \
|
|
5764
|
+
-not -path "$demo_dir/.loki/*" \
|
|
5765
|
+
-not -path "$demo_dir" \
|
|
5766
|
+
2>/dev/null | wc -l | tr -d ' ')
|
|
5767
|
+
|
|
5768
|
+
echo -e "${BOLD}Generated:${NC} $file_count files in $dir_count directories"
|
|
5741
5769
|
echo ""
|
|
5742
5770
|
|
|
5743
|
-
#
|
|
5744
|
-
if
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
" 2>/dev/null || true
|
|
5771
|
+
# Show top-level structure
|
|
5772
|
+
if command -v tree &>/dev/null; then
|
|
5773
|
+
echo -e "${BOLD}Project Structure:${NC}"
|
|
5774
|
+
tree -L 2 --dirsfirst -I '.git|.loki' "$demo_dir" 2>/dev/null || \
|
|
5775
|
+
ls -1 "$demo_dir" 2>/dev/null
|
|
5776
|
+
echo ""
|
|
5777
|
+
else
|
|
5778
|
+
echo -e "${BOLD}Top-level contents:${NC}"
|
|
5779
|
+
ls -1 "$demo_dir" | grep -v '^\.\(git\|loki\)$' || true
|
|
5780
|
+
echo ""
|
|
5754
5781
|
fi
|
|
5755
5782
|
|
|
5756
|
-
#
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5783
|
+
# Check for common web artifacts and offer to open
|
|
5784
|
+
local has_web=false
|
|
5785
|
+
local open_target=""
|
|
5786
|
+
|
|
5787
|
+
# Check for common entry points
|
|
5788
|
+
for candidate in \
|
|
5789
|
+
"$demo_dir/index.html" \
|
|
5790
|
+
"$demo_dir/dist/index.html" \
|
|
5791
|
+
"$demo_dir/build/index.html" \
|
|
5792
|
+
"$demo_dir/public/index.html" \
|
|
5793
|
+
"$demo_dir/frontend/dist/index.html" \
|
|
5794
|
+
"$demo_dir/client/dist/index.html"; do
|
|
5795
|
+
if [ -f "$candidate" ]; then
|
|
5796
|
+
has_web=true
|
|
5797
|
+
open_target="$candidate"
|
|
5798
|
+
break
|
|
5799
|
+
fi
|
|
5800
|
+
done
|
|
5801
|
+
|
|
5802
|
+
# Check for package.json with start script
|
|
5803
|
+
local has_start_script=false
|
|
5804
|
+
if [ -f "$demo_dir/package.json" ]; then
|
|
5805
|
+
if grep -q '"start"' "$demo_dir/package.json" 2>/dev/null; then
|
|
5806
|
+
has_start_script=true
|
|
5807
|
+
fi
|
|
5808
|
+
if grep -q '"dev"' "$demo_dir/package.json" 2>/dev/null; then
|
|
5809
|
+
has_start_script=true
|
|
5762
5810
|
fi
|
|
5763
|
-
fi
|
|
5764
|
-
# Also kill by port
|
|
5765
|
-
local port_pids
|
|
5766
|
-
port_pids=$(lsof -ti :57374 2>/dev/null || true)
|
|
5767
|
-
if [ -n "$port_pids" ]; then
|
|
5768
|
-
echo "$port_pids" | xargs kill 2>/dev/null || true
|
|
5769
5811
|
fi
|
|
5770
5812
|
|
|
5771
|
-
|
|
5772
|
-
|
|
5773
|
-
|
|
5813
|
+
if [ "$has_web" = true ] && [ -n "$open_target" ]; then
|
|
5814
|
+
echo -e "${CYAN}A web frontend was generated.${NC}"
|
|
5815
|
+
echo ""
|
|
5816
|
+
echo -n "Open in browser? [Y/n] "
|
|
5817
|
+
read -r answer </dev/tty 2>/dev/null || answer="n"
|
|
5818
|
+
if [[ -z "$answer" || "$answer" =~ ^[Yy] ]]; then
|
|
5819
|
+
if command -v open &>/dev/null; then
|
|
5820
|
+
open "$open_target"
|
|
5821
|
+
elif command -v xdg-open &>/dev/null; then
|
|
5822
|
+
xdg-open "$open_target"
|
|
5823
|
+
else
|
|
5824
|
+
echo -e "Open this file in your browser: ${BLUE}$open_target${NC}"
|
|
5825
|
+
fi
|
|
5826
|
+
fi
|
|
5827
|
+
elif [ "$has_start_script" = true ]; then
|
|
5828
|
+
echo -e "${CYAN}A start script was found in package.json.${NC}"
|
|
5829
|
+
echo -e "To run the app:"
|
|
5830
|
+
echo -e " cd $demo_dir && npm install && npm start"
|
|
5774
5831
|
fi
|
|
5775
|
-
|
|
5832
|
+
fi
|
|
5776
5833
|
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
#
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
local duration="${phase_durations[$phase_idx]}"
|
|
5783
|
-
|
|
5784
|
-
echo -e "${BOLD}[$phase]${NC} Phase $((phase_idx + 1))/${#phases[@]}"
|
|
5785
|
-
|
|
5786
|
-
# Write dashboard state for this phase
|
|
5787
|
-
_write_demo_state "$phase" "$iteration" "$completed_tasks" "$total_tasks" "$elapsed"
|
|
5788
|
-
|
|
5789
|
-
# Simulate work within this phase
|
|
5790
|
-
local phase_elapsed=0
|
|
5791
|
-
while [ $phase_elapsed -lt $duration ]; do
|
|
5792
|
-
# Show task progress
|
|
5793
|
-
if [ $task_idx -lt $total_tasks ]; then
|
|
5794
|
-
local task="${tasks[$task_idx]}"
|
|
5795
|
-
local agent="${agents[$((task_idx % ${#agents[@]}))]}"
|
|
5796
|
-
echo -e " ${CYAN}[agent:$agent]${NC} $task"
|
|
5797
|
-
|
|
5798
|
-
# Write task to queue
|
|
5799
|
-
echo "{\"id\":\"task-$task_idx\",\"title\":\"$task\",\"status\":\"completed\",\"agent\":\"$agent\"}" \
|
|
5800
|
-
> "$LOKI_DIR/queue/task-$task_idx.json" 2>/dev/null
|
|
5801
|
-
|
|
5802
|
-
completed_tasks=$((completed_tasks + 1))
|
|
5803
|
-
task_idx=$((task_idx + 1))
|
|
5804
|
-
fi
|
|
5805
|
-
|
|
5806
|
-
# Quality gate checks at specific phases
|
|
5807
|
-
if [ "$phase" = "CODE_REVIEW" ]; then
|
|
5808
|
-
echo -e " ${GREEN}[gate]${NC} Blind review: 3/3 reviewers approve"
|
|
5809
|
-
sleep 1
|
|
5810
|
-
echo -e " ${GREEN}[gate]${NC} Anti-sycophancy check: devil's advocate triggered"
|
|
5811
|
-
sleep 1
|
|
5812
|
-
elif [ "$phase" = "QUALITY_ASSURANCE" ]; then
|
|
5813
|
-
echo -e " ${GREEN}[gate]${NC} Static analysis: 0 issues"
|
|
5814
|
-
sleep 1
|
|
5815
|
-
echo -e " ${GREEN}[gate]${NC} Test coverage: 87% (threshold: 80%)"
|
|
5816
|
-
sleep 1
|
|
5817
|
-
echo -e " ${GREEN}[gate]${NC} Security scan: no vulnerabilities"
|
|
5818
|
-
sleep 1
|
|
5819
|
-
fi
|
|
5820
|
-
|
|
5821
|
-
iteration=$((iteration + 1))
|
|
5822
|
-
local step_sleep=2
|
|
5823
|
-
if [ $((duration - phase_elapsed)) -lt 3 ]; then
|
|
5824
|
-
step_sleep=1
|
|
5825
|
-
fi
|
|
5826
|
-
sleep $step_sleep
|
|
5827
|
-
phase_elapsed=$((phase_elapsed + step_sleep))
|
|
5828
|
-
elapsed=$((elapsed + step_sleep))
|
|
5829
|
-
|
|
5830
|
-
# Update dashboard state
|
|
5831
|
-
_write_demo_state "$phase" "$iteration" "$completed_tasks" "$total_tasks" "$elapsed"
|
|
5832
|
-
done
|
|
5834
|
+
echo ""
|
|
5835
|
+
echo -e "${BOLD}Next steps:${NC}"
|
|
5836
|
+
echo -e " cd $demo_dir # Explore the generated project"
|
|
5837
|
+
echo -e " loki start ./your-prd.md # Build your own project"
|
|
5838
|
+
echo -e " loki init # Create a PRD interactively"
|
|
5833
5839
|
|
|
5840
|
+
if [ $start_exit -ne 0 ]; then
|
|
5834
5841
|
echo ""
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
echo -e "${BOLD}[COMPLETION_COUNCIL]${NC} Evaluating project completion..."
|
|
5839
|
-
_write_demo_state "COMPLETION_COUNCIL" "$iteration" "$total_tasks" "$total_tasks" "$elapsed"
|
|
5840
|
-
sleep 2
|
|
5841
|
-
echo -e " ${GREEN}[council]${NC} Member 1: COMPLETE (all acceptance criteria met)"
|
|
5842
|
-
sleep 1
|
|
5843
|
-
echo -e " ${GREEN}[council]${NC} Member 2: COMPLETE (tests passing, code reviewed)"
|
|
5844
|
-
sleep 1
|
|
5845
|
-
echo -e " ${GREEN}[council]${NC} Member 3: COMPLETE (deployment artifacts ready)"
|
|
5846
|
-
sleep 1
|
|
5847
|
-
echo -e " ${GREEN}[verdict]${NC} Unanimous: PROJECT COMPLETE (3/3 votes)"
|
|
5848
|
-
|
|
5849
|
-
# Write final state
|
|
5850
|
-
_write_demo_state "COMPLETE" "$iteration" "$total_tasks" "$total_tasks" "$elapsed"
|
|
5851
|
-
|
|
5852
|
-
exit 0
|
|
5853
|
-
}
|
|
5854
|
-
|
|
5855
|
-
# Helper: write dashboard-state.json during demo
|
|
5856
|
-
_write_demo_state() {
|
|
5857
|
-
local phase="$1" iteration="$2" completed="$3" total="$4" elapsed="$5"
|
|
5858
|
-
local running_agents=$((RANDOM % 3 + 1))
|
|
5859
|
-
local pending=$((total - completed))
|
|
5860
|
-
local temp_file="$LOKI_DIR/.dashboard-state.json.tmp"
|
|
5842
|
+
echo -e "${YELLOW}Note: loki start exited with code $start_exit.${NC}"
|
|
5843
|
+
echo -e "${YELLOW}The demo directory is preserved at: $demo_dir${NC}"
|
|
5844
|
+
fi
|
|
5861
5845
|
|
|
5862
|
-
|
|
5863
|
-
{
|
|
5864
|
-
"status": "running",
|
|
5865
|
-
"mode": "demo",
|
|
5866
|
-
"phase": "$phase",
|
|
5867
|
-
"iteration": $iteration,
|
|
5868
|
-
"complexity": "standard",
|
|
5869
|
-
"provider": "claude",
|
|
5870
|
-
"current_task": "",
|
|
5871
|
-
"pending_tasks": $pending,
|
|
5872
|
-
"completed_tasks": $completed,
|
|
5873
|
-
"failed_tasks": 0,
|
|
5874
|
-
"running_agents": $running_agents,
|
|
5875
|
-
"total_agents": 10,
|
|
5876
|
-
"uptime_seconds": $elapsed,
|
|
5877
|
-
"version": "$(get_version)",
|
|
5878
|
-
"agents": [],
|
|
5879
|
-
"council": {
|
|
5880
|
-
"enabled": true,
|
|
5881
|
-
"last_verdict": null,
|
|
5882
|
-
"convergence_score": 0
|
|
5883
|
-
}
|
|
5884
|
-
}
|
|
5885
|
-
STATEEOF
|
|
5886
|
-
mv "$temp_file" "$LOKI_DIR/dashboard-state.json" 2>/dev/null
|
|
5846
|
+
return $start_exit
|
|
5887
5847
|
}
|
|
5888
5848
|
|
|
5889
5849
|
# Quick mode - lightweight single-task execution
|
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.
|