@theholocron/cli 3.37.2 → 3.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -379,6 +379,63 @@ declare function resolvePluginPackage(provider: string): string;
379
379
  declare function resolveEntry(key: CapabilityKey, raw: RawProviderEntry): ResolvedProviderEntry;
380
380
  declare function resolveConfig(raw: HolocronConfig): ResolvedHolocronConfig;
381
381
  //#endregion
382
+ //#region src/compose.d.ts
383
+ type WorkflowEntry = NonNullable<HolocronConfig["workflows"]>[number];
384
+ /** A single composable capability fragment. */
385
+ interface Capability {
386
+ /** Unique identifier — used for deduplication and dependency resolution. */
387
+ id: string;
388
+ /** Other capability IDs that must be present in the same compose() call. */
389
+ requires?: string[];
390
+ /** Workflow entries contributed by this capability. Merged by name; last writer wins. */
391
+ workflows?: WorkflowEntry[];
392
+ /** Provider config. Shallow-merged at the top level; later capabilities override per-key. */
393
+ providers?: RawProvidersConfig;
394
+ /** CI check names that must pass. Unioned across all capabilities. */
395
+ requiredChecks?: string[];
396
+ /** Repo config fragment. Scalar fields: last writer wins. properties/topics/teams: merged. */
397
+ repo?: Partial<Omit<RepoConfig, "name">>;
398
+ /** Org name. Last writer wins. */
399
+ org?: string;
400
+ /** Org canonical domain. Last writer wins. */
401
+ domain?: string;
402
+ /** Docs site config. Last writer wins. */
403
+ docs?: DocsConfig;
404
+ }
405
+ /** The merged result of a compose() call. Spreads into defineConfig(). */
406
+ interface ComposedPreset {
407
+ workflows: WorkflowEntry[];
408
+ providers: RawProvidersConfig;
409
+ repo: Partial<Omit<RepoConfig, "name">> & {
410
+ requiredChecks: string[];
411
+ };
412
+ org?: string;
413
+ domain?: string;
414
+ docs?: DocsConfig;
415
+ }
416
+ /**
417
+ * Merge any number of capability fragments into a single preset object that
418
+ * spreads directly into `defineConfig()`.
419
+ *
420
+ * - Accepts individual capabilities or nested arrays (for bundle presets).
421
+ * - Deduplicates by `id` — when the same ID appears more than once, the last
422
+ * occurrence wins. This lets callers override bundle defaults by listing an
423
+ * explicit capability after the bundle.
424
+ * - Validates all `requires` at call time and throws `ConfigError` if any are
425
+ * unmet, listing every missing dependency in a single message.
426
+ *
427
+ * @example
428
+ * // docs-only site — no typecheck
429
+ * const preset = compose(node(), docs());
430
+ *
431
+ * // library with docs
432
+ * const preset = compose(node(), typecheck(), docs());
433
+ *
434
+ * // nextjs() is a bundle that returns Capability[]
435
+ * const preset = compose(node(), nextjs());
436
+ */
437
+ declare function compose(...args: (Capability | Capability[])[]): ComposedPreset;
438
+ //#endregion
382
439
  //#region src/define-config.d.ts
383
440
  declare function defineConfig(config: HolocronConfig): HolocronConfig;
384
441
  //#endregion
@@ -449,4 +506,4 @@ interface LoadedConfig {
449
506
  */
450
507
  declare function loadConfig(cwd: string): Promise<LoadedConfig>;
451
508
  //#endregion
452
- export { Analytics, AppConfig, Auth, AuthDescription, AuthError, AuthEvent, AuthEventType, AuthIdentity, AuthUser, CARDINALITY, CapabilityConfigPackage, CapabilityImpls, CapabilityKey, Cardinality, CardinalityFor, ChromaticProjectConfig, Ci, CiRun, CiRunFilter, CiRunStatus, ConfigError, ConfigFileError, ConnectionStringOptions, CreateAuthUserInput, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, DnsRecordType, DocsConfig, DoctorConfig, EnsureResult, EnvConfig, EnvLookup, Environment, EnvironmentReviewer, Environments, FeatureResolverConfig, HolocronConfig, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, LoadedConfig, MultiEntry, NormalizedAuthUser, Notifications, Observability, PagesConfig, ParseWebhookInput, ProviderApiError, ProviderIdentity, ProviderOptions, PullRequest, REQUIRED_CAPABILITIES, RawProviderEntry, RawProvidersConfig, RepoConfig, RepoProperties, RepoProtection, RepoRef, RepoSettings, type RequestOptions, ResolveTokenConfig, type ResolveTokenInput, ResolvedCapability, ResolvedHolocronConfig, ResolvedProviderEntry, ResolvedProvidersConfig, ResolvedTuple, type RestClient, type RestClientConfig, Ruleset, SecretScope, Secrets, SingleEntry, Source, StatusCategory, Storage, StorageBranch, StorybookDeployProject, TeamEntry, TeamPermission, Tooling, ToolingDoctorReport, TrackerDoctorReport, TrackerUser, Vault, WebhookDashboardInfo, WebhookVerificationError, WorkflowWithConfig, createEnvLookup, createFeatureResolver, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
509
+ export { Analytics, AppConfig, Auth, AuthDescription, AuthError, AuthEvent, AuthEventType, AuthIdentity, AuthUser, CARDINALITY, Capability, CapabilityConfigPackage, CapabilityImpls, CapabilityKey, Cardinality, CardinalityFor, ChromaticProjectConfig, Ci, CiRun, CiRunFilter, CiRunStatus, ComposedPreset, ConfigError, ConfigFileError, ConnectionStringOptions, CreateAuthUserInput, Deployment, DeploymentProject, DeploymentProjectSettings, DeploymentRecord, DeploymentTarget, DeploymentTrigger, Dns, DnsRecord, DnsRecordType, DocsConfig, DoctorConfig, EnsureResult, EnvConfig, EnvLookup, Environment, EnvironmentReviewer, Environments, FeatureResolverConfig, HolocronConfig, Issue, IssueSearchFilter, Issues, LabelDef, LifecycleResult, LifecycleSlot, LoadedConfig, MultiEntry, NormalizedAuthUser, Notifications, Observability, PagesConfig, ParseWebhookInput, ProviderApiError, ProviderIdentity, ProviderOptions, PullRequest, REQUIRED_CAPABILITIES, RawProviderEntry, RawProvidersConfig, RepoConfig, RepoProperties, RepoProtection, RepoRef, RepoSettings, type RequestOptions, ResolveTokenConfig, type ResolveTokenInput, ResolvedCapability, ResolvedHolocronConfig, ResolvedProviderEntry, ResolvedProvidersConfig, ResolvedTuple, type RestClient, type RestClientConfig, Ruleset, SecretScope, Secrets, SingleEntry, Source, StatusCategory, Storage, StorageBranch, StorybookDeployProject, TeamEntry, TeamPermission, Tooling, ToolingDoctorReport, TrackerDoctorReport, TrackerUser, Vault, WebhookDashboardInfo, WebhookVerificationError, WorkflowWithConfig, compose, createEnvLookup, createFeatureResolver, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
package/dist/index.mjs CHANGED
@@ -244,6 +244,96 @@ function resolveConfig(raw) {
244
244
  };
245
245
  }
246
246
  //#endregion
247
+ //#region src/compose.ts
248
+ function workflowName(e) {
249
+ return typeof e === "string" ? e : e.name;
250
+ }
251
+ /**
252
+ * Merge any number of capability fragments into a single preset object that
253
+ * spreads directly into `defineConfig()`.
254
+ *
255
+ * - Accepts individual capabilities or nested arrays (for bundle presets).
256
+ * - Deduplicates by `id` — when the same ID appears more than once, the last
257
+ * occurrence wins. This lets callers override bundle defaults by listing an
258
+ * explicit capability after the bundle.
259
+ * - Validates all `requires` at call time and throws `ConfigError` if any are
260
+ * unmet, listing every missing dependency in a single message.
261
+ *
262
+ * @example
263
+ * // docs-only site — no typecheck
264
+ * const preset = compose(node(), docs());
265
+ *
266
+ * // library with docs
267
+ * const preset = compose(node(), typecheck(), docs());
268
+ *
269
+ * // nextjs() is a bundle that returns Capability[]
270
+ * const preset = compose(node(), nextjs());
271
+ */
272
+ function compose(...args) {
273
+ const flat = args.flat();
274
+ const byId = /* @__PURE__ */ new Map();
275
+ for (const cap of flat) byId.set(cap.id, cap);
276
+ const caps = [...byId.values()];
277
+ const available = new Set(caps.map((c) => c.id));
278
+ const errors = [];
279
+ for (const cap of caps) for (const req of cap.requires ?? []) if (!available.has(req)) errors.push(`"${cap.id}" requires "${req}"`);
280
+ if (errors.length > 0) throw new ConfigError(`compose(): unmet dependencies — ${errors.join(", ")}`);
281
+ const workflowMap = /* @__PURE__ */ new Map();
282
+ for (const cap of caps) for (const entry of cap.workflows ?? []) workflowMap.set(workflowName(entry), entry);
283
+ let providers = {};
284
+ for (const cap of caps) if (cap.providers) providers = {
285
+ ...providers,
286
+ ...cap.providers
287
+ };
288
+ const checksSeen = /* @__PURE__ */ new Set();
289
+ const requiredChecks = [];
290
+ for (const cap of caps) for (const check of cap.requiredChecks ?? []) if (!checksSeen.has(check)) {
291
+ checksSeen.add(check);
292
+ requiredChecks.push(check);
293
+ }
294
+ let repo = {};
295
+ for (const cap of caps) {
296
+ if (!cap.repo) continue;
297
+ const { properties, topics, teams, ...scalars } = cap.repo;
298
+ repo = {
299
+ ...repo,
300
+ ...scalars
301
+ };
302
+ if (properties) repo.properties = {
303
+ ...repo.properties,
304
+ ...properties
305
+ };
306
+ if (topics) {
307
+ const merged = /* @__PURE__ */ new Set([...repo.topics ?? [], ...topics]);
308
+ repo.topics = [...merged];
309
+ }
310
+ if (teams) {
311
+ const teamMap = new Map((repo.teams ?? []).map((t) => [typeof t === "string" ? t : t.slug, t]));
312
+ for (const t of teams) teamMap.set(typeof t === "string" ? t : t.slug, t);
313
+ repo.teams = [...teamMap.values()];
314
+ }
315
+ }
316
+ let org;
317
+ let domain;
318
+ let docs;
319
+ for (const cap of caps) {
320
+ if (cap.org !== void 0) org = cap.org;
321
+ if (cap.domain !== void 0) domain = cap.domain;
322
+ if (cap.docs !== void 0) docs = cap.docs;
323
+ }
324
+ return {
325
+ workflows: [...workflowMap.values()],
326
+ providers,
327
+ repo: {
328
+ ...repo,
329
+ requiredChecks
330
+ },
331
+ ...org !== void 0 ? { org } : {},
332
+ ...domain !== void 0 ? { domain } : {},
333
+ ...docs !== void 0 ? { docs } : {}
334
+ };
335
+ }
336
+ //#endregion
247
337
  //#region src/define-config.ts
248
338
  function defineConfig(config) {
249
339
  return config;
@@ -367,4 +457,4 @@ async function fileExists(path) {
367
457
  }
368
458
  }
369
459
  //#endregion
370
- export { AuthError, CARDINALITY, ConfigError, ConfigFileError, ProviderApiError, REQUIRED_CAPABILITIES, WebhookVerificationError, createEnvLookup, createFeatureResolver, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
460
+ export { AuthError, CARDINALITY, ConfigError, ConfigFileError, ProviderApiError, REQUIRED_CAPABILITIES, WebhookVerificationError, compose, createEnvLookup, createFeatureResolver, createResolveToken, createRestClient, defineConfig, deleteToken, getToken, isMulti, listStoredProviders, loadConfig, resolveConfig, resolveEntry, resolvePluginPackage, setToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theholocron/cli",
3
- "version": "3.37.2",
3
+ "version": "3.38.1",
4
4
  "description": "The Holocron CLI — a pluggable, capability-based orchestrator for spinning up and operating software projects.",
5
5
  "keywords": [
6
6
  "cli",