/** * 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