Problem Statement
We need a standard, scalable distribution model for IdLE modules.
We are moving to name-based RequiredModules to support standard PowerShell dependency resolution (especially for PSGallery publication and third-party extensions). In repo/zip layouts (e.g., git clone or extracted GitHub archive), modules live under src/ and will not be discovered by name unless src/ is part of $env:PSModulePath.
At the same time, the current packaging approach (shipping many modules inside a single package under a non-module-root folder) prevents reliable Import-Module <ModuleName> behavior because discovery is PSModulePath-root based.
We want:
- PSGallery scenario:
Install-Module IdLE installs IdLE plus its foundational dependencies (e.g., IdLE.Core, IdLE.Steps.Common)
Import-Module IdLE.Provider.* works by module name and pulls its declared RequiredModules
- Repo/zip scenario:
- Users import
IdLE first, and IdLE bootstraps discovery so that subsequent imports by name work
Proposed Solution
Implement the distribution strategy in two parts:
- Packaging / Publishing overhaul (Monorepo → multiple published modules)
- Repo/Zip bootstrap for module discovery (Src-Mode via
IdLE.init.ps1)
Part 1: Packaging / Publishing overhaul
Goals
- Publish each module under
src/<ModuleName> as a separate PSGallery module:
IdLE
IdLE.Core
IdLE.Steps.Common
IdLE.Steps.*
IdLE.Provider.*
- Use name-based
RequiredModules everywhere (no relative paths).
- Ensure
IdLE (meta module) uses RequiredModules = @('IdLE.Core','IdLE.Steps.Common').
- Providers should not require Steps; they should require Core if they use Core APIs.
- Keep external tool/module dependencies (e.g., EXO modules) as soft runtime dependencies if that is the current design (do not break import).
CI/Release requirements (high level)
- Update packaging tooling so that builds produce one installable module package per module.
- Update GitHub workflows to:
- build module artifacts
- run tests
- publish modules (stable) to PSGallery in a controlled order if needed (Core/Common before dependent modules)
- Define versioning strategy:
- at minimum: consistent version bump across all published modules per release
- or (optional later): independent module versioning (more complex)
Part 2: Repo/Zip bootstrap in IdLE.init.ps1
Enhance IdLE.init.ps1 to bootstrap module discovery for repo/zip layouts by idempotently extending $env:PSModulePath at process scope.
Behavior (detection)
On Import-Module IdLE:
- Determine the on-disk location of the imported
IdLE module.
- If a repo/zip layout is detected:
- detect a
src directory one level above the IdLE module directory (stable relative path)
- If
src exists and is not already in $env:PSModulePath, add it.
Rules
- No global/system-wide environment changes (process/session only).
- Idempotent: do not add duplicates.
- If
IdLE is installed via PSGallery (already discoverable), the init script should effectively do nothing.
- Supported entry-point rule:
- repo/zip layout:
Import-Module IdLE first
- direct provider/step import before
IdLE is not supported in repo/zip layouts
Acceptance criteria
PSGallery / installed modules
Install-Module IdLE results in IdLE, IdLE.Core, and IdLE.Steps.Common being installable/discoverable by name.
Import-Module IdLE loads the meta module and its RequiredModules.
- Importing a provider module by name (e.g.,
Import-Module IdLE.Provider.ExchangeOnline) loads its declared RequiredModules without requiring IdLE to have been imported first (in installed-module scenarios).
Repo/Zip layout
Import-Module <repo>/src/IdLE/IdLE.psd1 succeeds.
- After that,
Import-Module IdLE.Provider.* and Import-Module IdLE.Steps.* by name succeeds without manual PSModulePath edits.
CI/Release
- Build produces separate module artifacts per module under
src/.
- Tests run and pass for the refactored dependency model.
- Publishing pipeline can publish in a deterministic, documented order.
Implementation checklist (agent-ready)
Alternatives Considered
- Keep a single “bundle” package and ship extra modules under internal folders.
- Rejected: prevents standard
Import-Module <Name> behavior and breaks third-party expectations.
- Keep relative-path
RequiredModules to support repo layouts without PSModulePath bootstrap.
- Rejected: breaks standard dependency semantics and published module layouts; fragile for consumers.
- Require users to manually edit
$env:PSModulePath in repo/zip layouts.
- Rejected: error-prone and inconsistent onboarding.
Impact
- Breaking change (pre-1.0 acceptable):
- Module manifests will change (
NestedModules → name-based RequiredModules).
- Consumers relying on internal layout/relative imports may need adjustment.
- CI/Release process changes:
- multiple PSGallery modules published per release
- dependency ordering and versioning must be defined
- Repo/zip usage gains a controlled, process-scope environment modification when importing
IdLE (PSModulePath bootstrap).
Additional Context
Design decisions captured in this issue:
- Distribution will be standard PowerShell:
- each IdLE module is a standalone published module
- dependencies are expressed via name-based
RequiredModules
- Repo/zip layouts are supported with the explicit rule:
IdLE must be imported first, then other modules can be imported by name
IdLE.init.ps1 performs repo/zip bootstrap only when a src layout is detected and only at process scope.
Problem Statement
We need a standard, scalable distribution model for IdLE modules.
We are moving to name-based
RequiredModulesto support standard PowerShell dependency resolution (especially for PSGallery publication and third-party extensions). In repo/zip layouts (e.g.,git cloneor extracted GitHub archive), modules live undersrc/and will not be discovered by name unlesssrc/is part of$env:PSModulePath.At the same time, the current packaging approach (shipping many modules inside a single package under a non-module-root folder) prevents reliable
Import-Module <ModuleName>behavior because discovery is PSModulePath-root based.We want:
Install-Module IdLEinstallsIdLEplus its foundational dependencies (e.g.,IdLE.Core,IdLE.Steps.Common)Import-Module IdLE.Provider.*works by module name and pulls its declaredRequiredModulesIdLEfirst, and IdLE bootstraps discovery so that subsequent imports by name workProposed Solution
Implement the distribution strategy in two parts:
IdLE.init.ps1)Part 1: Packaging / Publishing overhaul
Goals
src/<ModuleName>as a separate PSGallery module:IdLEIdLE.CoreIdLE.Steps.CommonIdLE.Steps.*IdLE.Provider.*RequiredModuleseverywhere (no relative paths).IdLE(meta module) usesRequiredModules = @('IdLE.Core','IdLE.Steps.Common').CI/Release requirements (high level)
Part 2: Repo/Zip bootstrap in
IdLE.init.ps1Enhance
IdLE.init.ps1to bootstrap module discovery for repo/zip layouts by idempotently extending$env:PSModulePathat process scope.Behavior (detection)
On
Import-Module IdLE:IdLEmodule.srcdirectory one level above theIdLEmodule directory (stable relative path)srcexists and is not already in$env:PSModulePath, add it.Rules
IdLEis installed via PSGallery (already discoverable), the init script should effectively do nothing.Import-Module IdLEfirstIdLEis not supported in repo/zip layoutsAcceptance criteria
PSGallery / installed modules
Install-Module IdLEresults inIdLE,IdLE.Core, andIdLE.Steps.Commonbeing installable/discoverable by name.Import-Module IdLEloads the meta module and itsRequiredModules.Import-Module IdLE.Provider.ExchangeOnline) loads its declaredRequiredModuleswithout requiringIdLEto have been imported first (in installed-module scenarios).Repo/Zip layout
Import-Module <repo>/src/IdLE/IdLE.psd1succeeds.Import-Module IdLE.Provider.*andImport-Module IdLE.Steps.*by name succeeds without manual PSModulePath edits.CI/Release
src/.Implementation checklist (agent-ready)
IdLEmanifest fromNestedModulesto name-basedRequiredModules(IdLE.Core,IdLE.Steps.Common)RequiredModules(no relative paths)src/IdLE.init.ps1repo/zip bootstrap (src detection + idempotent PSModulePath update)Alternatives Considered
Import-Module <Name>behavior and breaks third-party expectations.RequiredModulesto support repo layouts without PSModulePath bootstrap.$env:PSModulePathin repo/zip layouts.Impact
NestedModules→ name-basedRequiredModules).IdLE(PSModulePath bootstrap).Additional Context
Design decisions captured in this issue:
RequiredModulesIdLEmust be imported first, then other modules can be imported by nameIdLE.init.ps1performs repo/zip bootstrap only when asrclayout is detected and only at process scope.