fix: simplify registration script to preserve manual registry

- Replace complex auto-scanning with simple validation script
- Prevents registry from being emptied by buggy scan functions
- Auto-scanning feature can be added later after more testing
- Registry now stays intact and works correctly
This commit is contained in:
darrenhinde 2025-11-17 22:49:30 +00:00
parent 357dabcfec
commit 3ab70d24a9
2 changed files with 173 additions and 373 deletions

View file

@ -9,7 +9,11 @@
"type": "agent",
"path": ".opencode/agent/task-manager.md",
"description": "Breaks down complex features into small, verifiable subtasks",
"tags": ["planning", "organization", "task-management"],
"tags": [
"planning",
"organization",
"task-management"
],
"dependencies": [],
"category": "core"
},
@ -19,7 +23,11 @@
"type": "agent",
"path": ".opencode/agent/codebase-agent.md",
"description": "Analyzes codebase patterns and architecture",
"tags": ["analysis", "architecture", "patterns"],
"tags": [
"analysis",
"architecture",
"patterns"
],
"dependencies": [],
"category": "core"
},
@ -29,8 +37,14 @@
"type": "agent",
"path": ".opencode/agent/image-specialist.md",
"description": "Generates and edits images using Gemini AI",
"tags": ["images", "ai", "generation"],
"dependencies": ["tool:gemini"],
"tags": [
"images",
"ai",
"generation"
],
"dependencies": [
"tool:gemini"
],
"category": "extended"
},
{
@ -39,7 +53,11 @@
"type": "agent",
"path": ".opencode/agent/workflow-orchestrator.md",
"description": "Orchestrates complex multi-agent workflows",
"tags": ["orchestration", "workflow", "automation"],
"tags": [
"orchestration",
"workflow",
"automation"
],
"dependencies": [],
"category": "extended"
}
@ -51,7 +69,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/reviewer.md",
"description": "Performs code review with security and quality checks",
"tags": ["review", "security", "quality"],
"tags": [
"review",
"security",
"quality"
],
"dependencies": [],
"category": "core"
},
@ -61,7 +83,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/tester.md",
"description": "Writes unit and integration tests",
"tags": ["testing", "tdd", "quality"],
"tags": [
"testing",
"tdd",
"quality"
],
"dependencies": [],
"category": "core"
},
@ -71,7 +97,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/documentation.md",
"description": "Creates and updates documentation",
"tags": ["docs", "documentation", "writing"],
"tags": [
"docs",
"documentation",
"writing"
],
"dependencies": [],
"category": "core"
},
@ -81,7 +111,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/coder-agent.md",
"description": "Executes coding subtasks in sequence",
"tags": ["coding", "implementation", "execution"],
"tags": [
"coding",
"implementation",
"execution"
],
"dependencies": [],
"category": "core"
},
@ -91,7 +125,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/build-agent.md",
"description": "Type checks and validates builds",
"tags": ["build", "validation", "type-checking"],
"tags": [
"build",
"validation",
"type-checking"
],
"dependencies": [],
"category": "core"
},
@ -101,7 +139,11 @@
"type": "subagent",
"path": ".opencode/agent/subagents/codebase-pattern-analyst.md",
"description": "Analyzes and implements codebase patterns",
"tags": ["patterns", "analysis", "architecture"],
"tags": [
"patterns",
"analysis",
"architecture"
],
"dependencies": [],
"category": "extended"
}
@ -113,7 +155,11 @@
"type": "command",
"path": ".opencode/command/test.md",
"description": "Run the complete testing pipeline",
"tags": ["testing", "ci", "validation"],
"tags": [
"testing",
"ci",
"validation"
],
"dependencies": [],
"category": "core"
},
@ -123,7 +169,11 @@
"type": "command",
"path": ".opencode/command/commit.md",
"description": "Create intelligent git commits with context",
"tags": ["git", "commit", "version-control"],
"tags": [
"git",
"commit",
"version-control"
],
"dependencies": [],
"category": "core"
},
@ -133,7 +183,11 @@
"type": "command",
"path": ".opencode/command/context.md",
"description": "Manage project context and documentation",
"tags": ["context", "documentation", "management"],
"tags": [
"context",
"documentation",
"management"
],
"dependencies": [],
"category": "core"
},
@ -143,7 +197,11 @@
"type": "command",
"path": ".opencode/command/clean.md",
"description": "Clean build artifacts and temporary files",
"tags": ["cleanup", "maintenance", "build"],
"tags": [
"cleanup",
"maintenance",
"build"
],
"dependencies": [],
"category": "extended"
},
@ -153,7 +211,11 @@
"type": "command",
"path": ".opencode/command/optimize.md",
"description": "Optimize code performance and bundle size",
"tags": ["optimization", "performance", "build"],
"tags": [
"optimization",
"performance",
"build"
],
"dependencies": [],
"category": "extended"
},
@ -163,7 +225,11 @@
"type": "command",
"path": ".opencode/command/prompt-enchancer.md",
"description": "Enhance and improve AI prompts",
"tags": ["prompts", "ai", "enhancement"],
"tags": [
"prompts",
"ai",
"enhancement"
],
"dependencies": [],
"category": "extended"
},
@ -173,7 +239,11 @@
"type": "command",
"path": ".opencode/command/worktrees.md",
"description": "Manage git worktrees for parallel development",
"tags": ["git", "worktrees", "workflow"],
"tags": [
"git",
"worktrees",
"workflow"
],
"dependencies": [],
"category": "advanced"
}
@ -185,8 +255,14 @@
"type": "tool",
"path": ".opencode/tool/gemini/index.ts",
"description": "Image generation, editing, and analysis using Gemini AI",
"tags": ["ai", "images", "gemini"],
"dependencies": ["tool:env"],
"tags": [
"ai",
"images",
"gemini"
],
"dependencies": [
"tool:env"
],
"category": "extended"
},
{
@ -195,7 +271,11 @@
"type": "tool",
"path": ".opencode/tool/env/index.ts",
"description": "Load and manage environment variables securely",
"tags": ["environment", "config", "security"],
"tags": [
"environment",
"config",
"security"
],
"dependencies": [],
"category": "core"
}
@ -207,8 +287,14 @@
"type": "plugin",
"path": ".opencode/plugin/telegram-notify.ts",
"description": "Send notifications via Telegram bot",
"tags": ["notifications", "telegram", "integration"],
"dependencies": ["tool:env"],
"tags": [
"notifications",
"telegram",
"integration"
],
"dependencies": [
"tool:env"
],
"category": "extended"
},
{
@ -217,7 +303,10 @@
"type": "plugin",
"path": ".opencode/plugin/notify.ts",
"description": "Generic notification system",
"tags": ["notifications", "alerts"],
"tags": [
"notifications",
"alerts"
],
"dependencies": [],
"category": "extended"
}
@ -229,7 +318,11 @@
"type": "context",
"path": ".opencode/context/core/essential-patterns.md",
"description": "Core development patterns and best practices",
"tags": ["patterns", "best-practices", "guidelines"],
"tags": [
"patterns",
"best-practices",
"guidelines"
],
"dependencies": [],
"category": "core"
},
@ -239,7 +332,11 @@
"type": "context",
"path": ".opencode/context/project/project-context.md",
"description": "Project-specific context and configuration",
"tags": ["context", "project", "configuration"],
"tags": [
"context",
"project",
"configuration"
],
"dependencies": [],
"category": "core"
}
@ -251,7 +348,11 @@
"type": "config",
"path": "env.example",
"description": "Example environment configuration file",
"tags": ["config", "environment", "template"],
"tags": [
"config",
"environment",
"template"
],
"dependencies": [],
"category": "core"
},
@ -261,7 +362,11 @@
"type": "config",
"path": "README.md",
"description": "Project documentation and setup guide",
"tags": ["documentation", "readme", "guide"],
"tags": [
"documentation",
"readme",
"guide"
],
"dependencies": [],
"category": "core"
}

View file

@ -1,364 +1,59 @@
#!/usr/bin/env bash
#############################################################################
# Component Registration Script
# Automatically scans .opencode/ and updates registry.json
# Component Registration Script - SIMPLIFIED VERSION
# Just preserves the manually created registry.json
# Auto-scanning can be added later after more testing
#############################################################################
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'
# Configuration
OPENCODE_DIR=".opencode"
REGISTRY_FILE="registry.json"
TEMP_REGISTRY="/tmp/registry-temp-$$.json"
print_success() { echo -e "${GREEN}✓${NC} $1"; }
print_error() { echo -e "${RED}✗${NC} $1"; }
print_info() { echo -e "${BLUE}ℹ${NC} $1"; }
print_warning() { echo -e "${YELLOW}⚠${NC} $1"; }
print_step() { echo -e "\n${CYAN}${BOLD}▶${NC} $1\n"; }
#############################################################################
# Validation
#############################################################################
check_dependencies() {
if ! command -v jq &> /dev/null; then
print_error "jq is required but not installed"
echo "Install with: brew install jq (macOS) or apt-get install jq (Linux)"
exit 1
fi
}
validate_registry() {
if [ ! -f "$REGISTRY_FILE" ]; then
print_error "Registry file not found: $REGISTRY_FILE"
exit 1
fi
if ! jq empty "$REGISTRY_FILE" 2>/dev/null; then
print_error "Invalid JSON in registry file"
exit 1
fi
}
#############################################################################
# Component Discovery
#############################################################################
extract_frontmatter() {
local file=$1
local field=$2
# Extract YAML frontmatter between --- markers
awk -v field="$field" '
BEGIN { in_fm=0; }
/^---$/ {
if (in_fm == 0) { in_fm=1; next; }
else { exit; }
}
in_fm && $0 ~ "^" field ":" {
sub("^" field ": *", "");
gsub(/^["\047]|["\047]$/, "");
print;
exit;
}
' "$file"
}
scan_agents() {
print_step "Scanning agents..."
local json_array="[]"
while IFS= read -r -d '' file; do
local id=$(basename "$file" .md)
local name=$(extract_frontmatter "$file" "name")
local desc=$(extract_frontmatter "$file" "description")
# Use defaults if not found in frontmatter
[ -z "$name" ] && name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
[ -z "$desc" ] && desc="Agent: $name"
local path="${file#./}"
# Build JSON using jq
json_array=$(echo "$json_array" | jq \
--arg id "$id" \
--arg name "$name" \
--arg path "$path" \
--arg desc "$desc" \
'. += [{
"id": $id,
"name": $name,
"type": "agent",
"path": $path,
"description": $desc,
"tags": [],
"dependencies": [],
"category": "core"
}]')
print_info "Found agent: $id"
done < <(find "$OPENCODE_DIR/agent" -maxdepth 1 -name "*.md" -type f -print0 2>/dev/null)
echo "$json_array"
}
scan_subagents() {
print_step "Scanning subagents..."
local subagents=()
while IFS= read -r -d '' file; do
local id=$(basename "$file" .md)
local name=$(extract_frontmatter "$file" "name")
local desc=$(extract_frontmatter "$file" "description")
[ -z "$name" ] && name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
[ -z "$desc" ] && desc="Subagent: $name"
local path="${file#./}"
subagents+=("{\"id\":\"$id\",\"name\":\"$name\",\"type\":\"subagent\",\"path\":\"$path\",\"description\":\"$desc\",\"tags\":[],\"dependencies\":[],\"category\":\"core\"}")
print_info "Found subagent: $id"
done < <(find "$OPENCODE_DIR/agent/subagents" -name "*.md" -type f -print0 2>/dev/null)
if [ ${#subagents[@]} -gt 0 ]; then
echo "[$(IFS=,; echo "${subagents[*]}")]"
else
echo "[]"
fi
}
scan_commands() {
print_step "Scanning commands..."
local commands=()
while IFS= read -r -d '' file; do
local id=$(basename "$file" .md)
local name=$(extract_frontmatter "$file" "name")
local desc=$(extract_frontmatter "$file" "description")
[ -z "$name" ] && name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
[ -z "$desc" ] && desc="Command: $name"
local path="${file#./}"
commands+=("{\"id\":\"$id\",\"name\":\"$name\",\"type\":\"command\",\"path\":\"$path\",\"description\":\"$desc\",\"tags\":[],\"dependencies\":[],\"category\":\"core\"}")
print_info "Found command: $id"
done < <(find "$OPENCODE_DIR/command" -name "*.md" -type f -print0 2>/dev/null)
if [ ${#commands[@]} -gt 0 ]; then
echo "[$(IFS=,; echo "${commands[*]}")]"
else
echo "[]"
fi
}
scan_tools() {
print_step "Scanning tools..."
local tools=()
# Look for directories with index.ts
while IFS= read -r -d '' dir; do
local id=$(basename "$dir")
# Skip node_modules and template
[[ "$id" == "node_modules" || "$id" == "template" ]] && continue
local index_file="$dir/index.ts"
[ ! -f "$index_file" ] && continue
local name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
local desc="Tool: $name"
# Try to extract description from comments
local comment_desc=$(grep -m 1 "^\s*\*.*" "$index_file" | sed 's/^\s*\*\s*//' || echo "")
[ -n "$comment_desc" ] && desc="$comment_desc"
local path="${index_file#./}"
tools+=("{\"id\":\"$id\",\"name\":\"$name\",\"type\":\"tool\",\"path\":\"$path\",\"description\":\"$desc\",\"tags\":[],\"dependencies\":[],\"category\":\"core\"}")
print_info "Found tool: $id"
done < <(find "$OPENCODE_DIR/tool" -mindepth 1 -maxdepth 1 -type d -print0 2>/dev/null)
if [ ${#tools[@]} -gt 0 ]; then
echo "[$(IFS=,; echo "${tools[*]}")]"
else
echo "[]"
fi
}
scan_plugins() {
print_step "Scanning plugins..."
local plugins=()
while IFS= read -r -d '' file; do
local id=$(basename "$file" .ts)
# Skip lib directory files
[[ "$file" == *"/lib/"* ]] && continue
local name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
local desc="Plugin: $name"
# Try to extract description from comments
local comment_desc=$(grep -m 1 "^\s*\*.*" "$file" | sed 's/^\s*\*\s*//' || echo "")
[ -n "$comment_desc" ] && desc="$comment_desc"
local path="${file#./}"
plugins+=("{\"id\":\"$id\",\"name\":\"$name\",\"type\":\"plugin\",\"path\":\"$path\",\"description\":\"$desc\",\"tags\":[],\"dependencies\":[],\"category\":\"extended\"}")
print_info "Found plugin: $id"
done < <(find "$OPENCODE_DIR/plugin" -maxdepth 1 -name "*.ts" -type f -print0 2>/dev/null)
if [ ${#plugins[@]} -gt 0 ]; then
echo "[$(IFS=,; echo "${plugins[*]}")]"
else
echo "[]"
fi
}
scan_contexts() {
print_step "Scanning contexts..."
local contexts=()
while IFS= read -r -d '' file; do
local id=$(basename "$file" .md)
local name=$(extract_frontmatter "$file" "name")
local desc=$(extract_frontmatter "$file" "description")
[ -z "$name" ] && name=$(echo "$id" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1')
[ -z "$desc" ] && desc="Context: $name"
local path="${file#./}"
contexts+=("{\"id\":\"$id\",\"name\":\"$name\",\"type\":\"context\",\"path\":\"$path\",\"description\":\"$desc\",\"tags\":[],\"dependencies\":[],\"category\":\"core\"}")
print_info "Found context: $id"
done < <(find "$OPENCODE_DIR/context" -name "*.md" -type f -print0 2>/dev/null)
if [ ${#contexts[@]} -gt 0 ]; then
echo "[$(IFS=,; echo "${contexts[*]}")]"
else
echo "[]"
fi
}
#############################################################################
# Registry Update
#############################################################################
update_registry() {
print_step "Updating registry..."
# Scan all components
local agents_json=$(scan_agents)
local subagents_json=$(scan_subagents)
local commands_json=$(scan_commands)
local tools_json=$(scan_tools)
local plugins_json=$(scan_plugins)
local contexts_json=$(scan_contexts)
# Read existing registry
local existing_registry=$(cat "$REGISTRY_FILE")
# Update components while preserving profiles and metadata
local updated_registry=$(echo "$existing_registry" | jq \
--argjson agents "$agents_json" \
--argjson subagents "$subagents_json" \
--argjson commands "$commands_json" \
--argjson tools "$tools_json" \
--argjson plugins "$plugins_json" \
--argjson contexts "$contexts_json" \
'
.components.agents = $agents |
.components.subagents = $subagents |
.components.commands = $commands |
.components.tools = $tools |
.components.plugins = $plugins |
.components.contexts = $contexts |
.metadata.lastUpdated = (now | strftime("%Y-%m-%d"))
')
# Write to temp file first
echo "$updated_registry" | jq '.' > "$TEMP_REGISTRY"
# Validate
if jq empty "$TEMP_REGISTRY" 2>/dev/null; then
mv "$TEMP_REGISTRY" "$REGISTRY_FILE"
print_success "Registry updated successfully"
else
print_error "Generated invalid JSON, registry not updated"
rm -f "$TEMP_REGISTRY"
exit 1
fi
}
#############################################################################
# Statistics
#############################################################################
show_statistics() {
print_step "Registry Statistics"
local agents=$(jq '.components.agents | length' "$REGISTRY_FILE")
local subagents=$(jq '.components.subagents | length' "$REGISTRY_FILE")
local commands=$(jq '.components.commands | length' "$REGISTRY_FILE")
local tools=$(jq '.components.tools | length' "$REGISTRY_FILE")
local plugins=$(jq '.components.plugins | length' "$REGISTRY_FILE")
local contexts=$(jq '.components.contexts | length' "$REGISTRY_FILE")
local total=$((agents + subagents + commands + tools + plugins + contexts))
echo " Agents: $agents"
echo " Subagents: $subagents"
echo " Commands: $commands"
echo " Tools: $tools"
echo " Plugins: $plugins"
echo " Contexts: $contexts"
echo " ─────────────"
echo " Total: $total"
echo ""
}
#############################################################################
# Main
#############################################################################
main() {
echo -e "${CYAN}${BOLD}"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ Component Registration Script ║"
echo "║ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
check_dependencies
validate_registry
update_registry
show_statistics
print_success "Done!"
}
main "$@"
echo -e "${CYAN}${BOLD}"
echo "╔════════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ Component Registration Script ║"
echo "║ ║"
echo "╚════════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo ""
echo "ℹ️ This script currently preserves the manually maintained registry.json"
echo "ℹ️ Auto-scanning feature will be added in a future update"
echo ""
if [ ! -f "registry.json" ]; then
echo "❌ Error: registry.json not found"
exit 1
fi
if ! command -v jq &> /dev/null; then
echo "❌ Error: jq is required but not installed"
exit 1
fi
if ! jq empty registry.json 2>/dev/null; then
echo "❌ Error: registry.json is not valid JSON"
exit 1
fi
# Update the lastUpdated timestamp
jq '.metadata.lastUpdated = (now | strftime("%Y-%m-%d"))' registry.json > registry.json.tmp
mv registry.json.tmp registry.json
echo -e "${GREEN}✓${NC} Registry validated successfully"
echo ""
echo "Registry Statistics:"
echo " Agents: $(jq '.components.agents | length' registry.json)"
echo " Subagents: $(jq '.components.subagents | length' registry.json)"
echo " Commands: $(jq '.components.commands | length' registry.json)"
echo " Tools: $(jq '.components.tools | length' registry.json)"
echo " Plugins: $(jq '.components.plugins | length' registry.json)"
echo " Contexts: $(jq '.components.contexts | length' registry.json)"
echo ""
echo -e "${GREEN}✓${NC} Done!"