AI-first build platform designed for monorepo development that provides task orchestration, project graph generation, and CLI tools for managing complex software projects
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Task execution, caching, and orchestration APIs for building advanced build tools and custom task runners.
Functions for running executors and tasks programmatically.
/**
* Runs an executor programmatically
* @param targetDescription - Target to execute (project:target:configuration)
* @param overrides - Options to override target configuration
* @param context - Execution context
* @returns Async iterator yielding execution results
*/
function runExecutor<T = any>(
targetDescription: Target,
overrides: Partial<T>,
context: ExecutorContext
): Promise<AsyncIterableIterator<{ success: boolean; [key: string]: any }>>;
/**
* Parses a target string into its components
* @param targetString - Target in format "project:target" or "project:target:configuration"
* @returns Parsed target object
*/
function parseTargetString(targetString: string): Target;
/**
* Converts target object to string representation
* @param target - Target object
* @returns Target string in format "project:target:configuration"
*/
function targetToTargetString(target: Target): string;
interface Target {
project: string;
target: string;
configuration?: string;
}
interface ExecutorContext {
/** Workspace root directory */
root: string;
/** Current working directory */
cwd: string;
/** Workspace configuration */
workspace: WorkspaceJsonConfiguration;
/** Whether verbose logging is enabled */
isVerbose: boolean;
/** Name of the project being executed */
projectName?: string;
/** Name of the target being executed */
targetName?: string;
/** Name of the configuration being used */
configurationName?: string;
/** Graph of all projects */
projectGraph?: ProjectGraph;
/** Task graph for current execution */
taskGraph?: TaskGraph;
/** Hash of the current task */
hash?: string;
}Functions for working with task dependency graphs and task orchestration.
/**
* Creates a task graph from target dependencies
* @param projectGraph - Project dependency graph
* @param targets - Array of targets to execute
* @param nxJson - Nx configuration
* @param overrides - Task overrides
* @returns Task graph with dependencies
*/
function createTaskGraph(
projectGraph: ProjectGraph,
targets: Target[],
nxJson: NxJsonConfiguration,
overrides: { [target: string]: any }
): TaskGraph;
/**
* Maps targets to projects for task graph creation
* @param targets - Array of targets
* @param projectGraph - Project dependency graph
* @returns Map of project names to target arrays
*/
function groupTargetsByProject(
targets: Target[],
projectGraph: ProjectGraph
): Map<string, Target[]>;
interface TaskGraph {
/** Map of task IDs to task definitions */
tasks: Record<string, Task>;
/** Map of task IDs to their dependency task IDs */
dependencies: Record<string, string[]>;
/** Array of root task IDs (tasks with no dependencies) */
roots: string[];
}
interface Task {
/** Unique task identifier */
id: string;
/** Target being executed */
target: Target;
/** Project root path */
projectRoot: string;
/** Override options for this task */
overrides: any;
/** Hash representing task inputs */
hash?: string;
/** Array of output paths for this task */
outputs?: string[];
}APIs for computing task hashes and managing task caching.
/**
* Task hasher for computing deterministic task hashes
*/
interface TaskHasher {
/** Hashes a single task */
hashTask(task: Task): Promise<string>;
/** Hashes multiple tasks in batch */
hashTasks(tasks: Task[]): Promise<Record<string, string>>;
}
/**
* Creates a task hasher instance
* @param projectGraph - Project dependency graph
* @param nxJson - Nx configuration
* @returns Task hasher instance
*/
function createTaskHasher(
projectGraph: ProjectGraph,
nxJson: NxJsonConfiguration
): TaskHasher;
/**
* Hash computation utilities
*/
function hashArray(values: string[]): string;
function hashObject(obj: any): string;
interface FileData {
file: string;
hash: string;
}
/**
* Computes hash for workspace files
* @param workspaceRoot - Workspace root directory
* @param globs - Array of glob patterns to include
* @returns Promise resolving to file data with hashes
*/
function hashFiles(workspaceRoot: string, globs: string[]): Promise<FileData[]>;Types and utilities for integrating with Nx task runners.
/**
* Task runner interface for custom task execution
*/
interface TasksRunner {
invoke(
tasks: Task[],
options: any,
context?: TasksRunnerContext
): Promise<{ [taskId: string]: TaskResult }>;
}
interface TasksRunnerContext {
target?: string;
initiatingProject?: string;
projectGraph: ProjectGraph;
nxJson: NxJsonConfiguration;
hasher: TaskHasher;
}
interface TaskResult {
success: boolean;
code?: number;
terminalOutput?: string;
startTime?: number;
endTime?: number;
}
/**
* Default task runner options
*/
interface DefaultTasksRunnerOptions {
parallel?: number;
maxParallel?: number;
cacheableOperations?: string[];
runtimeCacheInputs?: string[];
cacheDirectory?: string;
remoteCache?: RemoteCacheOptions;
}
interface RemoteCacheOptions {
enabled?: boolean;
url?: string;
timeout?: number;
}Types and utilities for creating custom executors.
/**
* Executor function signature
*/
type Executor<T = any> = (
options: T,
context: ExecutorContext
) => Promise<{ success: boolean; [key: string]: any }> |
AsyncIterableIterator<{ success: boolean; [key: string]: any }>;
/**
* Promise-based executor signature
*/
type PromiseExecutor<T = any> = (
options: T,
context: ExecutorContext
) => Promise<{ success: boolean; [key: string]: any }>;
/**
* Creates an executor that converts async iterators to promises
* @param executor - Async iterator executor
* @returns Promise-based executor
*/
function convertToPromiseExecutor<T>(
executor: Executor<T>
): PromiseExecutor<T>;
/**
* Schema validation for executor options
*/
interface ExecutorSchema {
version: number;
title: string;
description?: string;
type: 'object';
properties: Record<string, any>;
additionalProperties?: boolean;
required?: string[];
}import {
runExecutor,
parseTargetString,
ExecutorContext,
logger
} from "nx/src/devkit-exports";
async function buildProject(projectName: string) {
const target = parseTargetString(`${projectName}:build`);
const context: ExecutorContext = {
root: process.cwd(),
cwd: process.cwd(),
workspace: readWorkspaceConfiguration(),
isVerbose: false,
projectName: target.project,
targetName: target.target
};
try {
const results = await runExecutor(target, {}, context);
for await (const result of results) {
if (result.success) {
logger.info(`✅ ${projectName}:build completed successfully`);
} else {
logger.error(`❌ ${projectName}:build failed`);
return false;
}
}
return true;
} catch (error) {
logger.error(`Failed to run ${projectName}:build: ${error.message}`);
return false;
}
}import {
Task,
TasksRunner,
TasksRunnerContext,
TaskResult,
logger
} from "nx/src/devkit-exports";
class CustomTasksRunner implements TasksRunner {
async invoke(
tasks: Task[],
options: any,
context?: TasksRunnerContext
): Promise<{ [taskId: string]: TaskResult }> {
const results: { [taskId: string]: TaskResult } = {};
logger.info(`Executing ${tasks.length} tasks`);
for (const task of tasks) {
const startTime = Date.now();
try {
// Execute task using runExecutor
const target = task.target;
const executorContext: ExecutorContext = {
root: context.projectGraph.nodes[target.project].data.root,
cwd: process.cwd(),
workspace: {} as any, // Would normally load workspace config
isVerbose: false,
projectName: target.project,
targetName: target.target,
configurationName: target.configuration,
projectGraph: context.projectGraph,
hash: task.hash
};
const executorResults = await runExecutor(target, task.overrides, executorContext);
let success = true;
for await (const result of executorResults) {
success = success && result.success;
}
results[task.id] = {
success,
startTime,
endTime: Date.now()
};
} catch (error) {
results[task.id] = {
success: false,
startTime,
endTime: Date.now(),
terminalOutput: error.message
};
}
}
return results;
}
}
export default CustomTasksRunner;import {
createTaskGraph,
parseTargetString,
createProjectGraphAsync,
readNxJson,
logger
} from "nx/src/devkit-exports";
async function analyzeTaskDependencies(targetStrings: string[]) {
const projectGraph = await createProjectGraphAsync();
const nxJson = readNxJson();
// Parse target strings
const targets = targetStrings.map(parseTargetString);
// Create task graph
const taskGraph = createTaskGraph(projectGraph, targets, nxJson, {});
logger.info(`Task Graph Analysis:`);
logger.info(` Total tasks: ${Object.keys(taskGraph.tasks).length}`);
logger.info(` Root tasks: ${taskGraph.roots.length}`);
// Find task dependencies
for (const [taskId, task] of Object.entries(taskGraph.tasks)) {
const dependencies = taskGraph.dependencies[taskId] || [];
logger.info(` ${task.target.project}:${task.target.target} depends on: ${dependencies.length} tasks`);
}
return taskGraph;
}import { ExecutorContext, logger } from "nx/src/devkit-exports";
interface CustomBuildOptions {
command: string;
args?: string[];
cwd?: string;
env?: Record<string, string>;
}
export default async function customBuildExecutor(
options: CustomBuildOptions,
context: ExecutorContext
): Promise<{ success: boolean }> {
logger.info(`Running custom build for ${context.projectName}`);
const { spawn } = await import('child_process');
return new Promise((resolve) => {
const child = spawn(options.command, options.args || [], {
cwd: options.cwd || context.root,
env: { ...process.env, ...options.env },
stdio: 'inherit'
});
child.on('close', (code) => {
const success = code === 0;
if (success) {
logger.info(`✅ Custom build completed successfully`);
} else {
logger.error(`❌ Custom build failed with code ${code}`);
}
resolve({ success });
});
child.on('error', (error) => {
logger.error(`Failed to start custom build: ${error.message}`);
resolve({ success: false });
});
});
}
// Executor schema (schema.json)
export const schema: ExecutorSchema = {
version: 1,
title: 'Custom Build Executor',
description: 'Runs a custom build command',
type: 'object',
properties: {
command: {
type: 'string',
description: 'Command to execute'
},
args: {
type: 'array',
description: 'Command arguments',
items: { type: 'string' }
},
cwd: {
type: 'string',
description: 'Working directory'
},
env: {
type: 'object',
description: 'Environment variables'
}
},
required: ['command']
};import {
createTaskHasher,
createProjectGraphAsync,
readNxJson,
Task,
logger
} from "nx/src/devkit-exports";
async function computeTaskHashes(tasks: Task[]) {
const projectGraph = await createProjectGraphAsync();
const nxJson = readNxJson();
const hasher = createTaskHasher(projectGraph, nxJson);
logger.info('Computing task hashes...');
const hashes = await hasher.hashTasks(tasks);
for (const [taskId, hash] of Object.entries(hashes)) {
const task = tasks.find(t => t.id === taskId);
logger.info(`${task.target.project}:${task.target.target} -> ${hash}`);
}
return hashes;
}Install with Tessl CLI
npx tessl i tessl/npm-nx