diff --git a/.opencode/agent/meta/repo-manager.md b/.opencode/agent/meta/repo-manager.md index debae9a..be146eb 100644 --- a/.opencode/agent/meta/repo-manager.md +++ b/.opencode/agent/meta/repo-manager.md @@ -47,9 +47,9 @@ tags: - Request approval before ANY execution (bash, write, edit, task) + Request approval before ANY execution (bash, write, edit, task) , ContextScout is exempt from this rule. EXCEPTION: Discovery tasks (ContextScout, explore) and read/list/grep/glob tools do NOT require approval. - You don't need approval to use the ContextScout tool. Use it as much as you need to. + You don't need approval to use the ContextScout tool. Use it as much as you need to. Never ask for approval to use ContextScout. diff --git a/.opencode/context/openagents-repo/guides/resolving-installer-wildcard-failures.md b/.opencode/context/openagents-repo/guides/resolving-installer-wildcard-failures.md new file mode 100644 index 0000000..ce49a5f --- /dev/null +++ b/.opencode/context/openagents-repo/guides/resolving-installer-wildcard-failures.md @@ -0,0 +1,57 @@ +# Guide: Resolving Installer Wildcard Failures + +**Purpose**: Capture the root cause, fix, and lessons from wildcard context install failures. + +**Last Updated**: 2026-01-12 + +--- + +## Prerequisites +- Installer changes scoped to `install.sh` +- Registry entries validated (`./scripts/registry/validate-registry.sh`) + +**Estimated time**: 10 min + +## Steps + +### 1. Identify the failure mode +**Symptom**: +``` +curl: (3) URL rejected: Malformed input to a URL function +``` +**Cause**: Wildcard expansion returned context IDs that weren’t path-aligned (e.g., `standards-code` mapped to `.opencode/context/core/standards/code-quality.md`). Installer treated IDs as paths. + +### 2. Expand wildcards to path-based IDs +**Goal**: Make wildcard expansion output `core/...` IDs that map directly to a path. + +**Update**: +- Expand `context:core/*` to `core/standards/code-quality` style IDs + +### 3. Resolve context paths deterministically +**Goal**: Avoid ambiguous matches and ensure one registry entry is used. + +**Update**: +- Add `resolve_component_path` to map context IDs to the registry path +- Use `first(...)` in jq queries for deterministic selection + +### 4. Verify installation +```bash +bash scripts/tests/test-e2e-install.sh +``` +**Expected**: All E2E tests pass on macOS and Ubuntu. + +## Verification +```bash +REGISTRY_URL="file://$(pwd)/registry.json" ./install.sh --list +``` + +## Troubleshooting +| Issue | Solution | +|-------|----------| +| `Malformed input to a URL function` | Ensure wildcard expansion returns `core/...` IDs and uses `resolve_component_path` | +| Multiple context entries for one path | Use `first(...)` in jq lookups | + +## Related +- guides/debugging.md +- guides/updating-registry.md +- core-concepts/registry.md diff --git a/.opencode/context/openagents-repo/navigation.md b/.opencode/context/openagents-repo/navigation.md index 798453b..6e955f5 100644 --- a/.opencode/context/openagents-repo/navigation.md +++ b/.opencode/context/openagents-repo/navigation.md @@ -47,6 +47,7 @@ | `guides/testing-agent.md` | How to test agents | ⭐⭐⭐⭐ | | `guides/updating-registry.md` | How to update registry | ⭐⭐⭐ | | `guides/debugging.md` | How to debug issues | ⭐⭐⭐ | +| `guides/resolving-installer-wildcard-failures.md` | Fix wildcard context install failures | ⭐⭐⭐ | | `guides/creating-release.md` | How to create releases | ⭐⭐ | **When to read**: When performing specific tasks diff --git a/install.sh b/install.sh index a1f0626..572d583 100755 --- a/install.sh +++ b/install.sh @@ -298,7 +298,26 @@ get_component_info() { local component_id=$1 local component_type=$2 - jq_exec ".components.${component_type}[]? | select(.id == \"${component_id}\")" "$TEMP_DIR/registry.json" + if [ "$component_type" = "context" ] && [[ "$component_id" == */* ]]; then + jq_exec "first(.components.contexts[]? | select(.path == \".opencode/context/${component_id}.md\"))" "$TEMP_DIR/registry.json" + return + fi + + jq_exec ".components.${component_type}[]? | select(.id == \"${component_id}\" or (.aliases // [] | index(\"${component_id}\")))" "$TEMP_DIR/registry.json" +} + +resolve_component_path() { + local component_type=$1 + local component_id=$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\") | .path)" "$TEMP_DIR/registry.json" + return + fi + + jq_exec ".components.${registry_key}[]? | select(.id == \"${component_id}\" or (.aliases // [] | index(\"${component_id}\"))) | .path" "$TEMP_DIR/registry.json" } # Helper function to get the correct registry key for a component type @@ -322,6 +341,65 @@ get_install_path() { echo "${INSTALL_DIR}/${relative_path}" } +expand_context_wildcard() { + local pattern=$1 + local prefix="${pattern%%\**}" + + prefix="${prefix%/}" + if [ -n "$prefix" ]; then + prefix="${prefix}/" + fi + + jq_exec ".components.contexts[]? | select(.path | startswith(\".opencode/context/${prefix}\")) | .path | sub(\"^\\\\.opencode/context/\"; \"\") | sub(\"\\\\.md$\"; \"\")" "$TEMP_DIR/registry.json" +} + +expand_selected_components() { + local expanded=() + + for comp in "${SELECTED_COMPONENTS[@]}"; do + local type="${comp%%:*}" + local id="${comp##*:}" + + if [[ "$id" == *"*"* ]]; then + if [ "$type" != "context" ]; then + print_warning "Wildcard only supported for context components: ${comp}" + continue + fi + + local matches + matches=$(expand_context_wildcard "$id") + + if [ -z "$matches" ]; then + print_warning "No contexts matched: ${comp}" + continue + fi + + while IFS= read -r match; do + [ -n "$match" ] && expanded+=("context:${match}") + done <<< "$matches" + continue + fi + + expanded+=("$comp") + done + + local deduped=() + for comp in "${expanded[@]}"; do + local found=0 + for existing in "${deduped[@]}"; do + if [ "$existing" = "$comp" ]; then + found=1 + break + fi + done + if [ "$found" -eq 0 ]; then + deduped+=("$comp") + fi + done + + SELECTED_COMPONENTS=("${deduped[@]}") +} + resolve_dependencies() { local component=$1 local type="${component%%:*}" @@ -333,10 +411,41 @@ resolve_dependencies() { # Get dependencies for this component local deps - deps=$(jq_exec ".components.${registry_key}[] | select(.id == \"${id}\") | .dependencies[]?" "$TEMP_DIR/registry.json" 2>/dev/null || echo "") + deps=$(jq_exec ".components.${registry_key}[] | select(.id == \"${id}\" or (.aliases // [] | index(\"${id}\"))) | .dependencies[]?" "$TEMP_DIR/registry.json" 2>/dev/null || echo "") if [ -n "$deps" ]; then for dep in $deps; do + if [[ "$dep" == *"*"* ]]; then + local dep_type="${dep%%:*}" + local dep_id="${dep##*:}" + + if [ "$dep_type" = "context" ]; then + local matched + matched=$(expand_context_wildcard "$dep_id") + + if [ -z "$matched" ]; then + print_warning "No contexts matched dependency: ${dep}" + continue + fi + + while IFS= read -r match; do + local expanded_dep="context:${match}" + local found=0 + for existing in "${SELECTED_COMPONENTS[@]}"; do + if [ "$existing" = "$expanded_dep" ]; then + found=1 + break + fi + done + if [ "$found" -eq 0 ]; then + SELECTED_COMPONENTS+=("$expanded_dep") + resolve_dependencies "$expanded_dep" + fi + done <<< "$matched" + continue + fi + fi + # Add dependency if not already in list local found=0 for existing in "${SELECTED_COMPONENTS[@]}"; do @@ -585,6 +694,8 @@ show_profile_menu() { while IFS= read -r component; do [ -n "$component" ] && SELECTED_COMPONENTS+=("$component") done < "$temp_file" + + expand_selected_components # Resolve dependencies for profile installs print_step "Resolving dependencies..." @@ -908,7 +1019,7 @@ perform_installation() { local registry_key registry_key=$(get_registry_key "$type") local path - path=$(jq_exec ".components.${registry_key}[]? | select(.id == \"${id}\") | .path" "$TEMP_DIR/registry.json") + path=$(resolve_component_path "$type" "$id") if [ -n "$path" ] && [ "$path" != "null" ]; then local install_path @@ -985,7 +1096,7 @@ perform_installation() { # Get component path local path - path=$(jq_exec ".components.${registry_key}[]? | select(.id == \"${id}\") | .path" "$TEMP_DIR/registry.json") + path=$(resolve_component_path "$type" "$id") if [ -z "$path" ] || [ "$path" = "null" ]; then print_warning "Could not find path for ${comp}" @@ -1303,6 +1414,8 @@ main() { [ -n "$component" ] && SELECTED_COMPONENTS+=("$component") done < "$temp_file" + expand_selected_components + # Resolve dependencies for profile installs print_step "Resolving dependencies..." local original_count=${#SELECTED_COMPONENTS[@]} diff --git a/registry.json b/registry.json index c75d40d..bd92ed3 100644 --- a/registry.json +++ b/registry.json @@ -2189,8 +2189,8 @@ "category": "standard" }, { - "id": "workflows", - "name": "Workflows", + "id": "mastra-workflows", + "name": "Mastra Workflows", "type": "context", "path": ".opencode/context/development/ai/mastra-ai/concepts/workflows.md", "description": "Concept: Mastra Workflows", @@ -2287,6 +2287,26 @@ "tags": [], "dependencies": [], "category": "standard" + }, + { + "id": "building-cli-compact", + "name": "Building Cli Compact", + "type": "context", + "path": ".opencode/context/openagents-repo/guides/building-cli-compact.md", + "description": "Building CLIs in OpenAgents: Compact Guide", + "tags": [], + "dependencies": [], + "category": "standard" + }, + { + "id": "resolving-installer-wildcard-failures", + "name": "Resolving Installer Wildcard Failures", + "type": "context", + "path": ".opencode/context/openagents-repo/guides/resolving-installer-wildcard-failures.md", + "description": "Guide: Resolving Installer Wildcard Failures", + "tags": [], + "dependencies": [], + "category": "standard" } ], "config": [ @@ -2342,8 +2362,8 @@ "context:standards-docs", "context:standards-analysis", "context:workflows-delegation", - "context:workflows-sessions", - "context:workflows-task-breakdown", + "context:session-management", + "context:feature-breakdown", "context:workflows-review", "context:system-context-guide", "context:adding-skill", @@ -2380,16 +2400,7 @@ "context:essential-patterns", "context:project-context", "context:quick-start", - "context:standards-code", - "context:standards-patterns", - "context:standards-tests", - "context:standards-docs", - "context:standards-analysis", - "context:workflows-delegation", - "context:workflows-sessions", - "context:workflows-task-breakdown", - "context:workflows-review", - "context:system-context-guide", + "context:core/*", "context:adding-skill", "config:env-example", "config:readme" @@ -2419,16 +2430,7 @@ "context:essential-patterns", "context:project-context", "context:quick-start", - "context:standards-code", - "context:standards-patterns", - "context:standards-tests", - "context:standards-docs", - "context:standards-analysis", - "context:workflows-delegation", - "context:workflows-sessions", - "context:workflows-task-breakdown", - "context:workflows-review", - "context:system-context-guide", + "context:core/*", "context:adding-skill", "config:env-example", "config:readme" @@ -2474,16 +2476,7 @@ "context:essential-patterns", "context:project-context", "context:quick-start", - "context:standards-code", - "context:standards-patterns", - "context:standards-tests", - "context:standards-docs", - "context:standards-analysis", - "context:workflows-delegation", - "context:workflows-sessions", - "context:workflows-task-breakdown", - "context:workflows-review", - "context:system-context-guide", + "context:core/*", "context:adding-skill", "config:env-example", "config:readme" @@ -2538,16 +2531,7 @@ "context:essential-patterns", "context:project-context", "context:quick-start", - "context:standards-code", - "context:standards-patterns", - "context:standards-tests", - "context:standards-docs", - "context:standards-analysis", - "context:workflows-delegation", - "context:workflows-sessions", - "context:workflows-task-breakdown", - "context:workflows-review", - "context:system-context-guide", + "context:core/*", "context:adding-skill", "config:env-example", "config:readme" @@ -2559,7 +2543,7 @@ } }, "metadata": { - "lastUpdated": "2026-01-11", + "lastUpdated": "2026-01-12", "schemaVersion": "1.0.0" }, "subagents": {