From 9b17b1bed7dabae222165e015a5c5a56c5a49f24 Mon Sep 17 00:00:00 2001 From: Tirth Kanani Date: Fri, 5 Jun 2026 17:10:45 +0100 Subject: [PATCH] fix(install): resolve Codex agents path on Windows (#340) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Windows, Codex CLI doesn't auto-traverse the `~/.understand-anything-plugin` junction when interpreting relative `agents/.md` paths emitted by the skill, so subagent dispatches silently fail to load the agent definition unless the user types the full path. This bites Codex on Windows but is latent across every non-Claude host that doesn't inject a runtime plugin root. Two-pronged fix: 1. `understand-anything-plugin/skills/understand/SKILL.md` and `understand-anything-plugin/hooks/auto-update-prompt.md`: prefix every agent-definition reference with the resolved `$PLUGIN_ROOT` so the dispatcher always receives an absolute path. This mirrors the pattern already used in `understand-domain/SKILL.md` ("Read the domain-analyzer agent prompt from $PLUGIN_ROOT/agents/...") and benefits every platform, not just Windows + Codex. 2. `install.ps1`: also create a vendor-specific plugin-root junction for codex/opencode/pi (e.g. `~/.codex/understand-anything/understand-anything-plugin`). These paths are already in the SKILL.md fallback chain, so even if a host's Windows runtime refuses to traverse the universal junction it can still discover the plugin via the vendor-specific one. `install.sh` is left untouched — symlinks on POSIX already resolve the universal junction correctly, and the SKILL.md change is the symmetric fix that helps every platform equally. Co-Authored-By: Claude Opus 4.7 (1M context) --- install.ps1 | 42 +++++++++++++++++-- .../hooks/auto-update-prompt.md | 4 +- .../skills/understand/SKILL.md | 14 ++++--- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/install.ps1 b/install.ps1 index 1a4b4df3..c5a06eac 100644 --- a/install.ps1 +++ b/install.ps1 @@ -26,12 +26,18 @@ $RepoUrl = if ($env:UA_REPO_URL) { $env:UA_REPO_URL } else { 'https://github. $RepoDir = if ($env:UA_DIR) { $env:UA_DIR } else { Join-Path $HOME '.understand-anything\repo' } $PluginLink = Join-Path $HOME '.understand-anything-plugin' -# Platform table — Target = skills directory; Style = "per-skill" | "folder" +# Platform table — Target = skills directory; Style = "per-skill" | "folder"; +# ExtraPluginLink = optional second plugin-root junction. The skills' SKILL.md +# resolves the plugin root via a fallback chain that includes vendor-specific +# locations (e.g. $HOME/.codex/understand-anything/understand-anything-plugin) +# in addition to the universal $HOME/.understand-anything-plugin. Hosts that do +# not auto-traverse the universal junction on Windows (issue #340) still find +# the plugin via this vendor-specific path. $Platforms = [ordered]@{ gemini = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill' } - codex = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill' } - opencode = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill' } - pi = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill' } + codex = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill'; ExtraPluginLink = (Join-Path $HOME '.codex\understand-anything\understand-anything-plugin') } + opencode = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill'; ExtraPluginLink = (Join-Path $HOME '.opencode\understand-anything\understand-anything-plugin') } + pi = @{ Target = (Join-Path $HOME '.agents\skills'); Style = 'per-skill'; ExtraPluginLink = (Join-Path $HOME '.pi\understand-anything\understand-anything-plugin') } openclaw = @{ Target = (Join-Path $HOME '.openclaw\skills'); Style = 'folder' } antigravity = @{ Target = (Join-Path $HOME '.gemini\antigravity\skills'); Style = 'folder' } vscode = @{ Target = (Join-Path $HOME '.copilot\skills'); Style = 'per-skill' } @@ -191,6 +197,25 @@ function Link-Plugin-Root { } } +function Link-Extra-Plugin-Root([string]$LinkPath) { + # Mirror the universal plugin junction at a vendor-specific path that the + # SKILL.md fallback chain already probes (e.g. + # $HOME/.codex/understand-anything/understand-anything-plugin). This makes + # the plugin discoverable to hosts whose Windows runtime does not auto- + # traverse the universal $HOME/.understand-anything-plugin junction (see + # issue #340). + if (-not $LinkPath) { return } + if (Test-Path $LinkPath) { + Write-Host " • $LinkPath already exists, leaving as-is" + return + } + $parent = Split-Path -Parent $LinkPath + if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null } + $src = Join-Path $RepoDir 'understand-anything-plugin' + New-Item -ItemType Junction -Path $LinkPath -Target $src | Out-Null + Write-Host " ✓ $LinkPath → $src" +} + function Cmd-Install([string]$Id) { $cfg = Resolve-Platform $Id Clone-Or-Update @@ -198,6 +223,10 @@ function Cmd-Install([string]$Id) { Link-Skills $cfg.Target $cfg.Style Write-Host '→ Linking universal plugin root' Link-Plugin-Root + if ($cfg.Contains('ExtraPluginLink') -and $cfg.ExtraPluginLink) { + Write-Host "→ Linking vendor-specific plugin root for $Id" + Link-Extra-Plugin-Root $cfg.ExtraPluginLink + } Write-Host "`n✓ Installed Understand-Anything for $Id" Write-Host ' Restart your CLI or IDE to pick up the skills.' @@ -214,6 +243,11 @@ function Cmd-Uninstall([string]$Id) { if (Remove-Reparse $PluginLink) { Write-Host " ✓ removed $PluginLink" } + if ($cfg.Contains('ExtraPluginLink') -and $cfg.ExtraPluginLink) { + if (Remove-Reparse $cfg.ExtraPluginLink) { + Write-Host " ✓ removed $($cfg.ExtraPluginLink)" + } + } if (Test-Path $RepoDir) { Write-Host "`nThe checkout at $RepoDir was kept (other platforms may still use it)." Write-Host "To remove it: Remove-Item -Recurse -Force '$RepoDir'" diff --git a/understand-anything-plugin/hooks/auto-update-prompt.md b/understand-anything-plugin/hooks/auto-update-prompt.md index b20aa18d..dd0eccea 100644 --- a/understand-anything-plugin/hooks/auto-update-prompt.md +++ b/understand-anything-plugin/hooks/auto-update-prompt.md @@ -157,7 +157,7 @@ Only re-analyze files with structural changes. This is the **only** phase that c 2. Batch the files from `filesToReanalyze` (from Phase 1). Use a single batch if ≤10 files, otherwise batch into groups of 5-10. -3. For each batch, dispatch a subagent using the `file-analyzer` agent definition (at `agents/file-analyzer.md`). Append: +3. For each batch, dispatch a subagent using the `file-analyzer` agent definition (at `$PLUGIN_ROOT/agents/file-analyzer.md`, using the `$PLUGIN_ROOT` resolved in Phase 0 step 9). Append: > **Additional context from main session:** > @@ -200,7 +200,7 @@ Only re-analyze files with structural changes. This is the **only** phase that c If the change analysis flagged `ARCHITECTURE_UPDATE`: -1. Dispatch a subagent using the `architecture-analyzer` agent definition (at `agents/architecture-analyzer.md`), passing the full merged node set and import edges. Include previous layer definitions for naming consistency: +1. Dispatch a subagent using the `architecture-analyzer` agent definition (at `$PLUGIN_ROOT/agents/architecture-analyzer.md`, using the `$PLUGIN_ROOT` resolved in Phase 0 step 9), passing the full merged node set and import edges. Include previous layer definitions for naming consistency: > Previous layer definitions (for naming consistency): > ```json diff --git a/understand-anything-plugin/skills/understand/SKILL.md b/understand-anything-plugin/skills/understand/SKILL.md index 35c0b112..fbb8e3e2 100644 --- a/understand-anything-plugin/skills/understand/SKILL.md +++ b/understand-anything-plugin/skills/understand/SKILL.md @@ -120,6 +120,8 @@ Determine whether to run a full analysis or incremental update. If `pnpm` is missing, report to the user: "Install Node.js ≥ 22 and pnpm ≥ 10, then re-run `/understand`." + **Use `$PLUGIN_ROOT` for every agent-definition reference in subsequent phases.** All `agents/.md` paths below are shorthand for `$PLUGIN_ROOT/agents/.md`. On hosts that don't auto-resolve relative paths to the plugin tree (e.g. Codex CLI on Windows, where the `~/.understand-anything-plugin` junction is not implicitly traversed — see issue #340), always prefix agent reads with the resolved `$PLUGIN_ROOT` from above so the dispatcher receives an absolute path. Bare `agents/.md` is not portable across all platforms. + 2. Get the current git commit hash: ```bash git rev-parse HEAD @@ -236,7 +238,7 @@ Set up and verify the `.understandignore` file before scanning. Report to the user: `[Phase 1/7] Scanning project files...` -Dispatch a subagent using the `project-scanner` agent definition (at `agents/project-scanner.md`). Append the following additional context: +Dispatch a subagent using the `project-scanner` agent definition (at `$PLUGIN_ROOT/agents/project-scanner.md`). Append the following additional context: > **Additional context from main session:** > @@ -302,7 +304,7 @@ Load `.understand-anything/intermediate/batches.json` (produced by Phase 1.5). I Report: `[Phase 2/7] Analyzing files — files in batches (up to 5 concurrent)...` -For each batch, dispatch a subagent using the `file-analyzer` agent definition (at `agents/file-analyzer.md`). Run up to **5 subagents concurrently**. Append the following additional context: +For each batch, dispatch a subagent using the `file-analyzer` agent definition (at `$PLUGIN_ROOT/agents/file-analyzer.md`). Run up to **5 subagents concurrently**. Append the following additional context: > **Additional context from main session:** > @@ -392,7 +394,7 @@ After batches complete: Report to the user: `[Phase 3/7] Reviewing assembled graph...` -Dispatch a subagent using the `assemble-reviewer` agent definition (at `agents/assemble-reviewer.md`). +Dispatch a subagent using the `assemble-reviewer` agent definition (at `$PLUGIN_ROOT/agents/assemble-reviewer.md`). Pass these parameters in the dispatch prompt: @@ -420,7 +422,7 @@ After the subagent completes, read `$PROJECT_ROOT/.understand-anything/intermedi Report to the user: `[Phase 4/7] Identifying architectural layers...` **Build the combined prompt template:** - 1. Use the `architecture-analyzer` agent definition (at `agents/architecture-analyzer.md`). + 1. Use the `architecture-analyzer` agent definition (at `$PLUGIN_ROOT/agents/architecture-analyzer.md`). 2. **Language context injection:** For each language detected in Phase 1 (e.g., `python`, `markdown`, `dockerfile`, `yaml`, `sql`, `terraform`, `graphql`, `protobuf`, `shell`, `html`, `css`), read the file at `./languages/.md` (e.g., `./languages/python.md`, `./languages/dockerfile.md`) and append its content after the base template under a `## Language Context` header. If the file does not exist for a detected language, skip it silently and continue. These files are in the `languages/` subdirectory next to this SKILL.md file. **Include non-code language snippets** — they provide edge patterns and summary styles for non-code files. 3. **Framework addendum injection:** For each framework detected in Phase 1 (e.g., `Django`), read the file at `./frameworks/.md` (e.g., `./frameworks/django.md`) and append its full content after the language context. If the file does not exist for a detected framework, skip it silently and continue. These files are in the `frameworks/` subdirectory next to this SKILL.md file. 4. **Output locale injection:** If `$OUTPUT_LANGUAGE` is NOT `en` (English), read the locale guidance file at `./locales/.md` (e.g., `./locales/zh.md`, `./locales/ja.md`, `./locales/ko.md`) and append its content after the framework addendums under a `## Output Language Guidelines` header. This provides language-specific guidance for tag naming conventions, summary style, and layer name translations. If the locale file does not exist for the specified language, skip silently — the `$LANGUAGE_DIRECTIVE` still applies. These files are in the `locales/` subdirectory next to this SKILL.md file. @@ -502,7 +504,7 @@ All four fields (`id`, `name`, `description`, `nodeIds`) are required. Report to the user: `[Phase 5/7] Building guided tour...` -Dispatch a subagent using the `tour-builder` agent definition (at `agents/tour-builder.md`). Append the following additional context: +Dispatch a subagent using the `tour-builder` agent definition (at `$PLUGIN_ROOT/agents/tour-builder.md`). Append the following additional context: > **Additional context from main session:** > @@ -695,7 +697,7 @@ If the script exits non-zero, read stderr, fix the script, and retry once. If `--review` IS in `$ARGUMENTS`, dispatch the LLM graph-reviewer subagent as follows: -Dispatch a subagent using the `graph-reviewer` agent definition (at `agents/graph-reviewer.md`). Append the following additional context: +Dispatch a subagent using the `graph-reviewer` agent definition (at `$PLUGIN_ROOT/agents/graph-reviewer.md`). Append the following additional context: > **Additional context from main session:** >