From d17eb13f337f7eae5fa7d6095d89e4b4ab448372 Mon Sep 17 00:00:00 2001 From: darrenhinde <107584450+darrenhinde@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:18:58 +0000 Subject: [PATCH 1/2] fix(install): resolve custom install failures and missing agent-metadata (#237, #277) Fix custom install mode breaking all components by mapping plural category names to singular types. Add agent-metadata.json to registry config section and all profiles. Clean up registry data quality issues including duplicate context IDs, description artifacts, and schema inconsistencies. Co-Authored-By: Claude Opus 4.6 --- install.sh | 55 ++++++++++++++++++++++++------------- registry.json | 76 +++++++++++++++++++++++++++++---------------------- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/install.sh b/install.sh index c08b37b7..469b68db 100755 --- a/install.sh +++ b/install.sh @@ -297,13 +297,20 @@ get_profile_components() { get_component_info() { local component_id=$1 local component_type=$2 - + local registry_key + registry_key=$(get_registry_key "$component_type") + if [ "$component_type" = "context" ] && [[ "$component_id" == */* ]]; then - jq_exec "first(.components.contexts[]? | select(.path == \".opencode/context/${component_id}.md\"))" "$TEMP_DIR/registry.json" + local result + result=$(jq_exec "first(.components.contexts[]? | select(.path == \".opencode/context/${component_id}.md\"))" "$TEMP_DIR/registry.json") + if [ -z "$result" ] || [ "$result" = "null" ]; then + result=$(jq_exec "first(.components.contexts[]? | select(.path == \".opencode/context/${component_id}\"))" "$TEMP_DIR/registry.json") + fi + echo "$result" return fi - jq_exec ".components.${component_type}[]? | select(.id == \"${component_id}\" or (.aliases // [] | index(\"${component_id}\")))" "$TEMP_DIR/registry.json" + jq_exec ".components.${registry_key}[]? | select(.id == \"${component_id}\" or (.aliases // [] | index(\"${component_id}\")))" "$TEMP_DIR/registry.json" } resolve_component_path() { @@ -554,9 +561,7 @@ show_install_location_menu() { fi local normalized_path - normalized_path=$(normalize_and_validate_path "$custom_path") - - if ! normalize_and_validate_path "$custom_path" > /dev/null; then + if ! normalized_path=$(normalize_and_validate_path "$custom_path"); then print_error "Invalid path" sleep 2 show_install_location_menu @@ -753,6 +758,9 @@ show_custom_menu() { read -r -p "Enter category numbers (space-separated) or option: " -a selections for sel in "${selections[@]}"; do + if [[ ! "$sel" =~ ^[0-9]+$ ]]; then + continue + fi if [ "$sel" -eq $((${#categories[@]}+1)) ]; then selected_categories=("${categories[@]}") break @@ -804,7 +812,19 @@ show_component_selection() { echo " ${idx}) ${comp_name}" echo " ${comp_desc}" - all_components+=("${category}:${comp_id}") + local singular_type + case "$category" in + agents) singular_type="agent" ;; + subagents) singular_type="subagent" ;; + commands) singular_type="command" ;; + tools) singular_type="tool" ;; + plugins) singular_type="plugin" ;; + skills) singular_type="skill" ;; + contexts) singular_type="context" ;; + config) singular_type="config" ;; + *) singular_type="${category%s}" ;; + esac + all_components+=("${singular_type}:${comp_id}") component_details+=("${comp_name}|${comp_desc}") idx=$((idx+1)) @@ -822,7 +842,7 @@ show_component_selection() { break elif [ "$sel" = "done" ]; then break - elif [ "$sel" -ge 1 ] && [ "$sel" -le ${#all_components[@]} ]; then + elif [[ "$sel" =~ ^[0-9]+$ ]] && [ "$sel" -ge 1 ] && [ "$sel" -le ${#all_components[@]} ]; then SELECTED_COMPONENTS+=("${all_components[$((sel-1))]}") fi done @@ -1023,11 +1043,9 @@ perform_installation() { for comp in "${SELECTED_COMPONENTS[@]}"; do local type="${comp%%:*}" local id="${comp##*:}" - local registry_key - registry_key=$(get_registry_key "$type") local path path=$(resolve_component_path "$type" "$id") - + if [ -n "$path" ] && [ "$path" != "null" ]; then local install_path install_path=$(get_install_path "$path") @@ -1097,13 +1115,13 @@ perform_installation() { local type="${comp%%:*}" local id="${comp##*:}" - # Get the correct registry key (handles singular/plural) - local registry_key - registry_key=$(get_registry_key "$type") - - # Get component path + # Get component path (registry key resolved internally) local path path=$(resolve_component_path "$type" "$id") + + # Registry key needed for multi-file (skills) lookup + local registry_key + registry_key=$(get_registry_key "$type") if [ -z "$path" ] || [ "$path" = "null" ]; then print_warning "Could not find path for ${comp}" @@ -1288,7 +1306,7 @@ list_components() { echo -e "${BOLD}Available Components${NC}\n" - local categories=("agents" "subagents" "commands" "tools" "plugins" "skills" "contexts") + local categories=("agents" "subagents" "commands" "tools" "plugins" "skills" "contexts" "config") for category in "${categories[@]}"; do local cat_display @@ -1443,8 +1461,7 @@ main() { # Apply custom install directory if specified (CLI arg overrides env var) if [ -n "$CUSTOM_INSTALL_DIR" ]; then local normalized_path - if normalize_and_validate_path "$CUSTOM_INSTALL_DIR" > /dev/null; then - normalized_path=$(normalize_and_validate_path "$CUSTOM_INSTALL_DIR") + if normalized_path=$(normalize_and_validate_path "$CUSTOM_INSTALL_DIR"); then INSTALL_DIR="$normalized_path" if ! validate_install_path "$INSTALL_DIR"; then print_warning "Installation path may have issues, but continuing..." diff --git a/registry.json b/registry.json index ad73ccd5..51fcd4bd 100644 --- a/registry.json +++ b/registry.json @@ -579,7 +579,7 @@ "name": "Test New Command", "type": "command", "path": ".opencode/command/test-new-command.md", - "description": "Test command to verify auto-detection and registry updates work correctly\\\"", + "description": "Test command to verify auto-detection and registry updates work correctly", "tags": [], "dependencies": [], "category": "standard" @@ -589,7 +589,7 @@ "name": "Commit OpenAgents Control", "type": "command", "path": ".opencode/command/commit-openagents.md", - "description": "description: Smart commit command for opencode-agents repository with automatic validation and conventional commits", + "description": "Smart commit command for opencode-agents repository with automatic validation and conventional commits", "tags": [], "dependencies": [], "category": "standard" @@ -599,7 +599,7 @@ "name": "Prompt Optimizer", "type": "command", "path": ".opencode/command/prompt-engineering/prompt-optimizer.md", - "description": "Advanced prompt optimizer: Research patterns + token efficiency + semantic preservation. Achieves 30-50% token reduction with 100% meaning preserved.\\\"", + "description": "Advanced prompt optimizer: Research patterns + token efficiency + semantic preservation. Achieves 30-50% token reduction with 100% meaning preserved.", "tags": [], "dependencies": [], "category": "standard" @@ -609,7 +609,7 @@ "name": "Create Tests", "type": "command", "path": ".opencode/command/openagents/new-agents/create-tests.md", - "description": "description: \\\"Generate comprehensive test suites for OpenCode agents with 8 essential test types\\\"", + "description": "Generate comprehensive test suites for OpenCode agents with 8 essential test types", "tags": [], "dependencies": [], "category": "standard" @@ -619,7 +619,7 @@ "name": "Create Agent", "type": "command", "path": ".opencode/command/openagents/new-agents/create-agent.md", - "description": "description: \\\"Create new OpenCode agents following research-backed best practices (Anthropic 2025)\\\"", + "description": "Create new OpenCode agents following research-backed best practices (Anthropic 2025)", "tags": [], "dependencies": [], "category": "standard" @@ -650,6 +650,7 @@ "patterns", "refactoring" ], + "dependencies": [], "category": "standard" } ], @@ -1256,7 +1257,7 @@ "category": "standard" }, { - "id": "agents", + "id": "plugin-agents", "name": "Agents", "type": "context", "path": ".opencode/context/openagents-repo/plugins/context/capabilities/agents.md", @@ -2133,6 +2134,7 @@ "development", "patterns" ], + "dependencies": [], "category": "standard" }, { @@ -2145,6 +2147,7 @@ "learning", "guide" ], + "dependencies": [], "category": "standard" }, { @@ -2157,6 +2160,7 @@ "product", "guide" ], + "dependencies": [], "category": "standard" }, { @@ -2169,10 +2173,11 @@ "data", "guide" ], + "dependencies": [], "category": "standard" }, { - "id": "context-bundle-template", + "id": "context-bundle-template-alt", "name": "Context Bundle Template", "type": "context", "path": ".opencode/context/openagents-repo/templates/context-bundle-template.md", @@ -2182,6 +2187,7 @@ "context", "bundle" ], + "dependencies": [], "category": "standard" }, { @@ -2198,7 +2204,6 @@ "dependencies" ], "dependencies": [ - "context:external-libraries-workflow", "context:adding-agent-basics", "context:adding-skill-basics" ], @@ -2413,7 +2418,7 @@ "category": "navigation" }, { - "id": "ui-navigation", + "id": "ui-nav-patterns", "name": "Navigation: UI", "type": "context", "path": ".opencode/context/ui/navigation.md", @@ -2652,10 +2657,11 @@ "name": "Agent Metadata", "type": "context", "path": ".opencode/context/openagents-repo/core-concepts/agent-metadata.md", - "description": "...\\\" # \u2705 Valid OpenCode field", + "description": "Centralized metadata schema for OpenAgents Control agents — registry management, documentation, and tooling", "tags": [ - "development", - "coding" + "metadata", + "registry", + "agents" ], "dependencies": [], "category": "standard" @@ -3102,6 +3108,20 @@ ], "dependencies": [], "category": "essential" + }, + { + "id": "agent-metadata-config", + "name": "Agent Metadata Configuration", + "type": "config", + "path": ".opencode/config/agent-metadata.json", + "description": "Centralized metadata for OpenAgents Control agents — used for registry management, installation, and documentation", + "tags": [ + "config", + "metadata", + "agents" + ], + "dependencies": [], + "category": "essential" } ] }, @@ -3133,7 +3153,8 @@ "context:workflows-review", "context:system-context-guide", "context:adding-skill-basics", - "config:env-example" + "config:env-example", + "config:agent-metadata-config" ] }, "developer": { @@ -3180,7 +3201,8 @@ "context:api-design", "config:env-example", "config:readme", - "context:openagents-repo/*" + "context:openagents-repo/*", + "config:agent-metadata-config" ] }, "business": { @@ -3210,7 +3232,8 @@ "context:project-intelligence/*", "context:adding-skill-basics", "config:env-example", - "config:readme" + "config:readme", + "config:agent-metadata-config" ] }, "full": { @@ -3265,7 +3288,8 @@ "context:api-design", "config:env-example", "config:readme", - "context:openagents-repo/*" + "context:openagents-repo/*", + "config:agent-metadata-config" ] }, "advanced": { @@ -3338,7 +3362,8 @@ "context:frontmatter", "context:codebase-references", "config:env-example", - "config:readme" + "config:readme", + "config:agent-metadata-config" ], "additionalPaths": [ ".Building/", @@ -3348,21 +3373,6 @@ }, "metadata": { "lastUpdated": "2026-01-31", - "schemaVersion": "1.0.0" - }, - "subagents": { - "test": { - "simple-responder": { - "id": "simple-responder", - "name": "Simple Responder", - "description": "Test agent that responds with AWESOME TESTING", - "category": "test", - "type": "utility", - "version": "1.0.0", - "path": ".opencode/agent/subagents/test/simple-responder.md", - "mode": "subagent", - "status": "stable" - } - } + "schemaVersion": "2.0.0" } } From 9d935b3aa04cb17b62f1e7e7ce709f5038a5fffc Mon Sep 17 00:00:00 2001 From: darrenhinde <107584450+darrenhinde@users.noreply.github.com> Date: Wed, 25 Mar 2026 00:27:07 +0000 Subject: [PATCH 2/2] fix(install): correct root-path routing, display counter, and duplicate trap Fix get_install_path misrouting root-level config files (env.example, README.md) into INSTALL_DIR instead of project root. Fix custom install display counter resetting per category. Remove duplicate INT/TERM trap. Co-Authored-By: Claude Opus 4.6 --- install.sh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/install.sh b/install.sh index 469b68db..bfdca598 100755 --- a/install.sh +++ b/install.sh @@ -65,7 +65,7 @@ INSTALL_DIR="${OPENCODE_INSTALL_DIR:-.opencode}" # Allow override via environme TEMP_DIR="/tmp/opencode-installer-$$" # Cleanup temp directory on exit (success or failure) -trap 'rm -rf "$TEMP_DIR" 2>/dev/null || true' EXIT INT TERM +trap 'rm -rf "$TEMP_DIR" 2>/dev/null || true' EXIT # Global variables SELECTED_COMPONENTS=() @@ -351,8 +351,12 @@ get_install_path() { local registry_path=$1 # Strip leading .opencode/ if present local relative_path="${registry_path#.opencode/}" - # Return INSTALL_DIR + relative path - echo "${INSTALL_DIR}/${relative_path}" + # If path didn't start with .opencode/, it's a root-relative path (e.g. env.example, README.md) + if [ "$relative_path" = "$registry_path" ]; then + echo "./${registry_path}" + else + echo "${INSTALL_DIR}/${relative_path}" + fi } expand_context_wildcard() { @@ -794,15 +798,14 @@ show_component_selection() { local all_components=() local component_details=() + local idx=1 for category in "${categories[@]}"; do local cat_display cat_display=$(echo "$category" | awk '{print toupper(substr($0,1,1)) tolower(substr($0,2))}') echo -e "${CYAN}${BOLD}${cat_display}:${NC}" - + local components components=$(jq_exec ".components.${category}[]? | .id" "$TEMP_DIR/registry.json") - - local idx=1 while IFS= read -r comp_id; do local comp_name comp_name=$(jq_exec ".components.${category}[]? | select(.id == \"${comp_id}\") | .name" "$TEMP_DIR/registry.json")