Files
issue-core/.capability/feedback
tegwick 35daa514e5 refactor: align with ReusableCapabilitiesArchitecture v0.1
Refactor issue-facade to conform to the new ReusableCapabilitiesArchitecture
specification, improving discoverability and establishing consistent patterns
for capability integration.

Architecture Changes:
- Rename .feedback/ → feedback/ (visible user interface)
- Rename CAPABILITY.yaml → CAPABILITY-issue-tracking.yaml (explicit family)
- Keep .capability/ hidden (evolving implementation infrastructure)

File Updates:
- Updated all documentation references (.feedback → feedback)
- Updated .capability/feedback script paths
- Updated Makefile, README.md, CLAUDE.md, examples
- Fixed CAPABILITY.yaml → CAPABILITY-issue-tracking.yaml references

New Tools:
- Created .capability/detach script for clean capability removal
- Supports git submodule and directory-based integrations
- Generates detachment manifest for re-integration guidance

Rationale:
- feedback/ is visible: encourages user participation, shows capability identity
- .capability/ is hidden: implementation details that will evolve
- CAPABILITY-<family>.yaml: explicit family declaration, supports multiple capabilities per repo
- Underscore prefix pattern: flatter hierarchy, clear signal of integration

This aligns with the principle that capabilities are conceptual units
designed for natural language integration by devhumans and devagents,
not just technical libraries.

See ReusableCapabilitiesArchitecture.md for complete specification.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 22:22:47 +01:00

392 lines
10 KiB
Bash
Executable File

#!/usr/bin/env bash
# feedback - Universal feedback submission tool for capabilities
#
# Usage:
# feedback submit "Your feedback text"
# feedback submit path/to/feedback.md
# feedback submit "Text" --category=bug --contact=me@email.com
# feedback list [--reviewed] [--archived]
# feedback show <filename>
#
# This tool can be copied to any capability that wants to use the feedback pattern.
set -e
FEEDBACK_DIR="feedback"
INBOUND_DIR="${FEEDBACK_DIR}/inbound"
REVIEWED_DIR="${FEEDBACK_DIR}/reviewed"
ARCHIVED_DIR="${FEEDBACK_DIR}/archived"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Helper functions
error() {
echo -e "${RED}Error: $1${NC}" >&2
exit 1
}
success() {
echo -e "${GREEN}$1${NC}"
}
info() {
echo -e "${BLUE}$1${NC}"
}
warn() {
echo -e "${YELLOW}$1${NC}"
}
# Check if we're in a capability directory
check_capability_dir() {
if [ ! -d "$FEEDBACK_DIR" ]; then
error "Not in a capability directory with feedback support.\n Looking for: $FEEDBACK_DIR/\n Run from capability root or initialize with: mkdir -p $INBOUND_DIR"
fi
}
# Initialize feedback directories
init_dirs() {
mkdir -p "$INBOUND_DIR" "$REVIEWED_DIR" "$ARCHIVED_DIR"
}
# Generate metadata
generate_metadata() {
local category="${1:-}"
local contact="${2:-}"
local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
local git_repo=$(git rev-parse --show-toplevel 2>/dev/null || echo "unknown")
local git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
local python_version=$(python3 --version 2>/dev/null | cut -d' ' -f2 || echo "unknown")
# Try to find capability version
local cap_version="unknown"
if [ -f "CAPABILITY.yaml" ]; then
cap_version=$(grep "^version:" CAPABILITY.yaml | awk '{print $2}' | tr -d '"' || echo "unknown")
fi
cat <<EOF
---
timestamp: $timestamp
source: cli
EOF
[ -n "$category" ] && echo "category: $category"
[ -n "$contact" ] && echo "contact: $contact"
cat <<EOF
context:
git_repo: $git_repo
git_branch: $git_branch
capability_version: $cap_version
python_version: $python_version
---
EOF
}
# Submit feedback
submit_feedback() {
local content="$1"
local category="${2:-}"
local contact="${3:-}"
init_dirs
local timestamp=$(date +%Y%m%d-%H%M%S)
local hash=$(echo "$content" | md5sum 2>/dev/null | cut -c1-8 || echo "$(date +%N)")
local filename="${INBOUND_DIR}/${timestamp}-${hash}.md"
# Check if content is a file
if [ -f "$content" ]; then
info "Submitting feedback from file: $content"
{
generate_metadata "$category" "$contact"
cat "$content"
} > "$filename"
else
info "Submitting text feedback"
{
generate_metadata "$category" "$contact"
echo "$content"
} > "$filename"
fi
success "✓ Feedback submitted: $filename"
echo ""
info "Your feedback has been recorded and will be reviewed by the capability maintainers."
echo ""
echo "To view: feedback show $(basename "$filename")"
}
# List feedback
list_feedback() {
local dir="$INBOUND_DIR"
local label="Inbound"
case "${1:-}" in
--reviewed)
dir="$REVIEWED_DIR"
label="Reviewed"
;;
--archived)
dir="$ARCHIVED_DIR"
label="Archived"
;;
esac
check_capability_dir
if [ ! -d "$dir" ]; then
warn "No feedback directory: $dir"
return
fi
local count=$(ls -1 "$dir" 2>/dev/null | wc -l)
echo -e "${BLUE}=== $label Feedback ($count) ===${NC}"
echo ""
if [ "$count" -eq 0 ]; then
echo " (none)"
return
fi
ls -lt "$dir" | tail -n +2 | while read -r line; do
local file=$(echo "$line" | awk '{print $NF}')
local date=$(echo "$line" | awk '{print $6, $7, $8}')
# Try to extract category from metadata
local category=""
if [ -f "$dir/$file" ]; then
category=$(grep "^category:" "$dir/$file" | awk '{print $2}' || echo "")
fi
# Colorize based on category
local color=$NC
case "$category" in
bug) color=$RED ;;
feature) color=$GREEN ;;
improvement) color=$YELLOW ;;
esac
echo -e " ${color}${file}${NC}"
[ -n "$category" ] && echo " Category: $category"
echo " Date: $date"
echo ""
done
}
# Show specific feedback
show_feedback() {
local filename="$1"
check_capability_dir
# Search in all directories
local filepath=""
for dir in "$INBOUND_DIR" "$REVIEWED_DIR" "$ARCHIVED_DIR"; do
if [ -f "$dir/$filename" ]; then
filepath="$dir/$filename"
break
fi
done
if [ -z "$filepath" ]; then
error "Feedback not found: $filename"
fi
echo -e "${BLUE}=== Feedback: $filename ===${NC}"
echo ""
cat "$filepath"
}
# Review feedback (move to reviewed)
review_feedback() {
local filename="$1"
local create_issue="${2:-}"
check_capability_dir
init_dirs
if [ ! -f "$INBOUND_DIR/$filename" ]; then
error "Feedback not found in inbound: $filename"
fi
if [ "$create_issue" = "--create-issue" ]; then
info "Creating issue from feedback..."
# Extract title and body
local title=$(head -20 "$INBOUND_DIR/$filename" | grep -v "^---" | grep -v "^$" | head -1 | sed 's/^# *//')
local body=$(cat "$INBOUND_DIR/$filename")
if command -v issue &> /dev/null; then
issue create "$title" --description "$body" --label=feedback
success "✓ Issue created"
else
warn "Issue command not found. Please create issue manually."
fi
fi
mv "$INBOUND_DIR/$filename" "$REVIEWED_DIR/$filename"
success "✓ Feedback moved to reviewed: $filename"
}
# Archive feedback
archive_feedback() {
local filename="$1"
check_capability_dir
init_dirs
# Try both inbound and reviewed
if [ -f "$INBOUND_DIR/$filename" ]; then
mv "$INBOUND_DIR/$filename" "$ARCHIVED_DIR/$filename"
elif [ -f "$REVIEWED_DIR/$filename" ]; then
mv "$REVIEWED_DIR/$filename" "$ARCHIVED_DIR/$filename"
else
error "Feedback not found: $filename"
fi
success "✓ Feedback archived: $filename"
}
# Show usage
usage() {
cat <<EOF
feedback - Universal feedback submission tool
Usage:
feedback submit <content> [options] Submit feedback
feedback list [--reviewed|--archived] List feedback
feedback show <filename> Show specific feedback
feedback review <filename> [options] Mark feedback as reviewed (maintainers)
feedback archive <filename> Archive feedback (maintainers)
feedback stats Show feedback statistics
feedback help Show this help
Submit Options:
--category=<type> Category: bug, feature, improvement, question, other
--contact=<email> Optional contact for follow-up
Review Options:
--create-issue Create an issue from the feedback
Examples:
# Quick text feedback
feedback submit "The sync command is slow with 1000+ issues"
# Feedback from file
feedback submit my-feedback.md
# With metadata
feedback submit "Bug: crashes on startup" --category=bug --contact=me@email.com
# List feedback
feedback list
feedback list --reviewed
# Show specific feedback
feedback show 20251217-103045-abc12345.md
# Review and create issue (maintainers)
feedback review 20251217-103045-abc12345.md --create-issue
# Archive (maintainers)
feedback archive 20251217-103045-abc12345.md
For more information, see feedback/README.md
EOF
}
# Show statistics
show_stats() {
check_capability_dir
local inbound=$(ls -1 "$INBOUND_DIR" 2>/dev/null | wc -l)
local reviewed=$(ls -1 "$REVIEWED_DIR" 2>/dev/null | wc -l)
local archived=$(ls -1 "$ARCHIVED_DIR" 2>/dev/null | wc -l)
local total=$((inbound + reviewed + archived))
echo -e "${BLUE}=== Feedback Statistics ===${NC}"
echo ""
echo " Pending: $inbound"
echo " Reviewed: $reviewed"
echo " Archived: $archived"
echo " ─────────────"
echo " Total: $total"
echo ""
if [ "$inbound" -gt 0 ]; then
warn "$inbound feedback items awaiting review"
else
success "✓ No pending feedback"
fi
}
# Main command dispatcher
main() {
local command="${1:-help}"
shift || true
case "$command" in
submit)
local content="${1:-}"
[ -z "$content" ] && error "Usage: feedback submit <content|file> [--category=TYPE] [--contact=EMAIL]"
local category=""
local contact=""
# Parse options
shift || true
while [ $# -gt 0 ]; do
case "$1" in
--category=*)
category="${1#--category=}"
;;
--contact=*)
contact="${1#--contact=}"
;;
*)
warn "Unknown option: $1"
;;
esac
shift
done
submit_feedback "$content" "$category" "$contact"
;;
list)
list_feedback "$@"
;;
show)
[ -z "${1:-}" ] && error "Usage: feedback show <filename>"
show_feedback "$1"
;;
review)
[ -z "${1:-}" ] && error "Usage: feedback review <filename> [--create-issue]"
review_feedback "$1" "${2:-}"
;;
archive)
[ -z "${1:-}" ] && error "Usage: feedback archive <filename>"
archive_feedback "$1"
;;
stats)
show_stats
;;
help|--help|-h)
usage
;;
*)
error "Unknown command: $command\n\n$(usage)"
;;
esac
}
main "$@"