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

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.js CHANGED
@@ -80,16 +80,19 @@ var ConsoleLogSink = class {
80
80
  };
81
81
  var Logger = class _Logger {
82
82
  level;
83
+ format;
83
84
  sink;
84
85
  context;
85
86
  constructor(options = {}) {
86
87
  this.level = options.level ?? "info";
88
+ this.format = options.format ?? "text";
87
89
  this.sink = options.sink ?? new ConsoleLogSink();
88
90
  this.context = options.context ?? {};
89
91
  }
90
92
  child(context) {
91
93
  return new _Logger({
92
94
  level: this.level,
95
+ format: this.format,
93
96
  sink: this.sink,
94
97
  context: { ...this.context, ...context }
95
98
  });
@@ -108,8 +111,13 @@ var Logger = class _Logger {
108
111
  }
109
112
  log(level, message, data) {
110
113
  if (LEVEL_ORDER[level] < LEVEL_ORDER[this.level]) return;
111
- const parts = [(/* @__PURE__ */ new Date()).toISOString(), level.toUpperCase(), message];
114
+ const at = (/* @__PURE__ */ new Date()).toISOString();
112
115
  const merged = { ...this.context, ...data };
116
+ if (this.format === "json") {
117
+ this.sink.write(level, JSON.stringify({ at, level, message, ...merged }));
118
+ return;
119
+ }
120
+ const parts = [at, level.toUpperCase(), message];
113
121
  if (Object.keys(merged).length > 0) {
114
122
  parts.push(JSON.stringify(merged));
115
123
  }
@@ -117,6 +125,10 @@ var Logger = class _Logger {
117
125
  }
118
126
  };
119
127
  var logger = new Logger();
128
+ function configureLogger(options) {
129
+ if (options.level !== void 0) logger.level = options.level;
130
+ if (options.format !== void 0) logger.format = options.format;
131
+ }
120
132
 
121
133
  // src/config/schema.ts
122
134
  import { z } from "zod";
@@ -199,9 +211,45 @@ var projectConfigSchema = z.object({
199
211
  }).strict();
200
212
  var appConfigSchema = z.object({
201
213
  project: projectConfigSchema,
202
- logging: z.object({ level: z.enum(["debug", "info", "warn", "error"]) }).strict().optional()
214
+ logging: z.object({
215
+ level: z.enum(["debug", "info", "warn", "error"]),
216
+ format: z.enum(["text", "json"]).optional()
217
+ }).strict().optional()
203
218
  }).strict();
204
219
 
220
+ // src/config/secrets.ts
221
+ var SAFE_KEY_SUFFIXES = ["_env", "_env_var", "_file", "_path", "_ref", "_id", "_url", "_command"];
222
+ var SECRET_KEY = /^\s*([A-Za-z0-9_-]*(?:api[_-]?key|token|password|passwd|secret|credential)[A-Za-z0-9_-]*)\s*:\s*(.*)$/i;
223
+ var SAFE_VALUE = /^\s*(?:\$\{[^}]*\}|\$[A-Z_][A-Z0-9_]*|<[^>]*>|""|''|null|~)\s*$/i;
224
+ function scanForInlineSecrets(source) {
225
+ const findings = [];
226
+ source.split("\n").forEach((line, index) => {
227
+ const trimmed = line.trim();
228
+ if (trimmed.startsWith("#")) return;
229
+ const match = SECRET_KEY.exec(line);
230
+ if (!match) return;
231
+ const key = match[1] ?? "";
232
+ const rawValue = (match[2] ?? "").trim().replace(/,\s*$/, "");
233
+ const keyIsReference = SAFE_KEY_SUFFIXES.some((suffix) => key.toLowerCase().endsWith(suffix));
234
+ if (keyIsReference) return;
235
+ const value = rawValue.replace(/^["']|["']$/g, "");
236
+ if (value.length === 0 || SAFE_VALUE.test(rawValue)) return;
237
+ if (value.length < 8) return;
238
+ findings.push({
239
+ line: index + 1,
240
+ key,
241
+ excerpt: `${key}: ${value.slice(0, 3)}\u2026 (${value.length} chars, redacted)`
242
+ });
243
+ });
244
+ return findings;
245
+ }
246
+ function describeSecretFindings(file, findings) {
247
+ const lines = findings.map((f) => ` line ${f.line}: ${f.excerpt}`).join("\n");
248
+ return `${file} appears to contain ${findings.length} inline secret(s):
249
+ ${lines}
250
+ OmniNode never stores credentials in configuration. Replace each value with an environment-variable reference, e.g. api_key_env_var: MY_API_KEY.`;
251
+ }
252
+
205
253
  // src/config/loader.ts
206
254
  import { existsSync, readFileSync } from "fs";
207
255
  import { parse as parseYaml } from "yaml";
@@ -238,6 +286,10 @@ function loadConfig(options = {}) {
238
286
  );
239
287
  }
240
288
  const raw = readFileSync(path, "utf8");
289
+ const secretFindings = scanForInlineSecrets(raw);
290
+ if (secretFindings.length > 0) {
291
+ throw new ConfigError("CONFIG_INVALID", describeSecretFindings(path, secretFindings));
292
+ }
241
293
  const expanded = expandEnvRefs(raw, env, path);
242
294
  let data;
243
295
  try {
@@ -541,7 +593,9 @@ var OpenAICompatibleProvider = class {
541
593
  /** Discovered models, so getModel() answers without another round-trip. */
542
594
  discovered;
543
595
  env;
544
- constructor(config, log = logger, env = process.env) {
596
+ audit;
597
+ constructor(config, log = logger, env = process.env, audit) {
598
+ this.audit = audit;
545
599
  this.config = { ...config, baseUrl: normalizeBaseUrl(config.baseUrl) };
546
600
  this.env = env;
547
601
  this.providerId = config.providerId ?? config.name;
@@ -580,17 +634,28 @@ var OpenAICompatibleProvider = class {
580
634
  timeoutMs: this.requestTimeoutMs
581
635
  });
582
636
  } catch (error) {
583
- if (error instanceof ProviderError) throw error;
584
- throw providerTransportError({ provider: this.config.name, operation: "listModels", cause: error });
637
+ if (error instanceof ProviderError) {
638
+ await this.recordProviderError("listModels", error);
639
+ throw error;
640
+ }
641
+ const normalized = providerTransportError({
642
+ provider: this.config.name,
643
+ operation: "listModels",
644
+ cause: error
645
+ });
646
+ await this.recordProviderError("listModels", normalized);
647
+ throw normalized;
585
648
  }
586
649
  const { status, body } = response;
587
650
  if (status !== 200) {
588
- throw providerHttpError({
651
+ const httpError = providerHttpError({
589
652
  provider: this.config.name,
590
653
  operation: "listModels",
591
654
  status,
592
655
  body
593
656
  });
657
+ await this.recordProviderError("listModels", httpError);
658
+ throw httpError;
594
659
  }
595
660
  return response;
596
661
  }
@@ -642,6 +707,21 @@ var OpenAICompatibleProvider = class {
642
707
  stream(request, onChunk) {
643
708
  return streamChatCompletion(this.config, request, onChunk, this.env);
644
709
  }
710
+ /** Provider errors are part of the audit trail (§14 correlation, §18 observability). */
711
+ async recordProviderError(operation, error) {
712
+ await this.audit?.record({
713
+ at: (/* @__PURE__ */ new Date()).toISOString(),
714
+ action: "provider.error",
715
+ id: this.providerId,
716
+ providerId: this.providerId,
717
+ detail: {
718
+ operation,
719
+ code: error.code,
720
+ kind: error.details?.kind,
721
+ message: error.message
722
+ }
723
+ });
724
+ }
645
725
  async healthCheck() {
646
726
  const lastCheckedAt = (/* @__PURE__ */ new Date()).toISOString();
647
727
  try {
@@ -686,12 +766,17 @@ var OpenAICompatibleProvider = class {
686
766
  }
687
767
  });
688
768
  } catch (error) {
689
- if (error instanceof ProviderError) throw error;
690
- throw providerTransportError({ provider: this.config.name, operation: "chat", cause: error });
769
+ if (error instanceof ProviderError) {
770
+ await this.recordProviderError("chat", error);
771
+ throw error;
772
+ }
773
+ const normalized = providerTransportError({ provider: this.config.name, operation: "chat", cause: error });
774
+ await this.recordProviderError("chat", normalized);
775
+ throw normalized;
691
776
  }
692
777
  const { status, body } = response;
693
778
  if (status !== 200) {
694
- throw providerHttpError({
779
+ const httpError = providerHttpError({
695
780
  provider: this.config.name,
696
781
  operation: "chat",
697
782
  status,
@@ -700,6 +785,8 @@ var OpenAICompatibleProvider = class {
700
785
  code: "MODEL_NOT_FOUND"
701
786
  } : {}
702
787
  });
788
+ await this.recordProviderError("chat", httpError);
789
+ throw httpError;
703
790
  }
704
791
  const payload = body;
705
792
  const choices = Array.isArray(payload.choices) ? payload.choices : [];
@@ -892,13 +979,18 @@ var OPENAI_COMPATIBLE_TYPES = [
892
979
  "local",
893
980
  "custom"
894
981
  ];
895
- function createProvider(config) {
982
+ function createProvider(config, options = {}) {
983
+ const shared = {
984
+ ...options.env !== void 0 ? { env: options.env } : {},
985
+ ...options.audit !== void 0 ? { audit: options.audit } : {}
986
+ };
896
987
  if (config.type === "omnihilbras") {
897
- return new OmniHilbrasProvider(config);
988
+ return new OmniHilbrasProvider(config, void 0, options.env, options.audit);
898
989
  }
899
990
  if (OPENAI_COMPATIBLE_TYPES.includes(config.type)) {
900
- return new OpenAICompatibleProvider(config);
991
+ return new OpenAICompatibleProvider(config, void 0, options.env, options.audit);
901
992
  }
993
+ void shared;
902
994
  throw new OmniNodeError("NOT_IMPLEMENTED", `Provider type "${config.type}" has no adapter yet.`);
903
995
  }
904
996
 
@@ -1820,28 +1912,34 @@ function buildRoleRegistry(config) {
1820
1912
  }
1821
1913
 
1822
1914
  // src/persistence/json-file-store.ts
1823
- import { open, mkdir, readFile, rename, stat } from "fs/promises";
1915
+ import { open, mkdir, readFile, rename, stat, writeFile } from "fs/promises";
1824
1916
  import { dirname } from "path";
1825
1917
  var SCHEMA_VERSION = 2;
1826
- async function writeFileAtomic(target, contents) {
1918
+ async function writeFileAtomic(target, contents, durability = "rename") {
1827
1919
  const tmp = `${target}.tmp`;
1828
1920
  await mkdir(dirname(target), { recursive: true });
1829
- const handle = await open(tmp, "w");
1830
- try {
1831
- await handle.writeFile(contents, "utf8");
1832
- await handle.sync();
1833
- } finally {
1834
- await handle.close();
1921
+ if (durability === "fsync") {
1922
+ const handle = await open(tmp, "w");
1923
+ try {
1924
+ await handle.writeFile(contents, "utf8");
1925
+ await handle.sync();
1926
+ } finally {
1927
+ await handle.close();
1928
+ }
1929
+ } else {
1930
+ await writeFile(tmp, contents, "utf8");
1835
1931
  }
1836
1932
  await rename(tmp, target);
1837
- try {
1838
- const dir = await open(dirname(target), "r");
1933
+ if (durability === "fsync") {
1839
1934
  try {
1840
- await dir.sync();
1841
- } finally {
1842
- await dir.close();
1935
+ const dir = await open(dirname(target), "r");
1936
+ try {
1937
+ await dir.sync();
1938
+ } finally {
1939
+ await dir.close();
1940
+ }
1941
+ } catch {
1843
1942
  }
1844
- } catch {
1845
1943
  }
1846
1944
  }
1847
1945
  async function inspectDocument(path) {
@@ -1911,6 +2009,7 @@ async function readDocument(path, onCorrupt, quarantine = true) {
1911
2009
  var JsonFileStore = class {
1912
2010
  filePath;
1913
2011
  schemaVersion;
2012
+ durability;
1914
2013
  onCorrupt;
1915
2014
  quarantine;
1916
2015
  log;
@@ -1918,6 +2017,7 @@ var JsonFileStore = class {
1918
2017
  constructor(options) {
1919
2018
  this.filePath = `${options.directory ?? `${process.cwd()}/.omninode`}/${options.fileName}`;
1920
2019
  this.schemaVersion = options.schemaVersion ?? SCHEMA_VERSION;
2020
+ this.durability = options.durability ?? "rename";
1921
2021
  this.onCorrupt = options.onCorrupt;
1922
2022
  this.quarantine = options.quarantine ?? true;
1923
2023
  this.log = logger.child({ component: "persistence", file: options.fileName });
@@ -1932,7 +2032,7 @@ var JsonFileStore = class {
1932
2032
  async writeAll(items) {
1933
2033
  const document = { schemaVersion: this.schemaVersion, items };
1934
2034
  await writeFileAtomic(this.filePath, `${JSON.stringify(document, null, 2)}
1935
- `);
2035
+ `, this.durability);
1936
2036
  }
1937
2037
  /** Serializes an async operation against this file. */
1938
2038
  synchronized(operation) {
@@ -2029,13 +2129,14 @@ var TaskEngine = class {
2029
2129
  createdAt: now,
2030
2130
  updatedAt: now,
2031
2131
  ...input.project !== void 0 ? { project: input.project } : {},
2132
+ ...input.pipelineId !== void 0 ? { pipelineId: input.pipelineId } : {},
2032
2133
  ...input.role !== void 0 ? { role: input.role } : {},
2033
2134
  ...input.agent !== void 0 ? { agent: input.agent } : {},
2034
2135
  ...input.context !== void 0 ? { context: input.context } : {}
2035
2136
  };
2036
2137
  await this.options.store.save(task);
2037
2138
  this.log.info(`Created task ${task.id}.`);
2038
- await this.audit("task.created", task.id, { objective: task.objective, project: task.project });
2139
+ await this.audit("task.created", task, { objective: task.objective });
2039
2140
  return task;
2040
2141
  }
2041
2142
  async queue(id) {
@@ -2078,12 +2179,24 @@ var TaskEngine = class {
2078
2179
  const executionId = `exec-${Date.now().toString(36)}-${randomBytes(3).toString("hex")}`;
2079
2180
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
2080
2181
  current = await this.transition(current, "running", { attempt });
2182
+ await this.options.audit?.record({
2183
+ at: startedAt,
2184
+ action: "agent.started",
2185
+ id: current.id,
2186
+ taskId: current.id,
2187
+ ...current.pipelineId !== void 0 ? { pipelineId: current.pipelineId } : {},
2188
+ agentId: task.agent,
2189
+ executionId,
2190
+ detail: { attempt }
2191
+ });
2081
2192
  let output;
2082
2193
  let thrown;
2083
2194
  try {
2084
2195
  output = await agent.run({
2085
2196
  taskId: current.id,
2086
2197
  objective: current.objective,
2198
+ executionId,
2199
+ ...current.pipelineId !== void 0 ? { pipelineId: current.pipelineId } : {},
2087
2200
  ...role ? { role } : {},
2088
2201
  ...background !== void 0 ? { context: background } : {}
2089
2202
  });
@@ -2091,6 +2204,16 @@ var TaskEngine = class {
2091
2204
  thrown = error;
2092
2205
  }
2093
2206
  const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
2207
+ await this.options.audit?.record({
2208
+ at: finishedAt,
2209
+ action: "agent.completed",
2210
+ id: current.id,
2211
+ taskId: current.id,
2212
+ ...current.pipelineId !== void 0 ? { pipelineId: current.pipelineId } : {},
2213
+ agentId: task.agent,
2214
+ executionId,
2215
+ detail: { attempt, outcome: thrown !== void 0 || output === void 0 ? "threw" : "returned" }
2216
+ });
2094
2217
  if (thrown !== void 0 || output === void 0) {
2095
2218
  const outcome = classifyThrown(thrown);
2096
2219
  const message = thrown instanceof Error ? thrown.message : String(thrown);
@@ -2170,7 +2293,7 @@ var TaskEngine = class {
2170
2293
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2171
2294
  };
2172
2295
  await this.options.store.save(reset);
2173
- await this.audit("task.retry", id, { from: task.status });
2296
+ await this.audit("task.retry", reset, { from: task.status });
2174
2297
  this.log.info(`Task ${id} reset for retry.`);
2175
2298
  return reset;
2176
2299
  }
@@ -2203,16 +2326,21 @@ var TaskEngine = class {
2203
2326
  ...extra.result !== void 0 ? { result: { ...task.result, ...extra.result } } : {}
2204
2327
  };
2205
2328
  await this.options.store.save(updated);
2206
- await this.audit(`task.${to === "queued" ? "queued" : to}`, updated.id, {
2329
+ await this.audit(`task.${to === "queued" ? "queued" : to}`, updated, {
2207
2330
  from: task.status
2208
2331
  });
2209
2332
  return updated;
2210
2333
  }
2211
- async audit(action, id, detail) {
2334
+ async audit(action, task, detail, executionId) {
2212
2335
  await this.options.audit?.record({
2213
2336
  at: (/* @__PURE__ */ new Date()).toISOString(),
2214
2337
  action,
2215
- id,
2338
+ id: task.id,
2339
+ taskId: task.id,
2340
+ ...task.project !== void 0 ? { project: task.project } : {},
2341
+ ...task.pipelineId !== void 0 ? { pipelineId: task.pipelineId } : {},
2342
+ ...task.agent !== void 0 ? { agentId: task.agent } : {},
2343
+ ...executionId !== void 0 ? { executionId } : {},
2216
2344
  ...detail !== void 0 ? { detail } : {}
2217
2345
  });
2218
2346
  }
@@ -2235,7 +2363,7 @@ function sleep(ms) {
2235
2363
  }
2236
2364
 
2237
2365
  // src/audit/index.ts
2238
- import { mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
2366
+ import { appendFile, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
2239
2367
  import { dirname as dirname2 } from "path";
2240
2368
  var FileAuditLog = class {
2241
2369
  filePath;
@@ -2247,15 +2375,8 @@ var FileAuditLog = class {
2247
2375
  async record(event) {
2248
2376
  try {
2249
2377
  await mkdir2(dirname2(this.filePath), { recursive: true });
2250
- const { open: open2 } = await import("fs/promises");
2251
- const handle = await open2(this.filePath, "a");
2252
- try {
2253
- await handle.appendFile(`${JSON.stringify(event)}
2378
+ await appendFile(this.filePath, `${JSON.stringify(event)}
2254
2379
  `, "utf8");
2255
- await handle.sync();
2256
- } finally {
2257
- await handle.close();
2258
- }
2259
2380
  } catch (error) {
2260
2381
  this.log.warn(
2261
2382
  `Audit write failed: ${error instanceof Error ? error.message : String(error)}`
@@ -3394,6 +3515,7 @@ var PipelineEngine = class {
3394
3515
  at: (/* @__PURE__ */ new Date()).toISOString(),
3395
3516
  action: "pipeline.run.started",
3396
3517
  id: run.id,
3518
+ pipelineId: def.id,
3397
3519
  detail: { pipeline: def.id, objective }
3398
3520
  });
3399
3521
  const deps = this.effectiveDependencies(def);
@@ -3434,7 +3556,9 @@ var PipelineEngine = class {
3434
3556
  combinedContext: contextParts.join("\n\n"),
3435
3557
  reports: [...allReports],
3436
3558
  pipelineRunId: run.id,
3437
- runId: run.id
3559
+ runId: run.id,
3560
+ pipelineDefId: def.id,
3561
+ taskId: run.id
3438
3562
  };
3439
3563
  return this.executeStep(step, ctx);
3440
3564
  })
@@ -3511,8 +3635,9 @@ ${contribution}`);
3511
3635
  this.log.info(`Pipeline ${def.id} finished: ${finalStatus}.`);
3512
3636
  await this.options.audit?.record({
3513
3637
  at: (/* @__PURE__ */ new Date()).toISOString(),
3514
- action: "pipeline.run.finished",
3638
+ action: cancelled ? "pipeline.run.cancelled" : finalStatus === "failed" ? "pipeline.run.failed" : "pipeline.run.finished",
3515
3639
  id: run.id,
3640
+ pipelineId: def.id,
3516
3641
  detail: { pipeline: def.id, status: finalStatus }
3517
3642
  });
3518
3643
  return finished;
@@ -3593,6 +3718,7 @@ ${contribution}`);
3593
3718
  agentNames.map(
3594
3719
  (name) => this.options.tasks.create({
3595
3720
  objective: ctx.objective,
3721
+ ...ctx.pipelineRunId !== void 0 ? { pipelineId: ctx.pipelineRunId } : {},
3596
3722
  agent: name,
3597
3723
  ...ctx.role ? { role: ctx.role.id } : {},
3598
3724
  ...ctx.combinedContext.length > 0 ? { context: { background: ctx.combinedContext } } : {}
@@ -3635,6 +3761,7 @@ ${contribution}`);
3635
3761
  async runSingle(step, ctx, agentName) {
3636
3762
  const task = await this.options.tasks.create({
3637
3763
  objective: ctx.objective,
3764
+ ...ctx.pipelineRunId !== void 0 ? { pipelineId: ctx.pipelineRunId } : {},
3638
3765
  agent: agentName,
3639
3766
  ...ctx.role ? { role: ctx.role.id } : {},
3640
3767
  ...ctx.combinedContext.length > 0 ? { context: { background: ctx.combinedContext } } : {}
@@ -3705,7 +3832,13 @@ ${contribution}`);
3705
3832
  at: (/* @__PURE__ */ new Date()).toISOString(),
3706
3833
  action: "plan.generated",
3707
3834
  id: plan.id,
3708
- detail: { generatedBy: plan.generatedBy, steps: plan.steps.length }
3835
+ ...ctx.pipelineDefId !== void 0 ? { pipelineId: ctx.pipelineDefId } : {},
3836
+ detail: {
3837
+ generatedBy: plan.generatedBy,
3838
+ steps: plan.steps.length,
3839
+ run: ctx.pipelineRunId,
3840
+ taskId: ctx.taskId
3841
+ }
3709
3842
  });
3710
3843
  return {
3711
3844
  status: "completed",
@@ -3739,7 +3872,7 @@ function formatPlan(plan) {
3739
3872
  }
3740
3873
  return lines.join("\n");
3741
3874
  }
3742
- function createDefaultChatFn(providers) {
3875
+ function createDefaultChatFn(providers, options = {}) {
3743
3876
  return async (modelRef, messages) => {
3744
3877
  const separator = modelRef.indexOf(":");
3745
3878
  if (separator <= 0 || separator === modelRef.length - 1) {
@@ -3757,7 +3890,10 @@ function createDefaultChatFn(providers) {
3757
3890
  `Provider "${providerName}" (model "${modelRef}") is not configured.`
3758
3891
  );
3759
3892
  }
3760
- const provider = createProvider(providerConfig);
3893
+ const provider = createProvider(providerConfig, {
3894
+ ...options.audit !== void 0 ? { audit: options.audit } : {},
3895
+ ...options.env !== void 0 ? { env: options.env } : {}
3896
+ });
3761
3897
  const response = await provider.chat({ model: modelId, messages });
3762
3898
  return response.content;
3763
3899
  };
@@ -3896,6 +4032,7 @@ function truncate3(text, max) {
3896
4032
  }
3897
4033
 
3898
4034
  // src/reports/service.ts
4035
+ var MAX_REPORT_BYTES = 256 * 1024;
3899
4036
  var ReportService = class {
3900
4037
  constructor(store, log = logger) {
3901
4038
  this.store = store;
@@ -3930,6 +4067,16 @@ var ReportService = class {
3930
4067
  const reports = [];
3931
4068
  const rejected = [];
3932
4069
  for (const candidate of candidates) {
4070
+ const size = Buffer.byteLength(JSON.stringify(candidate), "utf8");
4071
+ if (size > MAX_REPORT_BYTES) {
4072
+ rejected.push({
4073
+ key: candidate?.id ?? "(unknown)",
4074
+ reason: `report exceeds the ${MAX_REPORT_BYTES} byte limit (${size} bytes)`,
4075
+ issues: []
4076
+ });
4077
+ this.log.warn(`Rejected oversized report (${size} bytes).`);
4078
+ continue;
4079
+ }
3933
4080
  const result = validateReport(candidate);
3934
4081
  if (result.valid) {
3935
4082
  reports.push(result.report);
@@ -4003,9 +4150,10 @@ var FileReportStore = class extends JsonFileStore {
4003
4150
 
4004
4151
  // src/pipelines/engine-factory.ts
4005
4152
  function buildPipelineEngine(config, log = logger) {
4153
+ const auditLog = new FileAuditLog();
4006
4154
  const agents = buildAgentRegistry(config, log);
4007
4155
  const roles = buildRoleRegistry(config);
4008
- const chat = createDefaultChatFn(config.project.providers);
4156
+ const chat = createDefaultChatFn(config.project.providers, { audit: auditLog });
4009
4157
  const tasks = new TaskEngine({
4010
4158
  agents,
4011
4159
  roles,
@@ -4102,7 +4250,7 @@ async function migrateProjectStores(directory = `${process.cwd()}/.omninode`, op
4102
4250
  }
4103
4251
 
4104
4252
  // src/version.ts
4105
- var OMNINODE_VERSION = "2.0.0-alpha.12";
4253
+ var OMNINODE_VERSION = "2.0.0-alpha.14";
4106
4254
  export {
4107
4255
  AgentAdapterRegistry,
4108
4256
  AgentError,
@@ -4121,6 +4269,7 @@ export {
4121
4269
  Logger,
4122
4270
  MAX_CONTEXT_CHARS,
4123
4271
  MAX_MESSAGE_BYTES,
4272
+ MAX_REPORT_BYTES,
4124
4273
  MemoryError,
4125
4274
  MemoryService,
4126
4275
  ModelPlanner,
@@ -4163,6 +4312,7 @@ export {
4163
4312
  buildPlannerContext,
4164
4313
  buildRoleRegistry,
4165
4314
  composeTaskText,
4315
+ configureLogger,
4166
4316
  createAgent,
4167
4317
  createDefaultChatFn,
4168
4318
  createMemoryProvider,
@@ -4174,6 +4324,7 @@ export {
4174
4324
  defaultProjectConfigYaml,
4175
4325
  defaultSearch,
4176
4326
  describeExit,
4327
+ describeSecretFindings,
4177
4328
  detectConflicts,
4178
4329
  encodeMessage,
4179
4330
  envelope,
@@ -4215,6 +4366,7 @@ export {
4215
4366
  resolveEnvPolicy,
4216
4367
  roleConfigSchema,
4217
4368
  sanitizeChunk,
4369
+ scanForInlineSecrets,
4218
4370
  similar,
4219
4371
  validateEnvelope,
4220
4372
  validatePlan,