@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/README.md +16 -1
- package/dist/cli/chunk-6Z6O63SS.js +708 -0
- package/dist/cli/chunk-6Z6O63SS.js.map +1 -0
- package/dist/cli/index.js +1278 -1572
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/providers-OYXBAQTX.js +36 -0
- package/dist/cli/providers-OYXBAQTX.js.map +1 -0
- package/dist/index.d.ts +102 -31
- package/dist/index.js +200 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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({
|
|
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
|
-
|
|
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)
|
|
584
|
-
|
|
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
|
-
|
|
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)
|
|
690
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
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
|
-
|
|
1838
|
-
const dir = await open(dirname(target), "r");
|
|
1933
|
+
if (durability === "fsync") {
|
|
1839
1934
|
try {
|
|
1840
|
-
await
|
|
1841
|
-
|
|
1842
|
-
|
|
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
|
|
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",
|
|
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
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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,
|