[PR #3109] [CLOSED] fix(setup): retain symbolic-link skill destinations across the lifecycle #5624

Closed
opened 2026-10-31 01:08:04 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/3109
Author: @akushonkamen
Created: 10/14/2026
Status: ❌ Closed

Base: main ← Head: fix/setup-symlinked-skill-destination


📝 Commits (2)

  • 97c2528 fix(setup): retain symbolic-link skill destinations across the lifecycle
  • 9ae7c77 merge: restore JavaScript analysis regression checks from main

📊 Changes

5 files changed (+198 additions, -35 deletions)

View changed files

📝 src/application/Doctor.ts (+22 -6)
📝 src/application/DoctorScope.ts (+9 -2)
📝 src/application/SetupSkill.ts (+68 -26)
📝 src/application/Uninstall.ts (+2 -1)
📝 tests/boundary/filesystem/setupSkill.test.ts (+97 -0)

📄 Description

Summary

When a client's reverse-engineer-anything skill directory is a symbolic link (skill manager or dotfiles repo linking ~/.claude/skills/reverse-engineer-anything to a shared copy), REA's skill lifecycle disagreed about the same directory: rea setup followed the link and wrote REA's bundle into the link target (replacing its SKILL.md, adding SKILL.md.rea.backup and references/), doctor then reported the skill aligned, while rea uninstall retained the same directory ("Skill directory is a symbolic link.") leaving every written file behind, and rea update's maintenance plan skipped it. Setup modified a location REA's own removal and maintenance paths do not manage.

Fixes #3057

Problem and expected behavior

Smallest trigger: a symlinked client skill root plus rea setup --client claude_code --yes with the skill enabled (issue reproduction uses an isolated temporary HOME with ln -s ../../managed/rea .claude/skills/reverse-engineer-anything).

Violated invariant: the documented policy — skill symbolic-link paths are "retained and reported rather than followed" (docs/installation.md "Diagnose, update, and remove"; the same rule Uninstall.ts already applied and the #1816 precedent for a symlinked ~/.rea root). Setup's installCanonicalSkill/planning path never checked whether a selected destination root is itself a symlink, so it was the one lifecycle stage that wrote through it, and doctor compared identity through the link and reported aligned for a copy REA cannot remove or update.

Expected behavior: setup, doctor, uninstall, and update treat a symbolic-link skill root uniformly — retain and report it, never follow it. An all-links selection plans no install and stays byte-identical; a mixed selection installs only into its managed roots; doctor names the link and points at replacing it instead of a run rea setup loop that would still do nothing.

Change and scope

  • In src/application/SetupSkill.ts: new partitionSkillDestinations splits selected skill destinations into managed and symbolic-link roots via lstat (missing/unreadable roots stay on each caller's existing path). canonicalSkillNeedsInstall and canonicalSkillFiles now consider only managed roots, so an all-links selection plans no install_skill action and no destination bytes change, and mixed selections write only their managed roots. readInstalledSkillIdentity reads only managed roots and, when every root is a link, returns the declined roots as the new symbolicLinkRoots field. A shared symbolicLinkSkillReason constant ("Skill directory is a symbolic link.") is exported for the lifecycle.
  • In src/application/Doctor.ts and src/application/DoctorScope.ts: the skill state union gains "unmanaged", produced when the identity carries declined roots (version null, symbolicLinkRoots non-empty). Doctor's detail names the link paths and the remediation becomes "Replace the symbolic-link skill directory with a real directory, then run rea setup to install a managed copy." — replacing the previous "Run rea setup" loop that could never resolve a linked root.
  • In src/application/Uninstall.ts: the existing retained reason literal now references the shared symbolicLinkSkillReason constant; uninstall behavior is unchanged (the fix aligns setup/doctor to uninstall's long-standing rule, not the reverse).
  • Explicitly not included: any change to uninstall or update behavior (both already decline linked roots), the alternative direction of managing files inside the link target (that would reverse the documented retention policy and needs a maintainer call), and client configuration-file symlink following in ClientConfigPath.ts. Registration-only setup (--skill=false) is unaffected.
  • Docs: no contract text changes required — this fix brings implementation in line with the already-documented retention policy.

Existing pattern harvested: the fix reuses the repo's established "retained and reported rather than followed" symlink rule — uninstall's per-root isSymbolicLink() check and its user-facing reason string (made into the shared symbolicLinkSkillReason constant), the #1816 precedent for declining a symlinked ~/.rea root, and existingSkillDestinations' existing skip of linked roots — and applies the same rule to the last two lifecycle stages that lacked it (setup write path, doctor identity read), instead of introducing a new policy.

Follow the contribution scope:

  • Contribution scope fit: ordinary fix within existing setup/doctor/uninstall boundaries; no new provider or capability involving target execution, injection, mutation, or protection recovery, so no maintainer scope decision is required ("not applicable").

Contract and boundary impact

  • Semantic owner and earliest changed stage: src/application/SetupSkill.ts skill destination partitioning, consumed by setup planning/installation and by src/application/Doctor.ts identity reporting.
  • Contribution scope fit and linked maintainer decision: not applicable; aligns implementation with the documented retention policy already enforced by uninstall/update.
  • CLI and MCP/tool-catalog contract: rea doctor's skill state field widens from "aligned" | "stale" | "missing" to add "unmanaged", with a new remediation string. Setup's applied actions for a linked selection change from installed_skill to none (nothing planned, nothing applied); mixed selections apply fewer actions (managed roots only). No MCP tool catalog changes.
  • Provider, bridge, target-format, or platform compatibility: applies to every client skill root on all platforms; lstat-based, so Windows junctions/symlinks resolve through Node's isSymbolicLink() on the stat. Client configuration-file symlink following (ClientConfigPath.ts) is deliberately untouched.
  • Evidence, artifact, provenance, or reconstruction contract: user-managed bytes behind links are no longer modified or backed-up into; no REA artifact is created inside a link target, so nothing is stranded there by a later uninstall.
  • Target selection, authority, upstream behavior, and cleanup details (if applicable): setup writes only into REA-managed, non-link skill roots; no new authority, network, or process interaction.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Expected effects (check known effects; use documentation-only on its own).
Unchecked items do not establish absence; leave uncertainties visible.

  • Read existing files or captured data.
  • Launch or attach to a process.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

(Setup reads the skill roots with lstat and, for managed roots only, writes the skill bundle — the same file writes setup always performed, now excluding link roots.)

Evidence and regression coverage

  • Tests added or updated: tests/boundary/filesystem/setupSkill.test.ts adds five symbolic-link regressions — (1) keeps a symbolic-link skill destination byte-identical and plans no install, (2) reads no REA skill identity through a symbolic-link destination, (3) reports doctor skill state unmanaged when the selected destination is a link, (4) installs only into managed roots when a selection also contains a link, (5) answers doctor from a managed root even when the selection also carries a link (mixed-selection empty-root boundary).
  • Base reproduction or other evidence: against the pre-fix sources (checked out from the parent commit on d901561) the same file fails 5 failed | 10 passed (15) — all five new regressions red, covering the issue's write-through, read-through, doctor stale, and mixed-selection paths; restoring the fix turns the same file green 15/15. The issue reporter's real-CLI outputs (aligned after write-through, uninstall retained, control on a regular directory) independently establish the failure mode on 6.4.0.
  • User-visible CLI/MCP output (if applicable): doctor reports skill.state: "unmanaged" with detail naming the link and a replace-the-link remediation; setup on a linked selection plans no install_skill action; uninstall's retained reason text is unchanged in wording.
  • Remaining proof gaps: no real-client end-to-end run on this machine (the issue reproduction uses a temporary HOME; the boundary tests mirror that layout). A linked-root run of the real rea setup/doctor/uninstall CLI by a maintainer or the reporter would close it.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npx vitest run tests/boundary/filesystem/setupSkill.test.ts — with the fix: 15 passed (15). Against pre-fix sources (the four changed source files checked out from the parent commit, tests unchanged): 5 failed | 10 passed (15), the five new regressions red. Sources restored and the tree verified clean afterwards. (The contributor brief recorded the red side as 4 failed | 10 passed; this session's run observed 5 failed | 10 passed, which matches the commit message's own recorded validation — all five regressions fail on the old code.)
  • npm run test:focused -- tests/boundary/filesystem/setupSkill.test.ts tests/boundary/filesystem/setupSkillCleanupOwnership.test.ts tests/boundary/filesystem/setupConfig.test.ts tests/boundary/filesystem/setupClientConfigCleanupOwnership.test.ts tests/boundary/filesystem/setupUnavailableProvider.test.ts tests/boundary/filesystem/doctorSystemHostFilesystem.test.ts tests/boundary/filesystem/generatedSkill.test.ts src/application/Doctor.test.ts src/application/Setup.configuration.test.ts src/application/Setup.planning.test.ts src/application/Setup.recovery.test.ts src/application/Setup.initialSnapshot.test.ts src/application/SetupInstallFailure.test.ts src/application/Update.test.ts tests/process-global/updateMaintenance.test.ts — 15 files passed, 197 passed (197).
  • npm run check:fast — 2 successful, 2 total (turbo typecheck + lint; cache was bypassed with --force for a fresh run: 0 cached).
  • npm run docs:check — exit 0 (readmeConsistency suite 5 passed).
  • npx oxfmt --check src/application/Doctor.ts src/application/DoctorScope.ts src/application/SetupSkill.ts src/application/Uninstall.ts tests/boundary/filesystem/setupSkill.test.ts — all matched files use the correct format.
  • Not run — real-client end-to-end with a temporary HOME: the boundary tests mirror that filesystem layout; no real Claude Code client session was driven here.
  • Not run — npm run check:pr: the full local gate is optional for changes of this width per AGENTS.md ("optional for broad changes or CI diagnosis"); CI owns the full deterministic suite.
  • Note: two checks named in the contributor brief, scripts/check_comment_history.py and scripts/check_brand_name.py, do not exist in this repository (verified by tree search in an earlier round); the repository's own gates above were run instead.
  • Note on origin/main: git fetch showed origin/main still at d901561 — no drift since validation, so no rebase was needed; the branch is a single commit on top of current origin/main.

Compatibility, safety, and release

  • Breaking changes or migration steps: none. Previously valid workflows keep working: regular-directory skill installs/uninstalls/updates are untouched; a linked selection that previously got a write-through now gets the documented retention behavior (no install, doctor unmanaged with a concrete remediation) — that is the fix, and users who want REA to manage the copy can replace the link as the remediation says. --skill=false registration-only setup is unchanged.
  • Real Hopper/Ghidra, browser, or OS coverage: not applicable to this change; no provider or target interaction. Windows junction coverage comes from the lstat/isSymbolicLink() semantics, not from a run on Windows.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: strictly narrows setup's write surface (stops writing into user-managed link targets); no new authority, network, or process capability. The doctor unmanaged state makes a previously hidden situation visible instead of misreporting aligned.
  • Competition disclosure for reviewers: this issue was claimed at 2026-10-14T02:29:01Z (comment on #3057) with this retain-and-report direction; PR #3108 (geekwolf, "fix(setup): refuse linked skill installation directories", created 2026-10-14T02:56:41Z) also fixes #3057 with a related but distinct approach (refusal framing, an additional references-directory link check). Left to maintainer arbitration; both cannot merge, and the direction difference (report unmanaged + replace-the-link remediation vs refusal) is the material delta to review.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/3109 **Author:** [@akushonkamen](https://github.com/akushonkamen) **Created:** 10/14/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/setup-symlinked-skill-destination` --- ### 📝 Commits (2) - [`97c2528`](https://github.com/morluto/rea/commit/97c25283a0354c6d629dc58a8c49cb4581b4972c) fix(setup): retain symbolic-link skill destinations across the lifecycle - [`9ae7c77`](https://github.com/morluto/rea/commit/9ae7c7798931b79c09ef26fe046240c41db7490d) merge: restore JavaScript analysis regression checks from main ### 📊 Changes **5 files changed** (+198 additions, -35 deletions) <details> <summary>View changed files</summary> 📝 `src/application/Doctor.ts` (+22 -6) 📝 `src/application/DoctorScope.ts` (+9 -2) 📝 `src/application/SetupSkill.ts` (+68 -26) 📝 `src/application/Uninstall.ts` (+2 -1) 📝 `tests/boundary/filesystem/setupSkill.test.ts` (+97 -0) </details> ### 📄 Description ## Summary When a client's `reverse-engineer-anything` skill directory is a symbolic link (skill manager or dotfiles repo linking `~/.claude/skills/reverse-engineer-anything` to a shared copy), REA's skill lifecycle disagreed about the same directory: `rea setup` followed the link and wrote REA's bundle into the link target (replacing its `SKILL.md`, adding `SKILL.md.rea.backup` and `references/`), doctor then reported the skill `aligned`, while `rea uninstall` retained the same directory ("Skill directory is a symbolic link.") leaving every written file behind, and `rea update`'s maintenance plan skipped it. Setup modified a location REA's own removal and maintenance paths do not manage. Fixes #3057 ## Problem and expected behavior Smallest trigger: a symlinked client skill root plus `rea setup --client claude_code --yes` with the skill enabled (issue reproduction uses an isolated temporary `HOME` with `ln -s ../../managed/rea .claude/skills/reverse-engineer-anything`). Violated invariant: the documented policy — skill symbolic-link paths are "retained and reported rather than followed" (`docs/installation.md` "Diagnose, update, and remove"; the same rule `Uninstall.ts` already applied and the #1816 precedent for a symlinked `~/.rea` root). Setup's `installCanonicalSkill`/planning path never checked whether a selected destination root is itself a symlink, so it was the one lifecycle stage that wrote through it, and doctor compared identity through the link and reported `aligned` for a copy REA cannot remove or update. Expected behavior: setup, doctor, uninstall, and update treat a symbolic-link skill root uniformly — retain and report it, never follow it. An all-links selection plans no install and stays byte-identical; a mixed selection installs only into its managed roots; doctor names the link and points at replacing it instead of a `run rea setup` loop that would still do nothing. ## Change and scope - In `src/application/SetupSkill.ts`: new `partitionSkillDestinations` splits selected skill destinations into managed and symbolic-link roots via `lstat` (missing/unreadable roots stay on each caller's existing path). `canonicalSkillNeedsInstall` and `canonicalSkillFiles` now consider only managed roots, so an all-links selection plans no `install_skill` action and no destination bytes change, and mixed selections write only their managed roots. `readInstalledSkillIdentity` reads only managed roots and, when every root is a link, returns the declined roots as the new `symbolicLinkRoots` field. A shared `symbolicLinkSkillReason` constant ("Skill directory is a symbolic link.") is exported for the lifecycle. - In `src/application/Doctor.ts` and `src/application/DoctorScope.ts`: the skill `state` union gains `"unmanaged"`, produced when the identity carries declined roots (version `null`, `symbolicLinkRoots` non-empty). Doctor's detail names the link paths and the remediation becomes "Replace the symbolic-link skill directory with a real directory, then run rea setup to install a managed copy." — replacing the previous `"Run rea setup"` loop that could never resolve a linked root. - In `src/application/Uninstall.ts`: the existing retained reason literal now references the shared `symbolicLinkSkillReason` constant; uninstall behavior is unchanged (the fix aligns setup/doctor to uninstall's long-standing rule, not the reverse). - Explicitly not included: any change to uninstall or update behavior (both already decline linked roots), the alternative direction of managing files inside the link target (that would reverse the documented retention policy and needs a maintainer call), and client *configuration*-file symlink following in `ClientConfigPath.ts`. Registration-only setup (`--skill=false`) is unaffected. - Docs: no contract text changes required — this fix brings implementation in line with the already-documented retention policy. Existing pattern harvested: the fix reuses the repo's established "retained and reported rather than followed" symlink rule — uninstall's per-root `isSymbolicLink()` check and its user-facing reason string (made into the shared `symbolicLinkSkillReason` constant), the #1816 precedent for declining a symlinked `~/.rea` root, and `existingSkillDestinations`' existing skip of linked roots — and applies the same rule to the last two lifecycle stages that lacked it (setup write path, doctor identity read), instead of introducing a new policy. Follow the [contribution scope](https://github.com/morluto/rea/blob/main/CONTRIBUTING.md#contribution-scope): - Contribution scope fit: ordinary fix within existing setup/doctor/uninstall boundaries; no new provider or capability involving target execution, injection, mutation, or protection recovery, so no maintainer scope decision is required ("not applicable"). ## Contract and boundary impact - Semantic owner and earliest changed stage: `src/application/SetupSkill.ts` skill destination partitioning, consumed by setup planning/installation and by `src/application/Doctor.ts` identity reporting. - Contribution scope fit and linked maintainer decision: not applicable; aligns implementation with the documented retention policy already enforced by uninstall/update. - CLI and MCP/tool-catalog contract: `rea doctor`'s skill `state` field widens from `"aligned" | "stale" | "missing"` to add `"unmanaged"`, with a new remediation string. Setup's applied actions for a linked selection change from `installed_skill` to none (nothing planned, nothing applied); mixed selections apply fewer actions (managed roots only). No MCP tool catalog changes. - Provider, bridge, target-format, or platform compatibility: applies to every client skill root on all platforms; `lstat`-based, so Windows junctions/symlinks resolve through Node's `isSymbolicLink()` on the stat. Client configuration-file symlink following (`ClientConfigPath.ts`) is deliberately untouched. - Evidence, artifact, provenance, or reconstruction contract: user-managed bytes behind links are no longer modified or backed-up into; no REA artifact is created inside a link target, so nothing is stranded there by a later uninstall. - Target selection, authority, upstream behavior, and cleanup details (if applicable): setup writes only into REA-managed, non-link skill roots; no new authority, network, or process interaction. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. Expected effects (check known effects; use documentation-only on its own). Unchecked items do not establish absence; leave uncertainties visible. - [x] Read existing files or captured data. - [ ] Launch or attach to a process. - [ ] Inject instrumentation or run scripts/code. - [x] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. (Setup reads the skill roots with `lstat` and, for managed roots only, writes the skill bundle — the same file writes setup always performed, now excluding link roots.) ## Evidence and regression coverage - Tests added or updated: `tests/boundary/filesystem/setupSkill.test.ts` adds five symbolic-link regressions — (1) `keeps a symbolic-link skill destination byte-identical and plans no install`, (2) `reads no REA skill identity through a symbolic-link destination`, (3) `reports doctor skill state unmanaged when the selected destination is a link`, (4) `installs only into managed roots when a selection also contains a link`, (5) `answers doctor from a managed root even when the selection also carries a link` (mixed-selection empty-root boundary). - Base reproduction or other evidence: against the pre-fix sources (checked out from the parent commit on `d901561`) the same file fails **5 failed | 10 passed (15)** — all five new regressions red, covering the issue's write-through, read-through, doctor `stale`, and mixed-selection paths; restoring the fix turns the same file green 15/15. The issue reporter's real-CLI outputs (aligned after write-through, uninstall `retained`, control on a regular directory) independently establish the failure mode on 6.4.0. - User-visible CLI/MCP output (if applicable): doctor reports `skill.state: "unmanaged"` with detail naming the link and a replace-the-link remediation; setup on a linked selection plans no `install_skill` action; uninstall's retained reason text is unchanged in wording. - Remaining proof gaps: no real-client end-to-end run on this machine (the issue reproduction uses a temporary `HOME`; the boundary tests mirror that layout). A linked-root run of the real `rea setup`/`doctor`/`uninstall` CLI by a maintainer or the reporter would close it. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npx vitest run tests/boundary/filesystem/setupSkill.test.ts` — with the fix: **15 passed (15)**. Against pre-fix sources (the four changed source files checked out from the parent commit, tests unchanged): **5 failed | 10 passed (15)**, the five new regressions red. Sources restored and the tree verified clean afterwards. (The contributor brief recorded the red side as 4 failed | 10 passed; this session's run observed 5 failed | 10 passed, which matches the commit message's own recorded validation — all five regressions fail on the old code.) - `npm run test:focused -- tests/boundary/filesystem/setupSkill.test.ts tests/boundary/filesystem/setupSkillCleanupOwnership.test.ts tests/boundary/filesystem/setupConfig.test.ts tests/boundary/filesystem/setupClientConfigCleanupOwnership.test.ts tests/boundary/filesystem/setupUnavailableProvider.test.ts tests/boundary/filesystem/doctorSystemHostFilesystem.test.ts tests/boundary/filesystem/generatedSkill.test.ts src/application/Doctor.test.ts src/application/Setup.configuration.test.ts src/application/Setup.planning.test.ts src/application/Setup.recovery.test.ts src/application/Setup.initialSnapshot.test.ts src/application/SetupInstallFailure.test.ts src/application/Update.test.ts tests/process-global/updateMaintenance.test.ts` — **15 files passed, 197 passed (197)**. - `npm run check:fast` — **2 successful, 2 total** (turbo typecheck + lint; cache was bypassed with `--force` for a fresh run: 0 cached). - `npm run docs:check` — exit 0 (readmeConsistency suite 5 passed). - `npx oxfmt --check src/application/Doctor.ts src/application/DoctorScope.ts src/application/SetupSkill.ts src/application/Uninstall.ts tests/boundary/filesystem/setupSkill.test.ts` — all matched files use the correct format. - Not run — real-client end-to-end with a temporary `HOME`: the boundary tests mirror that filesystem layout; no real Claude Code client session was driven here. - Not run — `npm run check:pr`: the full local gate is optional for changes of this width per `AGENTS.md` ("optional for broad changes or CI diagnosis"); CI owns the full deterministic suite. - Note: two checks named in the contributor brief, `scripts/check_comment_history.py` and `scripts/check_brand_name.py`, do not exist in this repository (verified by tree search in an earlier round); the repository's own gates above were run instead. - Note on origin/main: `git fetch` showed `origin/main` still at `d901561` — no drift since validation, so no rebase was needed; the branch is a single commit on top of current `origin/main`. ## Compatibility, safety, and release - Breaking changes or migration steps: none. Previously valid workflows keep working: regular-directory skill installs/uninstalls/updates are untouched; a linked selection that previously got a write-through now gets the documented retention behavior (no install, doctor `unmanaged` with a concrete remediation) — that is the fix, and users who want REA to manage the copy can replace the link as the remediation says. `--skill=false` registration-only setup is unchanged. - Real Hopper/Ghidra, browser, or OS coverage: not applicable to this change; no provider or target interaction. Windows junction coverage comes from the `lstat`/`isSymbolicLink()` semantics, not from a run on Windows. - Package or release metadata impact: none. - Security, privacy, process, or containment review: strictly narrows setup's write surface (stops writing into user-managed link targets); no new authority, network, or process capability. The doctor `unmanaged` state makes a previously hidden situation visible instead of misreporting `aligned`. - Competition disclosure for reviewers: this issue was claimed at 2026-10-14T02:29:01Z (comment on #3057) with this retain-and-report direction; PR #3108 (geekwolf, "fix(setup): refuse linked skill installation directories", created 2026-10-14T02:56:41Z) also fixes #3057 with a related but distinct approach (refusal framing, an additional `references`-directory link check). Left to maintainer arbitration; both cannot merge, and the direction difference (report `unmanaged` + replace-the-link remediation vs refusal) is the material delta to review. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:08:04 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5624
No description provided.