Skip to content
Docsv0.7.2

Projects & Worktrees

A project is the primary checkout plus its detached git worktrees, and it is the entry point for the chained resource API. Everything path-sensitive — config, actions, services, dependencies — is reached through namespaces that act on the active worktree unless you pass an explicit worktree.

import { DenvigSDK } from '@denvig/sdk'
const denvig = new DenvigSDK({ client: 'my-app' })
// By identifier or path
const project = await denvig.projects.retrieve('github:marcqualie/denvig')
// List every discovered project (each family rooted at its primary checkout)
const projects = await denvig.projects.list({ withConfig: true })
// Detect from cwd without throwing
const { project: detected, projectPath, slug } = await denvig.projects.detect()
project.id // stable internal id
project.slug // e.g. github:marcqualie/denvig
project.name // configured name, or the slug
project.path // absolute path of the active checkout
project.refs // known git refs
project.activeWorktree // the checkout this instance currently acts on
project.primaryWorktree // the primary ("main") checkout

A project exposes all of its checkouts through the worktrees namespace.

// List every checkout (primary + sibling worktrees)
const worktrees = project.worktrees.list()
// Retrieve a checkout by branch name ("main" = primary)
const feature = project.worktrees.retrieve('feature/x')
const wt = project.activeWorktree
wt.name // worktree name
wt.branch // branch the checkout is on
wt.path // absolute path on disk
wt.slug // project slug
wt.id // stable id
wt.isPrimary // true for the primary checkout
wt.config // resolved ProjectConfigSchema, with source paths
wt.services // services declared in this checkout's config
await wt.actions // all runnable actions, keyed by name
await wt.dependencies() // detected dependencies for this checkout

selectWorktree switches which checkout subsequent worktree-sensitive operations act on. It throws if the branch is unknown.

project.selectWorktree('feature/x')
// project.activeWorktree is now the feature/x checkout
const action = await project.actions.retrieve('build') // runs in feature/x

Alternatively, pass worktree to a single call without changing the active one:

const action = await project.actions.retrieve('build', { worktree: 'feature/x' })
const service = await project.services.retrieve('api', { worktree: 'feature/x' })
// Summary including aggregate service status
const info = await project.info()
// Available plugins and the actions each resolves
const plugins = await project.plugins()
const config = await project.config.retrieve()
console.log(config.sourcePaths) // files the config was loaded from

Stop all of the active checkout’s services and remove them from launchctl:

await project.teardown({ removeLogs: true })

Denvig builds canonical IDs (and hashes) for resources, used internally for log paths and service names. You can construct them yourself:

project.resourceId({ resource: 'service/api' })
// @marcqualie/denvig#root|service/api
project.resourceHash({ workspace: 'apps/web', resource: 'action/dev' })
// { id: '…', hash: 'abc123…' }