@hilbras/omninode 2.0.0-alpha.14 → 2.0.0-alpha.16

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.ts CHANGED
@@ -1502,6 +1502,10 @@ declare const projectConfigSchema: z.ZodObject<{
1502
1502
  } | undefined;
1503
1503
  }>;
1504
1504
  declare const appConfigSchema: z.ZodObject<{
1505
+ /** Active profile; overlays live under `profiles` (§16). */
1506
+ profile: z.ZodOptional<z.ZodString>;
1507
+ /** Named partial overlays, e.g. development/production/testing. */
1508
+ profiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1505
1509
  project: z.ZodObject<{
1506
1510
  name: z.ZodString;
1507
1511
  providers: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -1924,6 +1928,8 @@ declare const appConfigSchema: z.ZodObject<{
1924
1928
  required?: boolean | undefined;
1925
1929
  } | undefined;
1926
1930
  };
1931
+ profile?: string | undefined;
1932
+ profiles?: Record<string, unknown> | undefined;
1927
1933
  logging?: {
1928
1934
  level: "info" | "error" | "debug" | "warn";
1929
1935
  format?: "text" | "json" | undefined;
@@ -1997,6 +2003,8 @@ declare const appConfigSchema: z.ZodObject<{
1997
2003
  required?: boolean | undefined;
1998
2004
  } | undefined;
1999
2005
  };
2006
+ profile?: string | undefined;
2007
+ profiles?: Record<string, unknown> | undefined;
2000
2008
  logging?: {
2001
2009
  level: "info" | "error" | "debug" | "warn";
2002
2010
  format?: "text" | "json" | undefined;
@@ -2055,11 +2063,13 @@ interface AppConfig {
2055
2063
  };
2056
2064
  }
2057
2065
  interface LoadConfigOptions {
2058
- /** Explicit path; otherwise omninode.yaml/yml/json is looked up in the given directory. */
2066
+ /** Explicit path (CLI --config); otherwise the project file is discovered. */
2059
2067
  path?: string;
2060
2068
  directory?: string;
2061
- /** Environment used for ${VAR} expansion; defaults to process.env. */
2069
+ /** Environment used for ${VAR} expansion and OMNINODE_* overrides; defaults to process.env. */
2062
2070
  env?: Record<string, string | undefined>;
2071
+ /** Profile override (CLI --profile), above environment and file selection. */
2072
+ profile?: string;
2063
2073
  }
2064
2074
  declare function findConfigFile(directory?: string): string | undefined;
2065
2075
  /**
@@ -2068,7 +2078,58 @@ declare function findConfigFile(directory?: string): string | undefined;
2068
2078
  * authentication.
2069
2079
  */
2070
2080
  declare function expandEnvRefs(text: string, env: Record<string, string | undefined>, source?: string): string;
2081
+ interface LoadConfigResult {
2082
+ config: AppConfig;
2083
+ sources: ConfigSources;
2084
+ }
2085
+ /**
2086
+ * Composes configuration from every source with the documented precedence
2087
+ * (roadmap §16): CLI → environment → project file → user file → profile
2088
+ * overlay → defaults.
2089
+ */
2090
+ declare function loadConfigDetailed(options?: LoadConfigOptions): LoadConfigResult;
2091
+ /** Backwards-compatible wrapper: the composed configuration. */
2071
2092
  declare function loadConfig(options?: LoadConfigOptions): AppConfig;
2093
+ /**
2094
+ * Actionable configuration diagnostics (roadmap §16) — the kind of message a
2095
+ * user can act on, rather than a generic schema failure.
2096
+ */
2097
+ declare function configDiagnostics(config: AppConfig): string[];
2098
+
2099
+ /** Loose input shape: composition happens before strict validation. */
2100
+ type AppConfigInput = Record<string, unknown>;
2101
+ declare const KNOWN_PROFILES: readonly ["default", "development", "production", "testing"];
2102
+ type ProfileName = (typeof KNOWN_PROFILES)[number];
2103
+ interface ConfigSources {
2104
+ /** Project-level configuration file, if any. */
2105
+ projectFile?: string;
2106
+ /** User-level configuration file, if any. */
2107
+ userFile?: string;
2108
+ /** Active profile. */
2109
+ profile: string;
2110
+ /** Environment variables that overrode configuration. */
2111
+ envOverrides: string[];
2112
+ /** Values that came from built-in defaults. */
2113
+ defaults: string[];
2114
+ }
2115
+ /** Default user-level configuration locations, most portable first. */
2116
+ declare function userConfigPath(env?: Record<string, string | undefined>): string;
2117
+ /** Picks the profile: CLI (applied by the loader) > environment > file > default. */
2118
+ declare function resolveProfile(input: {
2119
+ profile?: unknown;
2120
+ }, env: Record<string, string | undefined>): string;
2121
+ /** Deep-merges configuration overlays (objects merge, scalars/arrays replace). */
2122
+ declare function mergeConfig<T>(base: T, overlay: unknown): T;
2123
+ /** Environment overrides applied above every file source. */
2124
+ declare function applyEnvOverrides(input: AppConfigInput, env: Record<string, string | undefined>): {
2125
+ config: AppConfigInput;
2126
+ applied: string[];
2127
+ };
2128
+ /** Built-in defaults, applied last. */
2129
+ declare function applyDefaults(input: AppConfigInput): {
2130
+ config: AppConfigInput;
2131
+ applied: string[];
2132
+ };
2072
2133
 
2073
2134
  /** Template written by `omninode init` (§22, §23). */
2074
2135
  declare function defaultProjectConfigYaml(projectName?: string): string;
@@ -3151,6 +3212,6 @@ declare function migrateProjectStores(directory?: string, options?: {
3151
3212
  checkOnly?: boolean;
3152
3213
  }): Promise<MigrationReport[]>;
3153
3214
 
3154
- declare const OMNINODE_VERSION = "2.0.0-alpha.14";
3215
+ declare const OMNINODE_VERSION = "2.0.0-alpha.16";
3155
3216
 
3156
- export { AgentAdapterRegistry, type AgentConfig, type AgentConfigYaml, type AgentDescriptor, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigYaml, type ArtifactKind, type ArtifactPayload, type AskedQuestion, type AuditAction, type AuditEvent, type AuditSink, type AuditSink as AuditStore, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatStreamChunk, type ChatUsage, type CollectionDiagnostics, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, type ConflictPosition, ConsoleLogSink, type CreateTaskInput, type CwdValidation, DEFAULT_MAX_OUTPUT_BYTES, type DecodeResult, type DefaultChatOptions, type DiscoveryResult, type DocumentState, type Durability, type EnvPolicy, type EnvelopeMeta, type Evidence, type EvidenceInput, type EvidenceKind, type ExecutionRecord, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingOrigin, type FindingSeverity, type FindingSource, type HelloResult, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IAgentAdapter, type IChatProvider, type IMemoryProvider, type IPipelineExecutor, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, type LoadConfigOptions, LocalMemoryProvider, type LogFormat, type LogLevel, type LogSink, Logger, type LoggerOptions, MAX_CONTEXT_CHARS, MAX_MESSAGE_BYTES, MAX_REPORT_BYTES, type MemoryCategory, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryProviderMetadata, type MemoryQuery, type MemoryScope, MemoryService, type MemoryServiceOptions, LocalMemoryProvider as MemoryStore, type MemoryTaskContext, type MessageEnvelope, type MigrationReport, type Modality, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, PROTOCOL_V2, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunAttempt, type PipelineRunFilter, type PipelineRunOptions, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type PipelineRunStore as PipelineStore, type Plan, type PlanFilter, type PlanJsonResult, type PlanRequest, type PlanStep, type PlanStore, type PlanValidationIssue, type PlanValidationResult, type PlannerConfigYaml, PlannerError, ProcessAgent, ProcessAgentAdapter, type Project, type ProjectConfigYaml, ProjectStores, type ProtocolAgentToNodeType, ProtocolDecoder, type ProtocolEnvelope, ProtocolError, type ProtocolMessageType, type ProtocolNodeToAgentType, ProtocolSession, type ProtocolViolation, type ProtocolViolationCode, type ProviderAuthentication, type ProviderCapability, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderErrorKind, type ProviderHealth, type ProviderStatus, type ProviderType, type QuestionPayload, type QuestionResponder, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportArtifact, type ReportConflict, type ReportFilter, type ReportPayload, ReportService, type ReportStore, type ReportValidationIssue, type ReportValidationResult, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, SCHEMA_VERSION, STORE_FILES, SUPPORTED_PROTOCOL_VERSIONS, type SecretFinding, type SessionIds, TERMINAL_TASK_STATUSES, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskPayload, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, authHeaders, buildAgentRegistry, buildChildEnv, buildHello, buildHelloAck, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, configureLogger, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, decodeMessage, decodeStream, defaultMetadata, defaultProjectConfigYaml, defaultSearch, describeExit, describeSecretFindings, detectConflicts, encodeMessage, envelope, expandEnvRefs, extractMessage, extractReportFromText, findConfigFile, inspectDocument, isNetworkError, isOmniNodeError, isRetryable, isSupportedProtocol, isTimeoutError, keywords, killTree, kindFromStatus, loadConfig, logger, migrateProjectStores, newMessageId, normalizeEvidence, normalizeFinding, parseHello, parsePlanJson, parseRetryAfter, pipelineConfigSchema, pipelineStepConfigSchema, planJsonSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, providerHttpError, providerTransportError, readDocument, registryKey, requestJson, requireCompletion, resolveApiKey, resolveEnvPolicy, roleConfigSchema, sanitizeChunk, scanForInlineSecrets, similar, validateEnvelope, validatePlan, validateReport, validateWorkingDirectory, writeFileAtomic };
3217
+ export { AgentAdapterRegistry, type AgentConfig, type AgentConfigYaml, type AgentDescriptor, AgentError, type AgentInfo, type AgentInputMode, type AgentIntegrationType, AgentRegistry, type AgentStatus, type AgentTaskInput, type AgentTaskOutput, type AgentToNodeMessage, type AggregateOptions, type AggregatedFinding, type AggregatedRecommendation, type AppConfig, type AppConfigInput, type AppConfigYaml, type ArtifactKind, type ArtifactPayload, type AskedQuestion, type AuditAction, type AuditEvent, type AuditSink, type AuditSink as AuditStore, type ChatFn, type ChatMessage, type ChatRequest, type ChatResponse, type ChatRole, type ChatStreamChunk, type ChatUsage, type CollectionDiagnostics, type CombinedMeta, type CombinedReport, type CombinedReportFilter, type Confidence, ConfigError, type ConfigSources, type ConflictPosition, ConsoleLogSink, type CreateTaskInput, type CwdValidation, DEFAULT_MAX_OUTPUT_BYTES, type DecodeResult, type DefaultChatOptions, type DiscoveryResult, type DocumentState, type Durability, type EnvPolicy, type EnvelopeMeta, type Evidence, type EvidenceInput, type EvidenceKind, type ExecutionRecord, type ExtractionMeta, FileAuditLog, FilePipelineRunStore, FilePlanStore, FileReportStore, FileTaskStore, type Finding, type FindingOrigin, type FindingSeverity, type FindingSource, type HelloResult, HeuristicPlanner, type HttpRequestOptions, type HttpResponse, type IAgent, type IAgentAdapter, type IChatProvider, type IMemoryProvider, type IPipelineExecutor, type IPlanner, type IProvider, type JsonDocument, JsonFileStore, type JsonFileStoreOptions, KNOWN_PROFILES, type LoadConfigOptions, type LoadConfigResult, LocalMemoryProvider, type LogFormat, type LogLevel, type LogSink, Logger, type LoggerOptions, MAX_CONTEXT_CHARS, MAX_MESSAGE_BYTES, MAX_REPORT_BYTES, type MemoryCategory, type MemoryContextQuery, type MemoryEntry, MemoryError, type MemoryProviderConfig, type MemoryProviderMetadata, type MemoryQuery, type MemoryScope, MemoryService, type MemoryServiceOptions, LocalMemoryProvider as MemoryStore, type MemoryTaskContext, type MessageEnvelope, type MigrationReport, type Modality, type ModelCapabilities, type ModelFilter, type ModelInfo, ModelPlanner, ModelRegistry, type ModelStatus, type NodeToAgentMessage, OMNINODE_VERSION, OPENAI_COMPATIBLE_TYPES, type OmniHilbrasConnectionResult, OmniHilbrasProvider, OmniNodeError, type OmniNodeErrorCode, type OmniNodeErrorOptions, OpenAICompatibleProvider, PROTOCOL_V2, type PipelineConfigYaml, type PipelineDefinition, PipelineEngine, type PipelineEngineOptions, PipelineError, type PipelineRun, type PipelineRunAttempt, type PipelineRunFilter, type PipelineRunOptions, type PipelineRunStatus, type PipelineRunStore, type PipelineStep, type PipelineStepCondition, type PipelineStepConfigYaml, type PipelineStepKind, type PipelineStepRun, type PipelineRunStore as PipelineStore, type Plan, type PlanFilter, type PlanJsonResult, type PlanRequest, type PlanStep, type PlanStore, type PlanValidationIssue, type PlanValidationResult, type PlannerConfigYaml, PlannerError, ProcessAgent, ProcessAgentAdapter, type ProfileName, type Project, type ProjectConfigYaml, ProjectStores, type ProtocolAgentToNodeType, ProtocolDecoder, type ProtocolEnvelope, ProtocolError, type ProtocolMessageType, type ProtocolNodeToAgentType, ProtocolSession, type ProtocolViolation, type ProtocolViolationCode, type ProviderAuthentication, type ProviderCapability, type ProviderConfig, type ProviderConfigYaml, ProviderError, type ProviderErrorKind, type ProviderHealth, type ProviderStatus, type ProviderType, type QuestionPayload, type QuestionResponder, type RememberaConfig, RememberaMemoryProvider, type Report, type ReportArtifact, type ReportConflict, type ReportFilter, type ReportPayload, ReportService, type ReportStore, type ReportValidationIssue, type ReportValidationResult, type RoleConfigYaml, type RoleDefinition, RoleRegistry, type RunPipelineOptions, SCHEMA_VERSION, STORE_FILES, SUPPORTED_PROTOCOL_VERSIONS, type SecretFinding, type SessionIds, TERMINAL_TASK_STATUSES, type Task, type TaskContext, TaskEngine, type TaskEngineOptions, TaskError, type TaskPayload, type TaskResult, type TaskStatus, type TaskStore, type TaskStoreFilter, type WritableLike, agentConfigSchema, aggregateReports, appConfigSchema, applyDefaults, applyEnvOverrides, authHeaders, buildAgentRegistry, buildChildEnv, buildHello, buildHelloAck, buildPipelineEngine, buildPlanner, buildPlannerContext, buildRoleRegistry, composeTaskText, configDiagnostics, configureLogger, createAgent, createDefaultChatFn, createMemoryProvider, createProvider, createTaskEngine, decodeMessage, decodeStream, defaultMetadata, defaultProjectConfigYaml, defaultSearch, describeExit, describeSecretFindings, detectConflicts, encodeMessage, envelope, expandEnvRefs, extractMessage, extractReportFromText, findConfigFile, inspectDocument, isNetworkError, isOmniNodeError, isRetryable, isSupportedProtocol, isTimeoutError, keywords, killTree, kindFromStatus, loadConfig, loadConfigDetailed, logger, mergeConfig, migrateProjectStores, newMessageId, normalizeEvidence, normalizeFinding, parseHello, parsePlanJson, parseRetryAfter, pipelineConfigSchema, pipelineStepConfigSchema, planJsonSchema, plannerConfigSchema, projectConfigSchema, providerConfigSchema, providerHttpError, providerTransportError, readDocument, registryKey, requestJson, requireCompletion, resolveApiKey, resolveEnvPolicy, resolveProfile, roleConfigSchema, sanitizeChunk, scanForInlineSecrets, similar, userConfigPath, validateEnvelope, validatePlan, validateReport, validateWorkingDirectory, writeFileAtomic };
package/dist/index.js CHANGED
@@ -210,6 +210,10 @@ var projectConfigSchema = z.object({
210
210
  }).strict().optional()
211
211
  }).strict();
212
212
  var appConfigSchema = z.object({
213
+ /** Active profile; overlays live under `profiles` (§16). */
214
+ profile: z.string().min(1).optional(),
215
+ /** Named partial overlays, e.g. development/production/testing. */
216
+ profiles: z.record(z.unknown()).optional(),
213
217
  project: projectConfigSchema,
214
218
  logging: z.object({
215
219
  level: z.enum(["debug", "info", "warn", "error"]),
@@ -250,6 +254,86 @@ ${lines}
250
254
  OmniNode never stores credentials in configuration. Replace each value with an environment-variable reference, e.g. api_key_env_var: MY_API_KEY.`;
251
255
  }
252
256
 
257
+ // src/config/profiles.ts
258
+ import { homedir } from "os";
259
+ import path from "path";
260
+ var KNOWN_PROFILES = ["default", "development", "production", "testing"];
261
+ function userConfigPath(env = process.env) {
262
+ if (env.OMNINODE_USER_CONFIG) return env.OMNINODE_USER_CONFIG;
263
+ const home = env.HOME ?? homedir();
264
+ return path.join(home, ".omninode", "config.yaml");
265
+ }
266
+ function resolveProfile(input, env) {
267
+ if (env.OMNINODE_PROFILE) return env.OMNINODE_PROFILE;
268
+ if (typeof input.profile === "string" && input.profile.length > 0) return input.profile;
269
+ return "default";
270
+ }
271
+ function mergeConfig(base, overlay) {
272
+ if (!isPlainObject(base) || !isPlainObject(overlay)) {
273
+ return overlay === void 0 ? base : overlay;
274
+ }
275
+ const result = { ...base };
276
+ for (const [key, value] of Object.entries(overlay)) {
277
+ const existing = result[key];
278
+ if (Array.isArray(value)) {
279
+ result[key] = value;
280
+ } else if (isPlainObject(value) && isPlainObject(existing)) {
281
+ result[key] = mergeConfig(existing, value);
282
+ } else {
283
+ result[key] = value;
284
+ }
285
+ }
286
+ return result;
287
+ }
288
+ function isPlainObject(value) {
289
+ return value !== null && typeof value === "object" && !Array.isArray(value);
290
+ }
291
+ function asObject(value) {
292
+ return isPlainObject(value) ? value : {};
293
+ }
294
+ function applyEnvOverrides(input, env) {
295
+ const applied = [];
296
+ const config = mergeConfig(input, {});
297
+ if (env.OMNINODE_LOG_LEVEL) {
298
+ config.logging = { ...asObject(config.logging), level: env.OMNINODE_LOG_LEVEL };
299
+ applied.push("OMNINODE_LOG_LEVEL");
300
+ }
301
+ if (env.OMNINODE_LOG_FORMAT) {
302
+ config.logging = { ...asObject(config.logging), format: env.OMNINODE_LOG_FORMAT };
303
+ applied.push("OMNINODE_LOG_FORMAT");
304
+ }
305
+ const memoryProvider = env.OMNINODE_MEMORY_PROVIDER;
306
+ const memoryRequired = env.OMNINODE_MEMORY_REQUIRED;
307
+ if (memoryProvider || memoryRequired) {
308
+ const project = asObject(config.project);
309
+ config.project = {
310
+ ...project,
311
+ memory: {
312
+ ...asObject(project.memory ?? { provider: "local" }),
313
+ ...memoryProvider ? { provider: memoryProvider } : {},
314
+ ...memoryRequired ? { required: memoryRequired !== "false" } : {}
315
+ }
316
+ };
317
+ if (memoryProvider) applied.push("OMNINODE_MEMORY_PROVIDER");
318
+ if (memoryRequired) applied.push("OMNINODE_MEMORY_REQUIRED");
319
+ }
320
+ return { config, applied };
321
+ }
322
+ function applyDefaults(input) {
323
+ const applied = [];
324
+ const config = mergeConfig(input, {});
325
+ const logging = asObject(config.logging);
326
+ if (logging.level === void 0) {
327
+ config.logging = { ...logging, level: "info" };
328
+ applied.push("logging.level");
329
+ }
330
+ if (logging.format === void 0) {
331
+ config.logging = { ...asObject(config.logging), format: "text" };
332
+ applied.push("logging.format");
333
+ }
334
+ return { config, applied };
335
+ }
336
+
253
337
  // src/config/loader.ts
254
338
  import { existsSync, readFileSync } from "fs";
255
339
  import { parse as parseYaml } from "yaml";
@@ -276,38 +360,111 @@ function expandEnvRefs(text, env, source = "config") {
276
360
  }
277
361
  );
278
362
  }
279
- function loadConfig(options = {}) {
363
+ function loadConfigDetailed(options = {}) {
280
364
  const env = options.env ?? process.env;
281
- const path = options.path ?? (options.directory ? findConfigFile(options.directory) : findConfigFile());
282
- if (!path) {
365
+ const explicitPath = options.path;
366
+ let input = {};
367
+ let projectFile;
368
+ let userFile;
369
+ if (!explicitPath) {
370
+ const candidate = userConfigPath(env);
371
+ if (existsSync(candidate)) {
372
+ input = mergeConfig(input, readConfigDocument(candidate, env));
373
+ userFile = candidate;
374
+ }
375
+ }
376
+ const resolvedProject = explicitPath ?? (options.directory ? findConfigFile(options.directory) : findConfigFile());
377
+ if (resolvedProject) {
378
+ input = mergeConfig(input, readConfigDocument(resolvedProject, env));
379
+ projectFile = resolvedProject;
380
+ }
381
+ if (!projectFile && !userFile) {
283
382
  throw new ConfigError(
284
383
  "CONFIG_NOT_FOUND",
285
384
  "No omninode.yaml found. Run `omninode init` to create one, or pass an explicit path."
286
385
  );
287
386
  }
288
- const raw = readFileSync(path, "utf8");
387
+ const profile = options.profile ?? resolveProfile(input, env);
388
+ const overlay = input.profiles?.[profile];
389
+ if (overlay !== void 0) {
390
+ const { profiles: _drop, ...base } = input;
391
+ input = mergeConfig(base, overlay);
392
+ } else if (profile !== "default" && profile !== "") {
393
+ throw new ConfigError(
394
+ "CONFIG_INVALID",
395
+ `Profile "${profile}" is not defined in this configuration (known: ${Object.keys(input.profiles ?? {}).join(", ") || "none"}).`
396
+ );
397
+ }
398
+ const withEnv = applyEnvOverrides(input, env);
399
+ const withDefaults = applyDefaults(withEnv.config);
400
+ const parsed = appConfigSchema.safeParse(withDefaults.config);
401
+ if (!parsed.success) {
402
+ const issues = parsed.error.issues.map((issue) => {
403
+ const location = issue.path.join(".") || "(root)";
404
+ return `${location}: ${issue.message}`;
405
+ });
406
+ throw new ConfigError(
407
+ "CONFIG_INVALID",
408
+ `Invalid configuration:
409
+ ${issues.join("\n ")}`,
410
+ { details: { issues } }
411
+ );
412
+ }
413
+ return {
414
+ config: toAppConfig(parsed.data),
415
+ sources: {
416
+ ...projectFile !== void 0 ? { projectFile } : {},
417
+ ...userFile !== void 0 ? { userFile } : {},
418
+ profile,
419
+ envOverrides: withEnv.applied,
420
+ defaults: withDefaults.applied
421
+ }
422
+ };
423
+ }
424
+ function readConfigDocument(path2, optionsEnv) {
425
+ const raw = readFileSync(path2, "utf8");
289
426
  const secretFindings = scanForInlineSecrets(raw);
290
427
  if (secretFindings.length > 0) {
291
- throw new ConfigError("CONFIG_INVALID", describeSecretFindings(path, secretFindings));
428
+ throw new ConfigError("CONFIG_INVALID", describeSecretFindings(path2, secretFindings));
292
429
  }
293
- const expanded = expandEnvRefs(raw, env, path);
294
- let data;
430
+ const expanded = expandEnvRefs(raw, optionsEnv, path2);
295
431
  try {
296
- data = parseYaml(expanded);
432
+ return parseYaml(expanded);
297
433
  } catch (error) {
298
- throw new ConfigError("CONFIG_INVALID", `Failed to parse ${path}.`, { cause: error });
434
+ throw new ConfigError("CONFIG_INVALID", `Failed to parse ${path2}.`, { cause: error });
299
435
  }
300
- const parsed = appConfigSchema.safeParse(data);
301
- if (!parsed.success) {
302
- const issues = parsed.error.issues.map((issue) => {
303
- const location = issue.path.length > 0 ? issue.path.join(".") : "(root)";
304
- return `${location}: ${issue.message}`;
305
- });
306
- throw new ConfigError("CONFIG_INVALID", `Invalid configuration in ${path}.`, {
307
- details: { issues }
308
- });
436
+ }
437
+ function loadConfig(options = {}) {
438
+ return loadConfigDetailed(options).config;
439
+ }
440
+ function configDiagnostics(config) {
441
+ const notes = [];
442
+ for (const provider of config.project.providers) {
443
+ if (!provider.apiKeyEnvVar && provider.baseUrl.startsWith("https://")) {
444
+ notes.push(
445
+ `Provider "${provider.name}": API key reference is missing \u2014 add api_key_env_var: <ENV_VAR> unless this endpoint is intentionally keyless.`
446
+ );
447
+ }
448
+ }
449
+ for (const agent of config.project.agents) {
450
+ if (!agent.command && agent.integration !== "custom") {
451
+ notes.push(`Agent "${agent.name}": no command configured \u2014 the process adapter needs one.`);
452
+ }
453
+ if (agent.allowExternalCwd) {
454
+ notes.push(`Agent "${agent.name}": may run outside the project root (allow_external_cwd).`);
455
+ }
456
+ }
457
+ for (const pipeline of config.project.pipelines) {
458
+ const ids = new Set(pipeline.steps.map((s) => s.id));
459
+ for (const step of pipeline.steps) {
460
+ for (const dep of step.dependsOn ?? []) {
461
+ if (!ids.has(dep)) {
462
+ notes.push(`Pipeline "${pipeline.id}": step "${step.id}" depends on unknown step "${dep}".`);
463
+ }
464
+ }
465
+ }
309
466
  }
310
- return toAppConfig(parsed.data);
467
+ return notes;
311
468
  }
312
469
  function toAppConfig(yaml) {
313
470
  return {
@@ -1942,15 +2099,15 @@ async function writeFileAtomic(target, contents, durability = "rename") {
1942
2099
  }
1943
2100
  }
1944
2101
  }
1945
- async function inspectDocument(path) {
2102
+ async function inspectDocument(path2) {
1946
2103
  let raw;
1947
2104
  try {
1948
- await stat(path);
2105
+ await stat(path2);
1949
2106
  } catch {
1950
2107
  return { status: "missing" };
1951
2108
  }
1952
2109
  try {
1953
- raw = await readFile(path, "utf8");
2110
+ raw = await readFile(path2, "utf8");
1954
2111
  } catch (error) {
1955
2112
  return { status: "corrupt", detail: `unreadable: ${error instanceof Error ? error.message : String(error)}` };
1956
2113
  }
@@ -1970,21 +2127,21 @@ async function inspectDocument(path) {
1970
2127
  if (version < SCHEMA_VERSION) return { status: "v1-legacy" };
1971
2128
  return { status: "current", schemaVersion: version, count: doc.items.length };
1972
2129
  }
1973
- async function readDocument(path, onCorrupt, quarantine = true) {
1974
- const state = await inspectDocument(path);
2130
+ async function readDocument(path2, onCorrupt, quarantine = true) {
2131
+ const state = await inspectDocument(path2);
1975
2132
  if (state.status === "missing" || state.status === "empty") return [];
1976
2133
  if (state.status === "future") {
1977
2134
  const error = new Error(
1978
- `${path} was written by a newer OmniNode (schema v${state.schemaVersion} > v${SCHEMA_VERSION})`
2135
+ `${path2} was written by a newer OmniNode (schema v${state.schemaVersion} > v${SCHEMA_VERSION})`
1979
2136
  );
1980
- onCorrupt?.(path, error);
2137
+ onCorrupt?.(path2, error);
1981
2138
  return [];
1982
2139
  }
1983
2140
  let raw;
1984
2141
  try {
1985
- raw = await readFile(path, "utf8");
2142
+ raw = await readFile(path2, "utf8");
1986
2143
  } catch (error) {
1987
- onCorrupt?.(path, error);
2144
+ onCorrupt?.(path2, error);
1988
2145
  return [];
1989
2146
  }
1990
2147
  try {
@@ -1993,16 +2150,16 @@ async function readDocument(path, onCorrupt, quarantine = true) {
1993
2150
  return parsed.items ?? [];
1994
2151
  } catch (error) {
1995
2152
  if (quarantine) {
1996
- const quarantinePath = `${path}.corrupt-${Date.now()}`;
2153
+ const quarantinePath = `${path2}.corrupt-${Date.now()}`;
1997
2154
  try {
1998
- await rename(path, quarantinePath);
2155
+ await rename(path2, quarantinePath);
1999
2156
  logger.child({ component: "persistence" }).warn(
2000
- `Quarantined unreadable store file ${path} \u2192 ${quarantinePath}`
2157
+ `Quarantined unreadable store file ${path2} \u2192 ${quarantinePath}`
2001
2158
  );
2002
2159
  } catch {
2003
2160
  }
2004
2161
  }
2005
- onCorrupt?.(path, error);
2162
+ onCorrupt?.(path2, error);
2006
2163
  return [];
2007
2164
  }
2008
2165
  }
@@ -4208,8 +4365,8 @@ var STORE_FILES = [
4208
4365
  async function migrateProjectStores(directory = `${process.cwd()}/.omninode`, options = {}) {
4209
4366
  const reports = [];
4210
4367
  for (const file of STORE_FILES) {
4211
- const path = `${directory}/${file}`;
4212
- const state = await inspectDocument(path);
4368
+ const path2 = `${directory}/${file}`;
4369
+ const state = await inspectDocument(path2);
4213
4370
  if (state.status === "missing") {
4214
4371
  reports.push({ file, state: state.status, migrated: false });
4215
4372
  continue;
@@ -4231,9 +4388,9 @@ async function migrateProjectStores(directory = `${process.cwd()}/.omninode`, op
4231
4388
  reports.push({ file, state: state.status, migrated: false, note: state.detail });
4232
4389
  continue;
4233
4390
  }
4234
- const items = await readDocument(path, void 0, false);
4391
+ const items = await readDocument(path2, void 0, false);
4235
4392
  if (!options.checkOnly) {
4236
- await writeFileAtomic(path, `${JSON.stringify({ schemaVersion: SCHEMA_VERSION, items }, null, 2)}
4393
+ await writeFileAtomic(path2, `${JSON.stringify({ schemaVersion: SCHEMA_VERSION, items }, null, 2)}
4237
4394
  `);
4238
4395
  }
4239
4396
  const beforeCount = items.length;
@@ -4250,7 +4407,7 @@ async function migrateProjectStores(directory = `${process.cwd()}/.omninode`, op
4250
4407
  }
4251
4408
 
4252
4409
  // src/version.ts
4253
- var OMNINODE_VERSION = "2.0.0-alpha.14";
4410
+ var OMNINODE_VERSION = "2.0.0-alpha.16";
4254
4411
  export {
4255
4412
  AgentAdapterRegistry,
4256
4413
  AgentError,
@@ -4265,6 +4422,7 @@ export {
4265
4422
  FileTaskStore,
4266
4423
  HeuristicPlanner,
4267
4424
  JsonFileStore,
4425
+ KNOWN_PROFILES,
4268
4426
  LocalMemoryProvider,
4269
4427
  Logger,
4270
4428
  MAX_CONTEXT_CHARS,
@@ -4302,6 +4460,8 @@ export {
4302
4460
  agentConfigSchema,
4303
4461
  aggregateReports,
4304
4462
  appConfigSchema,
4463
+ applyDefaults,
4464
+ applyEnvOverrides,
4305
4465
  authHeaders,
4306
4466
  buildAgentRegistry,
4307
4467
  buildChildEnv,
@@ -4312,6 +4472,7 @@ export {
4312
4472
  buildPlannerContext,
4313
4473
  buildRoleRegistry,
4314
4474
  composeTaskText,
4475
+ configDiagnostics,
4315
4476
  configureLogger,
4316
4477
  createAgent,
4317
4478
  createDefaultChatFn,
@@ -4342,7 +4503,9 @@ export {
4342
4503
  killTree,
4343
4504
  kindFromStatus,
4344
4505
  loadConfig,
4506
+ loadConfigDetailed,
4345
4507
  logger,
4508
+ mergeConfig,
4346
4509
  migrateProjectStores,
4347
4510
  newMessageId,
4348
4511
  normalizeEvidence,
@@ -4364,10 +4527,12 @@ export {
4364
4527
  requireCompletion,
4365
4528
  resolveApiKey,
4366
4529
  resolveEnvPolicy,
4530
+ resolveProfile,
4367
4531
  roleConfigSchema,
4368
4532
  sanitizeChunk,
4369
4533
  scanForInlineSecrets,
4370
4534
  similar,
4535
+ userConfigPath,
4371
4536
  validateEnvelope,
4372
4537
  validatePlan,
4373
4538
  validateReport,