Skip to content

T-1VJD-aspect-layer-detection-base

State: closed/done · Impact: medium · Complexity: medium

@sksizer/detect-runners and @sksizer/manifest-graph each independently re-parse package.json/Cargo.toml today for overlapping questions (“what tasks exist” vs. “what technology is this”). Land the shared base layer — collectAspects, reading every manifest kind once — as pure additive code with no existing provider or consumer touched yet, so it can be reviewed in isolation before anything depends on it.

detect-runners’s providers (cargo.ts, node-scripts.ts, moon.ts, just.ts, mise.ts, make.ts, +12 more) each call their own ctx.files()/ctx.readJson() for manifest presence/content. manifest-graph’s walk.ts independently parses package.json/Cargo.toml into its own ManifestInfo. project-facets.get.ts shells out to moon query projects a second time for facts a moon provider could already read. See ../decisions/D-LSLH-collapse-verbs-workflows-chain-hooks/detection-consolidation.md §1 “Inventory” for the full accounting.

A new @sksizer/detect-runners/aspects subpath exports collectAspects(root, opts): Promise<AspectCatalog> and the AspectFacts/AspectCatalog types (detection-consolidation.md §2), built from the existing ProviderContext memoized files()/readJson()/readText()/exists() primitives. Nothing else changes yet — no provider, no consumer, no behavior change to collect/tasks/discover.

  1. Add packages/ts/detect-runners/src/aspects.ts (or an aspect/ subdir) implementing AspectFacts/AspectCatalog/collectAspects per detection-consolidation.md §2’s shape (cargo, package.json, moon, justfile, mise, packageManager/lockfile, hookManagers, toolTrust, evidence).
  2. moon.role is populated from moon query projects, gated the same allowExec-aware way the existing moon provider gates itself — computed once per collectAspects() call.
  3. Export the subpath from the package’s package.json (exports map) as @sksizer/detect-runners/aspects.
  4. Add exhaustive unit tests against fixture directories (cargo-only, package.json-only, mixed, hook-manager markers, tool-trust markers).
AreaNote
packages/ts/detect-runners/src/aspects.tsNew: collectAspects, AspectFacts, AspectCatalog
packages/ts/detect-runners/package.jsonNew ./aspects export subpath
packages/ts/detect-runners/src/aspects.test.tsNew: fixture-driven coverage
  • AC-1: collectAspects(root, {allowExec: false}) against a fixture with only Cargo.toml returns AspectFacts.cargo populated and every other manifest field absent, with no exec.
  • AC-2: A fixture with a package.json scripts/dependencies populates AspectFacts.packageJson (name, main, types, scripts, dependencies) without touching Cargo.toml.
  • AC-3: moon.role is populated only when allowExec: true (or isRepoTrusted), matching the existing moon provider’s own exec gate.
  • AC-4: No existing detect-runners provider, and no manifest-graph or sdlc code, imports from the new subpath yet — this task ships dead code exercised only by its own tests.
  • AC-5: bun test packages/ts/detect-runners passes standalone.
  • Rewiring any existing provider to consume AspectFacts — T-6K39.
  • Moving detectDeps/resolvePinnedManagerInstall into this package — T-6K39.
  • manifest-graph’s walk.ts adoption — T-3GMU.
  • project-facets.get.ts’s shell-out removal — T-OUKL.
  • none

Detection-consolidation research: ../decisions/D-LSLH-collapse-verbs-workflows-chain-hooks/detection-consolidation.md, written to back D-LSLH-collapse-verbs-workflows-chain-hooks’s “The verb vocabulary: aspect-detected defaults” section (T-VE84).


← Back to Tasks