Skip to content

Task Resolution

After project detection builds a ProjectProfile, xtarterize resolves which tasks are relevant and what their current status is.

ProjectProfile → resolveTasks() → applicable tasks → resolveTaskStatuses() → status map

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 met

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

Each task’s applicable() method checks ProjectProfile properties:

// TypeScript tasks: only if project uses TS
applicable: (profile) => profile.typescript
// Vite plugin tasks: only if bundler is Vite
applicable: (profile) => profile.bundler === 'vite'
// CI tasks: only if GitHub detected
applicable: (profile) => profile.hasGitHub
// Turbo task: only if monorepo uses Turborepo
applicable: (profile) => profile.monorepoTool === 'turbo'

Task statuses are evaluated in parallel via Effect.all, making resolution efficient even with many tasks.