/**
* Solution bundle catalog: finds bundle templates on disk.
*
* Bundles are ordinary team templates with a `bundle` section. They are read
* from the OSS `config/templates/` and from every directory in
* `CREWLY_TEMPLATE_DIRS` (path-delimited). Crewly Pro sets that variable to
* its own `config/templates/` when it starts the engine, which is how paid
* bundles reach a Pro or hosted install without living in the OSS repo.
*
* Both layouts are read: `
//template.json` (relative files such as
* `norms/*.md` resolve against `//`) and flat `/.json`.
* The first directory that defines an id wins.
*
* @module services/bundle/bundle-catalog
*/
import type { BundleTemplate, LoadedBundle } from '../../types/solution-bundle.types.js';
import { type BundleValidation } from './bundle-manifest.js';
/** A bundle found on disk with its validation result. */
export interface BundleCatalogEntry extends LoadedBundle {
validation: BundleValidation;
}
/** Result of a scan. */
export interface BundleCatalogScan {
/** Valid bundles, first definition of each id */
bundles: BundleCatalogEntry[];
/** Files with a bundle section that failed validation */
invalid: Array<{
file: string;
id: string | null;
errors: string[];
}>;
}
/** Owner-facing summary of a bundle (lists, starter cards). */
export interface BundleSummary {
id: string;
name: string;
label: string;
tagline: string;
description: string;
status: string;
tier: string | null;
recommendedRuntime: string;
serverTier: string;
memberCount: number;
questionCount: number;
}
/** Everything the owner sees before deploying (questions included). */
export interface BundleDetail extends BundleSummary {
ownerSummary: string;
ownerDoes: string[];
runtime: BundleTemplate['bundle']['runtime'];
server: BundleTemplate['bundle']['server'];
questions: NonNullable;
teams: Array<{
key: string;
name: string;
members: Array<{
name: string;
role: string;
title: string;
}>;
}>;
skills: string[];
connectors: NonNullable;
schedules: Array<{
id: string;
title: string;
cron: string;
}>;
firstWeek: Array<{
id: string;
day: number;
title: string;
}>;
channels: string[];
}
/**
* Read a UTF-8 file, or null when it does not exist / cannot be read.
*
* @param file - Absolute path
* @returns Content or null
*/
export declare function readTextOrNull(file: string): string | null;
/**
* The template directories to scan: the given base dirs, then every entry
* of `CREWLY_TEMPLATE_DIRS`. Duplicates and empty entries are dropped.
*
* @param baseDirs - Directories that always come first (the OSS templates)
* @param env - Environment (tests)
* @returns Absolute directories, in priority order
*/
export declare function resolveTemplateDirs(baseDirs: string[], env?: NodeJS.ProcessEnv): string[];
/**
* The template directories to read bundles from.
*
* @param packageRoot - Crewly package root
* @param extra - Extra directories (CLI `--templates-dir`)
* @param env - Environment
* @returns Directories in priority order: OSS templates, extra, CREWLY_TEMPLATE_DIRS
*/
export declare function bundleTemplateDirs(packageRoot: string, extra?: string[], env?: NodeJS.ProcessEnv): string[];
/**
* Scan directories for bundle templates.
*
* @param dirs - Directories in priority order
* @returns Valid bundles and invalid files
*
* @example
* const { bundles } = scanBundles(resolveTemplateDirs([ossTemplatesDir]));
*/
export declare function scanBundles(dirs: string[]): BundleCatalogScan;
/**
* Bundle catalog over a set of directories. Re-scans on every call (a
* handful of small files), so templates added on disk show up without a
* restart.
*/
export declare class BundleCatalog {
private readonly getDirs;
/**
* @param getDirs - Directories to scan, in priority order
*/
constructor(getDirs: () => string[]);
/**
* Every valid bundle.
*
* @param options - `includeDrafts` to list drafts too
* @returns Bundles
*/
list(options?: {
includeDrafts?: boolean;
}): BundleCatalogEntry[];
/**
* One bundle by template id (drafts included).
*
* @param templateId - Template id
* @returns The bundle, or null
*/
get(templateId: string): BundleCatalogEntry | null;
/**
* Files with a bundle section that failed validation (for diagnostics).
*
* @returns Invalid files with their errors
*/
invalid(): BundleCatalogScan['invalid'];
}
/**
* Whether a bundle may be deployed without `allowDraft`.
*
* @param template - Bundle template
* @returns True unless the status is `draft`
*/
export declare function isReady(template: BundleTemplate): boolean;
/**
* The summary shown in lists.
*
* @param template - Bundle template
* @returns Summary
*/
export declare function toBundleSummary(template: BundleTemplate): BundleSummary;
/**
* The detail shown before deploying: questions, members, what gets set up.
*
* @param template - Bundle template
* @returns Detail
*/
export declare function toBundleDetail(template: BundleTemplate): BundleDetail;
//# sourceMappingURL=bundle-catalog.d.ts.map