@hilbras/omninode 2.0.0-alpha.19 → 2.0.0-alpha.20
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 +4 -3
- package/dist/cli/index.js +66 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.js +71 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://www.npmjs.com/package/@hilbras/omninode)
|
|
6
6
|
[](https://www.npmjs.com/package/@hilbras/omninode)
|
|
7
7
|
[](LICENSE)
|
|
8
|
-
[](docs/ROADMAP_V2.md)
|
|
9
9
|
|
|
10
10
|
**OmniNode** is a provider-agnostic multi-AI orchestration platform. It coordinates
|
|
11
11
|
CLI-based AI agents, AI providers, persistent memory, roles, reports and planning
|
|
@@ -36,7 +36,7 @@ release — is in progress**, shipping as tagged prereleases (`v2.0.0-alpha.N`).
|
|
|
36
36
|
| End-to-end workflow in one command | `omninode run <pipeline> "<objective>"` |
|
|
37
37
|
| Audit log, security model, examples, Docker runtime | [`src/audit/`](src/audit), [docs/SECURITY.md](docs/SECURITY.md) |
|
|
38
38
|
|
|
39
|
-
### v2.0.0 progress (
|
|
39
|
+
### v2.0.0 progress (20 of 24 phases)
|
|
40
40
|
|
|
41
41
|
| # | Phase | Outcome |
|
|
42
42
|
| --- | --- | --- |
|
|
@@ -59,7 +59,8 @@ release — is in progress**, shipping as tagged prereleases (`v2.0.0-alpha.N`).
|
|
|
59
59
|
| 17 | Testing expansion | explicit failure matrix + regression tests |
|
|
60
60
|
| 18 | Documentation overhaul | complete document set, rewritten README |
|
|
61
61
|
| 19 | API & package quality | curated public surface with CI guards, boundary validation, verified package contents |
|
|
62
|
-
| 20
|
|
62
|
+
| 20 | Performance & resources | bounded reports/context/audit log, concurrency limits, released handles |
|
|
63
|
+
| 21–24 | Developer experience · CI/CD · migration tooling · final hardening | next: developer experience |
|
|
63
64
|
|
|
64
65
|
The roadmap is [docs/ROADMAP_V2.md](docs/ROADMAP_V2.md); the completed v1 plan is
|
|
65
66
|
[docs/DEVELOPMENT_PLAN.md](docs/DEVELOPMENT_PLAN.md).
|
package/dist/cli/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import { realpathSync } from "fs";
|
|
|
23
23
|
import { Command } from "commander";
|
|
24
24
|
|
|
25
25
|
// src/version.ts
|
|
26
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
26
|
+
var OMNINODE_VERSION = "2.0.0-alpha.20";
|
|
27
27
|
|
|
28
28
|
// src/cli/exit-codes.ts
|
|
29
29
|
var EXIT = {
|
|
@@ -1183,6 +1183,9 @@ var ProcessAgent = class {
|
|
|
1183
1183
|
clearTimeout(timer);
|
|
1184
1184
|
this.running.delete(input.taskId);
|
|
1185
1185
|
GLOBAL_RUNNING.delete(child);
|
|
1186
|
+
child.stdin?.destroy();
|
|
1187
|
+
child.stdout?.destroy();
|
|
1188
|
+
child.stderr?.destroy();
|
|
1186
1189
|
finish();
|
|
1187
1190
|
};
|
|
1188
1191
|
const collect = (into, chunk) => {
|
|
@@ -2627,18 +2630,31 @@ function sleep(ms) {
|
|
|
2627
2630
|
}
|
|
2628
2631
|
|
|
2629
2632
|
// src/audit/index.ts
|
|
2630
|
-
import { appendFile, mkdir as mkdir2, readFile as readFile2 } from "fs/promises";
|
|
2633
|
+
import { appendFile, mkdir as mkdir2, readFile as readFile2, rename as rename2, stat as stat2 } from "fs/promises";
|
|
2631
2634
|
import { dirname as dirname2 } from "path";
|
|
2635
|
+
var DEFAULT_AUDIT_MAX_BYTES = 5 * 1024 * 1024;
|
|
2632
2636
|
var FileAuditLog = class {
|
|
2633
2637
|
filePath;
|
|
2638
|
+
maxBytes;
|
|
2634
2639
|
log;
|
|
2635
|
-
constructor(directory = `${process.cwd()}/.omninode`, log = logger) {
|
|
2640
|
+
constructor(directory = `${process.cwd()}/.omninode`, log = logger, maxBytes = DEFAULT_AUDIT_MAX_BYTES) {
|
|
2636
2641
|
this.filePath = `${directory}/audit.jsonl`;
|
|
2642
|
+
this.maxBytes = maxBytes;
|
|
2637
2643
|
this.log = log.child({ component: "audit" });
|
|
2638
2644
|
}
|
|
2645
|
+
/** Rotates the log once it passes the size budget, keeping one backup. */
|
|
2646
|
+
async rotateIfNeeded() {
|
|
2647
|
+
try {
|
|
2648
|
+
const stats = await stat2(this.filePath);
|
|
2649
|
+
if (stats.size <= this.maxBytes) return;
|
|
2650
|
+
await rename2(this.filePath, `${this.filePath}.1`);
|
|
2651
|
+
} catch {
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2639
2654
|
async record(event) {
|
|
2640
2655
|
try {
|
|
2641
2656
|
await mkdir2(dirname2(this.filePath), { recursive: true });
|
|
2657
|
+
await this.rotateIfNeeded();
|
|
2642
2658
|
await appendFile(this.filePath, `${JSON.stringify(event)}
|
|
2643
2659
|
`, "utf8");
|
|
2644
2660
|
} catch (error) {
|
|
@@ -3018,6 +3034,7 @@ var SEVERITY_RANK = {
|
|
|
3018
3034
|
high: 3,
|
|
3019
3035
|
critical: 4
|
|
3020
3036
|
};
|
|
3037
|
+
var MAX_COMBINED_FINDINGS = 200;
|
|
3021
3038
|
function aggregateReports(reports, options = {}) {
|
|
3022
3039
|
const threshold = options.similarityThreshold ?? 0.7;
|
|
3023
3040
|
const findingGroups = [];
|
|
@@ -3036,6 +3053,10 @@ function aggregateReports(reports, options = {}) {
|
|
|
3036
3053
|
const agreements = findingGroups.filter(
|
|
3037
3054
|
(group) => group.sources.length > 1 && group.severity !== void 0 && new Set(Object.values(group.severityBySource ?? {})).size === 1
|
|
3038
3055
|
);
|
|
3056
|
+
const maxFindings = options.maxFindings ?? MAX_COMBINED_FINDINGS;
|
|
3057
|
+
const orderedFindings = findingGroups.sort((a, b) => rank(b) - rank(a));
|
|
3058
|
+
const retainedFindings = orderedFindings.slice(0, maxFindings);
|
|
3059
|
+
const droppedFindings = orderedFindings.length - retainedFindings.length;
|
|
3039
3060
|
const disputed = conflicts.length;
|
|
3040
3061
|
const summary = `${reports.length} report(s) from ${sources.length > 0 ? sources.join(", ") : "no agents"}: ${findingGroups.length} unique finding group(s) (${totalRawFindings} raw), ${agreements.length} agreement(s), ${disputed} conflict(s), ${recommendationGroups.length} recommendation group(s).`;
|
|
3041
3062
|
return {
|
|
@@ -3045,7 +3066,7 @@ function aggregateReports(reports, options = {}) {
|
|
|
3045
3066
|
...options.pipelineRunId !== void 0 ? { pipelineRunId: options.pipelineRunId } : {},
|
|
3046
3067
|
taskIds: options.taskIds ?? [],
|
|
3047
3068
|
summary,
|
|
3048
|
-
findings:
|
|
3069
|
+
findings: retainedFindings,
|
|
3049
3070
|
agreements,
|
|
3050
3071
|
conflicts,
|
|
3051
3072
|
recommendations: recommendationGroups,
|
|
@@ -3058,7 +3079,8 @@ function aggregateReports(reports, options = {}) {
|
|
|
3058
3079
|
rawFindings: totalRawFindings,
|
|
3059
3080
|
findingGroups: findingGroups.length,
|
|
3060
3081
|
agreements: agreements.length,
|
|
3061
|
-
conflicts: conflicts.length
|
|
3082
|
+
conflicts: conflicts.length,
|
|
3083
|
+
findingsTruncated: droppedFindings
|
|
3062
3084
|
}
|
|
3063
3085
|
};
|
|
3064
3086
|
}
|
|
@@ -3796,6 +3818,13 @@ function describe(error) {
|
|
|
3796
3818
|
}
|
|
3797
3819
|
|
|
3798
3820
|
// src/pipelines/engine.ts
|
|
3821
|
+
var DEFAULT_MAX_PARALLEL_STEPS = 8;
|
|
3822
|
+
var MAX_COMBINED_CONTEXT_CHARS = 2e4;
|
|
3823
|
+
function budgetContext(context, maxChars = MAX_COMBINED_CONTEXT_CHARS) {
|
|
3824
|
+
if (context.length <= maxChars) return context;
|
|
3825
|
+
const marker = "\n[earlier context trimmed]\n";
|
|
3826
|
+
return marker + context.slice(context.length - (maxChars - marker.length));
|
|
3827
|
+
}
|
|
3799
3828
|
var PipelineEngine = class {
|
|
3800
3829
|
constructor(options) {
|
|
3801
3830
|
this.options = options;
|
|
@@ -3991,24 +4020,35 @@ var PipelineEngine = class {
|
|
|
3991
4020
|
if (ready.length === 0) {
|
|
3992
4021
|
throw new PipelineError("PIPELINE_FAILED", `Pipeline "${def.id}" scheduling stalled.`);
|
|
3993
4022
|
}
|
|
3994
|
-
const settled =
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4023
|
+
const settled = [];
|
|
4024
|
+
const limit = Math.max(1, this.options.maxParallelSteps ?? DEFAULT_MAX_PARALLEL_STEPS);
|
|
4025
|
+
for (let offset = 0; offset < ready.length; offset += limit) {
|
|
4026
|
+
const batch = ready.slice(offset, offset + limit);
|
|
4027
|
+
settled.push(
|
|
4028
|
+
...await Promise.all(
|
|
4029
|
+
batch.map(async (step) => {
|
|
4030
|
+
if (!this.shouldRun(step, deps.get(step.id) ?? [], outcomes)) {
|
|
4031
|
+
return { status: "skipped", summary: "", taskIds: [], reports: [] };
|
|
4032
|
+
}
|
|
4033
|
+
const ctx = {
|
|
4034
|
+
maxContextChars: this.options.maxContextChars,
|
|
4035
|
+
objective,
|
|
4036
|
+
...role ? { role } : {},
|
|
4037
|
+
combinedContext: budgetContext(
|
|
4038
|
+
contextParts.join("\n\n"),
|
|
4039
|
+
this.options.maxContextChars ?? MAX_COMBINED_CONTEXT_CHARS
|
|
4040
|
+
),
|
|
4041
|
+
reports: [...allReports],
|
|
4042
|
+
pipelineRunId: run2.id,
|
|
4043
|
+
runId: run2.id,
|
|
4044
|
+
pipelineDefId: def.id,
|
|
4045
|
+
taskId: run2.id
|
|
4046
|
+
};
|
|
4047
|
+
return this.executeStep(step, ctx);
|
|
4048
|
+
})
|
|
4049
|
+
)
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
4012
4052
|
ready.forEach((step, index) => {
|
|
4013
4053
|
const outcome = settled[index];
|
|
4014
4054
|
outcomes.set(step.id, outcome);
|
|
@@ -4233,7 +4273,9 @@ ${contribution}`);
|
|
|
4233
4273
|
};
|
|
4234
4274
|
}
|
|
4235
4275
|
async runPlan(step, ctx) {
|
|
4236
|
-
const aggregated = ctx.reports.length > 0 ? aggregateReports(ctx.reports
|
|
4276
|
+
const aggregated = ctx.reports.length > 0 ? aggregateReports(ctx.reports, {
|
|
4277
|
+
...step.constraints !== void 0 && step.constraints.length > 0 ? { maxFindings: MAX_COMBINED_FINDINGS } : {}
|
|
4278
|
+
}) : void 0;
|
|
4237
4279
|
const request = {
|
|
4238
4280
|
objective: ctx.objective,
|
|
4239
4281
|
reports: ctx.reports,
|