fix(scripts): use text stubs for plugin links when symlinks unavailable#695
fix(scripts): use text stubs for plugin links when symlinks unavailable#695
Conversation
- add Test-SymlinkCapability probe-once detection in plugin generation - replace New-RelativeSymlink with New-PluginLink supporting dual paths - write git-compatible text stubs as fallback instead of copying files - normalize path separators in LintingHelpers for cross-platform git paths - add Pester tests for capability detection and text stub behavior 🔧 Fixes #691 - Generated by Copilot
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #695 +/- ##
==========================================
- Coverage 85.43% 84.61% -0.82%
==========================================
Files 23 23
Lines 4674 4737 +63
==========================================
+ Hits 3993 4008 +15
- Misses 681 729 +48
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
- add Repair-PluginSymlinkIndex to fix 100644 -> 120000 for text stubs - use batched git update-index --index-info to avoid index.lock contention - integrate fixup into Generate-Plugins.ps1 for non-symlink systems 🔧 - Generated by Copilot
- split entries into tracked (batch --index-info) and new (--cacheinfo) - --index-info silently ignores untracked paths from PowerShell pipes - add WSL symlink test instruction for cross-platform verification 🔧 - Generated by Copilot
- delete wsl-symlink-test.instructions.md after successful verification - restore collection manifests and plugin READMEs to main state 🧹 - Generated by Copilot
|
@WilliamBerryiii @katriendg I have tested the fix on MacOs and there are no regression and works like expected |
|
@WilliamBerryiii @katriendg I tested this branch on Windows in a dev container and I saw no regression. It works as expected |
|
Thanks @bindsi and @peterbryntesson for the testing on your environments! I'm moving this into published PR for further review. |
katriendg
left a comment
There was a problem hiding this comment.
Also tested within WSL/devcontainer and working correctly as expected. Because this issue is affecting other users creating their PRs we will go ahead and merge in!
…est (#701) ## Description Stabilized the YAML display key ordering in `Update-HveCoreAllCollection` by rebuilding the `display` section as an ordered hashtable before serialization. `ConvertTo-Yaml` serialized regular hashtables with non-deterministic key iteration order, causing `featured` and `ordering` keys to appear in inconsistent sequences across runs. The fix explicitly inserts `featured` before `ordering` using `[ordered]@{}`, producing stable output. Added five Pester tests covering display key ordering behavior. - fix(scripts): rebuilt `display` section as `[ordered]@{}` with explicit `featured`-then-`ordering` key insertion before `ConvertTo-Yaml` serialization - test(build): added five Pester tests for `Update-HveCoreAllCollection` display key ordering — covers both-keys order, only-ordering, only-featured, return hashtable shape, and DryRun mode ## Related Issue(s) Fixes #702 ## Type of Change Select all that apply: **Code & Documentation:** - [x] Bug fix (non-breaking change fixing an issue) - [ ] New feature (non-breaking change adding functionality) - [ ] Breaking change (fix or feature causing existing functionality to change) - [ ] Documentation update **Infrastructure & Configuration:** - [ ] GitHub Actions workflow - [ ] Linting configuration (markdown, PowerShell, etc.) - [ ] Security configuration - [ ] DevContainer configuration - [ ] Dependency update **AI Artifacts:** - [ ] Reviewed contribution with `prompt-builder` agent and addressed all feedback - [ ] Copilot instructions (`.github/instructions/*.instructions.md`) - [ ] Copilot prompt (`.github/prompts/*.prompt.md`) - [ ] Copilot agent (`.github/agents/*.agent.md`) - [ ] Copilot skill (`.github/skills/*/SKILL.md`) > **Note for AI Artifact Contributors**: > > - **Agents**: Research, indexing/referencing other project (using standard VS Code GitHub Copilot/MCP tools), planning, and general implementation agents likely already exist. Review `.github/agents/` before creating new ones. > - **Skills**: Must include both bash and PowerShell scripts. See [Skills](../docs/contributing/skills.md). > - **Model Versions**: Only contributions targeting the **latest Anthropic and OpenAI models** will be accepted. Older model versions (e.g., GPT-3.5, Claude 3) will be rejected. > - See [Agents Not Accepted](../docs/contributing/custom-agents.md#agents-not-accepted) and [Model Version Requirements](../docs/contributing/ai-artifacts-common.md#model-version-requirements). **Other:** - [x] Script/automation (`.ps1`, `.sh`, `.py`) - [ ] Other (please describe): ## Testing Five new Pester tests added in `scripts/tests/plugins/PluginHelpers.Tests.ps1` under the `Update-HveCoreAllCollection - display key ordering` describe block: 1. **Preserves featured-then-ordering key order** — writes a manifest with `ordering` before `featured` (reversed), runs the function, and asserts `featured:` appears before `ordering:` in the output 2. **Handles display with only ordering key** — verifies output contains `ordering: alpha` and does not contain `featured:` 3. **Handles display with only featured key** — verifies output contains `featured:` and does not contain `ordering:` 4. **Returns expected result hashtable** — validates `ItemCount`, `AddedCount`, `RemovedCount`, and `DeprecatedCount` keys in the return value 5. **Does not write to disk in DryRun mode** — confirms the file remains unmodified when `-DryRun` is passed All 64 tests pass (59 existing + 5 new). ## Checklist ### Required Checks - [ ] Documentation is updated (if applicable) - [x] Files follow existing naming conventions - [x] Changes are backwards compatible (if applicable) - [x] Tests added for new functionality (if applicable) ### AI Artifact Contributions <!-- Not applicable — no AI artifacts changed --> ### Required Automated Checks The following validation commands must pass before merging: - [ ] Markdown linting: `npm run lint:md` - [ ] Spell checking: `npm run spell-check` - [ ] Frontmatter validation: `npm run lint:frontmatter` - [ ] Skill structure validation: `npm run validate:skills` - [ ] Link validation: `npm run lint:md-links` - [ ] PowerShell analysis: `npm run lint:ps` ## Security Considerations - [x] This PR does not contain any sensitive or NDA information - [ ] Any new dependencies have been reviewed for security issues - [x] Security-related scripts follow the principle of least privilege ## Additional Notes This fix addresses a YAML serialization inconsistency that was committed after PR #695 was squash-merged into main. The commit was cherry-picked from `f52e255` onto a dedicated branch from `origin/main`. 🔧 - Generated by Copilot
🤖 I have created a release *beep* *boop* --- ## [3.0.0](hve-core-v2.3.10...hve-core-v3.0.0) (2026-02-20) ### ⚠ BREAKING CHANGES * **skills:** migrate PR reference generation to self-contained skill ([#669](#669)) * restructure RPI collection to HVE Core naming convention ([#668](#668)) ### ✨ Features * **agents:** add agile-coach agent ([#562](#562)) ([de8d86c](de8d86c)) * **agents:** add DT coach agent with tiered instruction loading ([#656](#656)) ([206d3a7](206d3a7)) * **agents:** add product manager advisor and UX/UI designer agents ([#627](#627)) ([539eb8a](539eb8a)) * **agents:** add system architecture reviewer for design trade-offs and ADR creation ([#626](#626)) ([de5cfd6](de5cfd6)) * **build:** pin devcontainer image and align tool parity ([#704](#704)) ([6258b1c](6258b1c)) * **design-thinking:** add manufacturing industry context template ([#682](#682)) ([ce864bf](ce864bf)) * **instructions:** add DT coaching state protocol for session persistence ([#654](#654)) ([5a5be4e](5a5be4e)) * **instructions:** add dt-coaching-identity ambient instruction ([#642](#642)) ([6209a0d](6209a0d)) * **instructions:** add dt-method-01-deep for advanced scope conversation techniques ([#673](#673)) ([cc92ef9](cc92ef9)) * **instructions:** add dt-method-03-deep for advanced input synthesis techniques ([#676](#676)) ([0079a4f](0079a4f)) * **instructions:** add dt-method-09-deep instructions for Method 9 advanced coaching ([#703](#703)) ([150b2a6](150b2a6)) * **instructions:** add dt-method-sequencing ambient instruction ([#650](#650)) ([e465b2f](e465b2f)) * **instructions:** add dt-quality-constraints and design-thinking collection ([#645](#645)) ([17002bd](17002bd)) * **instructions:** add DT-to-RPI handoff contract specification ([#679](#679)) ([87f9962](87f9962)) * **instructions:** add energy industry context template ([#687](#687)) ([41088d8](41088d8)) * **instructions:** add healthcare industry context template ([#686](#686)) ([b2d5281](b2d5281)) * **instructions:** add Method 1 Scope Conversations coaching knowledge ([#651](#651)) ([93e2d48](93e2d48)) * **instructions:** add Method 2 Design Research coaching knowledge ([#652](#652)) ([30f7f3b](30f7f3b)) * **instructions:** add Method 3 Input Synthesis coaching knowledge ([#653](#653)) ([1efdb7d](1efdb7d)) * **instructions:** add Method 7 High-Fidelity Prototypes coaching instruction ([#666](#666)) ([9233eab](9233eab)) * **instructions:** add pull request instructions for PR generation workflow ([#706](#706)) ([73d23eb](73d23eb)) * **instructions:** create DT curriculum content (9 modules) ([#690](#690)) ([9f7378f](9f7378f)), closes [#617](#617) * **instructions:** create dt-method-02-deep.instructions.md ([#700](#700)) ([4d4d0ca](4d4d0ca)) * **instructions:** create dt-method-06-lofi-prototypes.instructions.md ([#684](#684)) ([4d5f757](4d5f757)) * **instructions:** create dt-method-07-deep.instructions.md ([#678](#678)) ([d3ec70d](d3ec70d)) * **instructions:** Create dt-method-08-deep.instructions.md ([#683](#683)) ([d9e1115](d9e1115)) * **instructions:** create dt-method-08-testing.instructions.md ([#681](#681)) ([3008ad8](3008ad8)) * **instructions:** create dt-method-09-iteration.instructions.md ([#685](#685)) ([9d7f4f5](9d7f4f5)) * **instructions:** create dt-rpi-research-context.instructions.md ([#689](#689)) ([34c7b89](34c7b89)) * **instructions:** create manufacturing reference learning scenario ([#692](#692)) ([1bd3994](1bd3994)) * **instructions:** Design Thinking Method 4 brainstorming instruction file ([#664](#664)) ([06f90b0](06f90b0)) * **prompts:** add DT start-project prompt for coaching initialization ([#657](#657)) ([ce583d5](ce583d5)) * **prompts:** add dt-resume-coaching prompt for session recovery ([#665](#665)) ([11b93cb](11b93cb)) * **prompts:** create dt-handoff-problem-space.prompt.md ([#688](#688)) ([277963d](277963d)) * **scripts:** add collection-level maturity field with validation, gating, and notices ([#697](#697)) ([7b1c8e8](7b1c8e8)) * **scripts:** add per-violation CI annotations and colorized console output ([#637](#637)) ([bd7d512](bd7d512)) * **skills:** edit SKILL frontmatter schema, add CI validation, and documentation ([#625](#625)) ([0138a78](0138a78)) * **skills:** mandate unit testing and document language support ([#636](#636)) ([9263617](9263617)) * **skills:** migrate PR reference generation to self-contained skill ([#669](#669)) ([cf8805f](cf8805f)) ### 🐛 Bug Fixes * **collections:** migrate artifacts into collection-based subdirectories ([#658](#658)) ([dfa5261](dfa5261)) * **instructions:** optimize Phase 1 DT token budgets and close [#564](https://github.com/microsoft/hve-core/issues/564)/[#565](https://github.com/microsoft/hve-core/issues/565) gaps ([#675](#675)) ([4f42f00](4f42f00)) * **scripts:** add CI annotations and step summary to copyright header check ([#638](#638)) ([5fa6328](5fa6328)) * **scripts:** add grouped link-lang console diagnostics and failure summary ([#661](#661)) ([4d6871f](4d6871f)) * **scripts:** add per-violation Write-Host and Write-CIAnnotation output to Test-DependencyPinning ([#640](#640)) ([9d3b71d](9d3b71d)) * **scripts:** align agent frontmatter schema with VS Code spec ([#469](#469)) ([254d445](254d445)) * **scripts:** optimize PSScriptAnalyzer linting performance in WSL2 ([#667](#667)) ([f120b93](f120b93)) * **scripts:** stabilize YAML display key ordering in collection manifest ([#701](#701)) ([73c0d2c](73c0d2c)) * **scripts:** use text stubs for plugin links when symlinks unavailable ([#695](#695)) ([d7650a3](d7650a3)) * **skills:** fix powershell test coverage in pr-reference skill ([#699](#699)) ([408e6b7](408e6b7)) ### 📚 Documentation * **dt:** add Method 5 Concepts and Method 6 Lo-Fi Prototypes instructions ([#693](#693)) ([cfdcf11](cfdcf11)) * **hve-guide:** add role-based guides and project lifecycle documentation ([#663](#663)) ([17a85da](17a85da)) ### ♻️ Refactoring * restructure RPI collection to HVE Core naming convention ([#668](#668)) ([120dde0](120dde0)) * **scripts:** consolidate duplicate logging into shared SecurityHelpers module ([#655](#655)) ([627a877](627a877)) * **scripts:** use shared SecurityHelpers and CIHelpers modules in security scripts ([#705](#705)) ([3a0baa7](3a0baa7)) ### 🔧 Maintenance * **deps-dev:** bump markdownlint-cli2 from 0.20.0 to 0.21.0 in the npm-dependencies group ([#609](#609)) ([1486dd7](1486dd7)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: hve-core-release-please[bot] <254602402+hve-core-release-please[bot]@users.noreply.github.com>
fix(scripts): use text stubs for plugin links when symlinks unavailable
Description
When
core.symlinksis false (Windows without Developer Mode or elevated privileges),New-Item -ItemType SymbolicLinkfails and plugin generation breaks. This PR replaces forced symlink creation with a dual-path strategy: probe symlink capability once at generation start, then either create real symlinks or write git-compatible text stubs containing the relative path. Text stubs match the 120000-mode format git produces when it checks out symlinks as plain files, keepinggit statusclean.Also normalizes path separators in
LintingHelperswheregit rev-parse --show-toplevelreturns forward slashes butResolve-Pathreturns backslashes on Windows.Batch Symlink Index Repair
When text stubs are written on a
core.symlinks=falsesystem, git records them as100644(regular file) in the index even though they represent symlinks.Repair-PluginSymlinkIndexcorrects allplugins/entries that should be120000mode, using a two-bucket approach:git update-index --index-infofor efficiencygit update-index --add --cacheinfocalls, since--index-infosilently ignores paths not yet tracked via PowerShell pipesThis runs automatically at the end of
Generate-Plugins.ps1when symlinks are unavailable.Related Issue(s)
Fixes #691
Type of Change
Select all that apply:
Code & Documentation:
Infrastructure & Configuration:
AI Artifacts:
prompt-builderagent and addressed all feedback.github/instructions/*.instructions.md).github/prompts/*.prompt.md).github/agents/*.agent.md).github/skills/*/SKILL.md)Other:
.ps1,.sh,.py)Testing
npm run test:ps)plugins/are byte-identical to git's 120000-mode symlink stubsnpm run plugin:generateproduces zerogit diffchanges inplugins/plugins/remains clean120000mode materialized as real working OS-level symlinks on WSL — zero broken, zero text stubs remainingRepair-PluginSymlinkIndexcorrectly handles both tracked and untracked files in the git indexChecklist
Required Checks
Required Automated Checks
The following validation commands must pass before merging:
npm run lint:mdnpm run spell-checknpm run lint:frontmatternpm run validate:skillsnpm run lint:md-linksnpm run lint:psSecurity Considerations
No new dependencies introduced.
Test-SymlinkCapabilitycreates a temporary probe directory scoped to the current PID and cleans up unconditionally viafinally. Text stubs are written with[System.IO.File]::WriteAllText()using only relative paths derived from the repository tree.Additional Notes
New-RelativeSymlinkis renamed toNew-PluginLinkto reflect the dual-path behaviorTest-SymlinkCapabilityprobes once per generation run to avoid repeated filesystem operationsRepair-PluginSymlinkIndexbatches git index corrections to avoid index.lock contention from rapid sequential--cacheinfocalls--index-infostdin pipe, new files via individual--cacheinfo(PowerShell pipe encoding prevents--index-infofrom accepting untracked paths)🔧 - Generated by Copilot