Task Resolution
After project detection builds a ProjectProfile, xtarterize resolves which tasks are relevant and what their current status is.
Resolution Pipeline
Section titled “Resolution Pipeline”ProjectProfile → resolveTasks() → applicable tasks → resolveTaskStatuses() → status mapresolveTasks(profile, allTasks)
Section titled “resolveTasks(profile, allTasks)”Filters the full task registry to only those where task.applicable(profile) returns true. This is a pure synchronous filter - no I/O, no side effects.
import { resolveTasks } from '@xtarterize/core'
const applicable = resolveTasks(profile, getAllTasks())// → only tasks whose conditions are metScope filtering
Section titled “Scope filtering”In addition to applicable(), resolveTasks() applies a scope
filter when the project is a monorepo. Each task can declare a
scope field:
type TaskScope = 'root' | 'package' | 'both'The scope filter checks the task’s scope against the monorepo position:
profile.monorepo === true├─ profile.workspaceRoot === true → exclude tasks with scope: 'package'└─ profile.workspaceRoot === false → exclude tasks with scope: 'root'In non-monorepo projects, scope filtering is skipped entirely. Tasks
without an explicit scope default to 'both' (included everywhere),
preserving backward compatibility for external plugins.
resolveTaskStatuses(tasks, cwd, profile)
Section titled “resolveTaskStatuses(tasks, cwd, profile)”Runs task.check() for each applicable task in parallel and returns a Map<taskId, TaskStatus>. Each task determines its own status by inspecting the filesystem.
import { resolveTaskStatuses } from '@xtarterize/core'
const statuses = await resolveTaskStatuses(applicable, cwd, profile)// → Map<string, 'new' | 'patch' | 'skip' | 'conflict'>The four statuses drive which tasks appear as actionable:
| Status | Meaning | Actionable for init |
Actionable for sync |
|---|---|---|---|
new |
Config doesn’t exist yet | Yes | No |
patch |
Config exists, can be updated | Yes | Yes |
skip |
Already conformant | No | No |
conflict |
Incompatible changes needed | Only if explicitly selected | Only if explicitly selected |
Task Gating Logic
Section titled “Task Gating Logic”Each task’s applicable() method checks ProjectProfile properties:
// TypeScript tasks: only if project uses TSapplicable: (profile) => profile.typescript
// Vite plugin tasks: only if bundler is Viteapplicable: (profile) => profile.bundler === 'vite'
// CI tasks: only if GitHub detectedapplicable: (profile) => profile.hasGitHub
// Turbo task: only if monorepo uses Turborepoapplicable: (profile) => profile.monorepoTool === 'turbo'Task statuses are evaluated in parallel via Effect.all, making resolution efficient even with many tasks.