@hilbras/omninode 2.0.0-alpha.7 → 2.0.0-alpha.9
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 -3
- package/dist/cli/index.js +267 -61
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +214 -46
- package/dist/index.js +265 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -191,7 +191,8 @@ var projectConfigSchema = z.object({
|
|
|
191
191
|
provider: z.string().min(1).default("local"),
|
|
192
192
|
base_url: z.string().url().optional(),
|
|
193
193
|
api_key_env_var: z.string().min(1).optional(),
|
|
194
|
-
|
|
194
|
+
/** When true, memory failures fail tasks instead of being tolerated (§12). */
|
|
195
|
+
required: z.boolean().optional()
|
|
195
196
|
}).strict().optional()
|
|
196
197
|
}).strict();
|
|
197
198
|
var appConfigSchema = z.object({
|
|
@@ -273,7 +274,8 @@ function toAppConfig(yaml) {
|
|
|
273
274
|
memory: {
|
|
274
275
|
provider: yaml.project.memory.provider,
|
|
275
276
|
baseUrl: yaml.project.memory.base_url,
|
|
276
|
-
apiKeyEnvVar: yaml.project.memory.api_key_env_var
|
|
277
|
+
apiKeyEnvVar: yaml.project.memory.api_key_env_var,
|
|
278
|
+
required: yaml.project.memory.required
|
|
277
279
|
}
|
|
278
280
|
} : {}
|
|
279
281
|
},
|
|
@@ -2202,6 +2204,23 @@ var FileAuditLog = class {
|
|
|
2202
2204
|
}
|
|
2203
2205
|
};
|
|
2204
2206
|
|
|
2207
|
+
// src/memory/base.ts
|
|
2208
|
+
function defaultSearch(provider, text, options = {}) {
|
|
2209
|
+
return provider.retrieve({
|
|
2210
|
+
text,
|
|
2211
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
2212
|
+
...options.limit !== void 0 ? { limit: options.limit } : {}
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
function defaultMetadata(name, options = {}) {
|
|
2216
|
+
return {
|
|
2217
|
+
name,
|
|
2218
|
+
capabilities: options.capabilities ?? ["retrieve", "store", "search"],
|
|
2219
|
+
relevanceRanking: options.relevanceRanking ?? false,
|
|
2220
|
+
...options.backend !== void 0 ? { backend: options.backend } : {}
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2205
2224
|
// src/memory/local.ts
|
|
2206
2225
|
var STOPWORDS = /* @__PURE__ */ new Set([
|
|
2207
2226
|
"the",
|
|
@@ -2264,9 +2283,27 @@ var LocalMemoryProvider = class extends JsonFileStore {
|
|
|
2264
2283
|
constructor(directory) {
|
|
2265
2284
|
super({ ...directory !== void 0 ? { directory } : {}, fileName: "memory.json" });
|
|
2266
2285
|
}
|
|
2267
|
-
|
|
2286
|
+
metadata() {
|
|
2287
|
+
return defaultMetadata(this.name, {
|
|
2288
|
+
capabilities: ["retrieve", "store", "search", "categories", "tags"],
|
|
2289
|
+
relevanceRanking: true,
|
|
2290
|
+
backend: { kind: "json-file", deterministicScoring: true }
|
|
2291
|
+
});
|
|
2292
|
+
}
|
|
2293
|
+
search(text, options = {}) {
|
|
2294
|
+
return defaultSearch(this, text, options);
|
|
2295
|
+
}
|
|
2296
|
+
/** @deprecated v1 alias of {@link retrieve}. */
|
|
2297
|
+
query(query) {
|
|
2298
|
+
return this.retrieve(query);
|
|
2299
|
+
}
|
|
2300
|
+
/** @deprecated v1 alias of {@link store}. */
|
|
2301
|
+
write(entry) {
|
|
2302
|
+
return this.store(entry);
|
|
2303
|
+
}
|
|
2304
|
+
async retrieve(query) {
|
|
2268
2305
|
const entries = await this.readAll();
|
|
2269
|
-
const filtered = entries.filter((entry) => query.scope ? entry.scope === query.scope : true).filter(
|
|
2306
|
+
const filtered = entries.filter((entry) => query.scope ? entry.scope === query.scope : true).filter((entry) => query.category ? entry.category === query.category : true).filter(
|
|
2270
2307
|
(entry) => query.tags && query.tags.length > 0 ? query.tags.every((tag) => (entry.tags ?? []).includes(tag)) : true
|
|
2271
2308
|
);
|
|
2272
2309
|
if (!query.text || query.text.trim().length === 0) {
|
|
@@ -2275,7 +2312,7 @@ var LocalMemoryProvider = class extends JsonFileStore {
|
|
|
2275
2312
|
const queryKeywords = keywords(query.text);
|
|
2276
2313
|
return filtered.map((entry) => ({ entry, score: relevanceScore(queryKeywords, entry) })).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, query.limit ?? 10).map(({ entry }) => entry);
|
|
2277
2314
|
}
|
|
2278
|
-
|
|
2315
|
+
store(entry) {
|
|
2279
2316
|
return this.mutate((entries) => {
|
|
2280
2317
|
const index = entries.findIndex((e) => e.key === entry.key);
|
|
2281
2318
|
const stamped = {
|
|
@@ -2306,11 +2343,40 @@ var RememberaMemoryProvider = class {
|
|
|
2306
2343
|
this.env = config.env ?? process.env;
|
|
2307
2344
|
this.log = log.child({ component: "remembera" });
|
|
2308
2345
|
}
|
|
2346
|
+
get authenticationConfigured() {
|
|
2347
|
+
return this.apiKeyEnvVar === void 0 || Boolean(this.env[this.apiKeyEnvVar]);
|
|
2348
|
+
}
|
|
2309
2349
|
headers() {
|
|
2310
2350
|
const key = this.apiKeyEnvVar ? resolveApiKey({ name: "remembera", apiKeyEnvVar: this.apiKeyEnvVar }, this.env) : void 0;
|
|
2311
2351
|
return key ? { authorization: `Bearer ${key}` } : {};
|
|
2312
2352
|
}
|
|
2313
|
-
|
|
2353
|
+
/** Search delegates to the gateway's relevance query. */
|
|
2354
|
+
search(text, options = {}) {
|
|
2355
|
+
return defaultSearch(
|
|
2356
|
+
this,
|
|
2357
|
+
text,
|
|
2358
|
+
{
|
|
2359
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
2360
|
+
...options.limit !== void 0 ? { limit: options.limit } : {}
|
|
2361
|
+
}
|
|
2362
|
+
);
|
|
2363
|
+
}
|
|
2364
|
+
metadata() {
|
|
2365
|
+
return defaultMetadata(this.name, {
|
|
2366
|
+
capabilities: ["retrieve", "store", "search", "categories", "tags"],
|
|
2367
|
+
relevanceRanking: true,
|
|
2368
|
+
backend: { kind: "http", baseUrl: this.baseUrl, authenticated: this.authenticationConfigured }
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2371
|
+
/** @deprecated v1 alias of {@link retrieve}. */
|
|
2372
|
+
query(query) {
|
|
2373
|
+
return this.retrieve(query);
|
|
2374
|
+
}
|
|
2375
|
+
/** @deprecated v1 alias of {@link store}. */
|
|
2376
|
+
write(entry) {
|
|
2377
|
+
return this.store(entry);
|
|
2378
|
+
}
|
|
2379
|
+
async retrieve(query) {
|
|
2314
2380
|
const { status, body } = await this.request(`${this.baseUrl}/api/memory/query`, query);
|
|
2315
2381
|
if (status !== 200) {
|
|
2316
2382
|
throw new MemoryError(`Remembera query returned HTTP ${status}.`);
|
|
@@ -2321,7 +2387,7 @@ var RememberaMemoryProvider = class {
|
|
|
2321
2387
|
}
|
|
2322
2388
|
return entries.map((entry) => this.toEntry(entry)).filter((entry) => entry !== void 0);
|
|
2323
2389
|
}
|
|
2324
|
-
async
|
|
2390
|
+
async store(entry) {
|
|
2325
2391
|
const { status } = await this.request(`${this.baseUrl}/api/memory`, entry);
|
|
2326
2392
|
if (status !== 200 && status !== 201) {
|
|
2327
2393
|
throw new MemoryError(`Remembera write returned HTTP ${status}.`);
|
|
@@ -2356,6 +2422,7 @@ var RememberaMemoryProvider = class {
|
|
|
2356
2422
|
content: entry.content,
|
|
2357
2423
|
scope: scope === "project" || scope === "role" || scope === "task" || scope === "knowledge" ? scope : "knowledge",
|
|
2358
2424
|
...Array.isArray(entry.tags) ? { tags: entry.tags.filter((t) => typeof t === "string") } : {},
|
|
2425
|
+
...typeof entry.category === "string" ? { category: entry.category } : {},
|
|
2359
2426
|
...typeof entry.createdAt === "string" ? { createdAt: entry.createdAt } : {},
|
|
2360
2427
|
...typeof entry.updatedAt === "string" ? { updatedAt: entry.updatedAt } : {}
|
|
2361
2428
|
};
|
|
@@ -2386,57 +2453,54 @@ function createMemoryProvider(config) {
|
|
|
2386
2453
|
}
|
|
2387
2454
|
|
|
2388
2455
|
// src/memory/service.ts
|
|
2456
|
+
var DEFAULT_ENTRY_LIMIT = 8;
|
|
2389
2457
|
var MAX_CONTEXT_CHARS = 4e3;
|
|
2390
2458
|
var MemoryService = class {
|
|
2391
|
-
constructor(provider, log = logger) {
|
|
2459
|
+
constructor(provider, log = logger, options = {}) {
|
|
2392
2460
|
this.provider = provider;
|
|
2393
2461
|
this.log = log.child({ component: "memory", provider: provider.name });
|
|
2462
|
+
this.required = options.required ?? false;
|
|
2463
|
+
this.maxContextChars = options.maxContextChars ?? MAX_CONTEXT_CHARS;
|
|
2394
2464
|
}
|
|
2395
2465
|
provider;
|
|
2396
2466
|
log;
|
|
2467
|
+
required;
|
|
2468
|
+
maxContextChars;
|
|
2397
2469
|
get providerRef() {
|
|
2398
2470
|
return this.provider;
|
|
2399
2471
|
}
|
|
2400
2472
|
get providerName() {
|
|
2401
2473
|
return this.provider.name;
|
|
2402
2474
|
}
|
|
2403
|
-
|
|
2404
|
-
|
|
2475
|
+
get isRequired() {
|
|
2476
|
+
return this.required;
|
|
2477
|
+
}
|
|
2478
|
+
/** Structured, budgeted context for a task (§12 — avoid loading all memory). */
|
|
2479
|
+
async contextFor(query) {
|
|
2480
|
+
let entries;
|
|
2405
2481
|
try {
|
|
2406
|
-
|
|
2482
|
+
entries = await this.provider.retrieve({
|
|
2407
2483
|
text: query.objective,
|
|
2408
2484
|
...query.role ? { tags: [query.role] } : {},
|
|
2409
|
-
limit:
|
|
2485
|
+
limit: query.limit ?? DEFAULT_ENTRY_LIMIT
|
|
2410
2486
|
});
|
|
2411
|
-
if (entries.length === 0) return "";
|
|
2412
|
-
const byScope = /* @__PURE__ */ new Map();
|
|
2413
|
-
for (const entry of entries) {
|
|
2414
|
-
byScope.set(entry.scope, [...byScope.get(entry.scope) ?? [], entry]);
|
|
2415
|
-
}
|
|
2416
|
-
const parts = [];
|
|
2417
|
-
for (const scope of ["project", "task", "role", "knowledge"]) {
|
|
2418
|
-
const scopeEntries = byScope.get(scope) ?? [];
|
|
2419
|
-
if (scopeEntries.length === 0) continue;
|
|
2420
|
-
const lines = scopeEntries.map((entry) => `- ${entry.content}`).join("\n");
|
|
2421
|
-
parts.push(`### Relevant memory (${scope})
|
|
2422
|
-
${lines}`);
|
|
2423
|
-
}
|
|
2424
|
-
const context = parts.join("\n\n");
|
|
2425
|
-
return context.length > MAX_CONTEXT_CHARS ? `${context.slice(0, MAX_CONTEXT_CHARS)}\u2026` : context;
|
|
2426
2487
|
} catch (error) {
|
|
2427
|
-
this.
|
|
2428
|
-
`Memory query failed (continuing without memory): ${error instanceof Error ? error.message : String(error)}`
|
|
2429
|
-
);
|
|
2430
|
-
return "";
|
|
2488
|
+
return this.handleFailure("retrieve", error, { text: "", entries: [], truncated: false });
|
|
2431
2489
|
}
|
|
2490
|
+
return this.format(entries);
|
|
2491
|
+
}
|
|
2492
|
+
/** Prompt-ready context text (v1 convenience wrapper). */
|
|
2493
|
+
async gatherContext(query) {
|
|
2494
|
+
return (await this.contextFor(query)).text;
|
|
2432
2495
|
}
|
|
2433
|
-
/** Records a finished task's outcome —
|
|
2496
|
+
/** Records a finished task's outcome — task history plus "known problems" (§12). */
|
|
2434
2497
|
async recordTaskOutcome(task) {
|
|
2435
2498
|
const outcome = task.result?.summary ?? task.result?.error ?? "(no output)";
|
|
2436
2499
|
try {
|
|
2437
|
-
await this.provider.
|
|
2500
|
+
await this.provider.store({
|
|
2438
2501
|
key: `task:${task.id}`,
|
|
2439
2502
|
scope: "task",
|
|
2503
|
+
category: "tasks",
|
|
2440
2504
|
content: `Objective: ${task.objective}
|
|
2441
2505
|
Status: ${task.status}
|
|
2442
2506
|
Outcome: ${outcome}`,
|
|
@@ -2447,18 +2511,53 @@ Outcome: ${outcome}`,
|
|
|
2447
2511
|
(report) => report.findings.filter((finding) => finding.severity === "high" || finding.severity === "critical").map((finding) => ({ report, finding }))
|
|
2448
2512
|
);
|
|
2449
2513
|
for (const { report, finding } of significant) {
|
|
2450
|
-
await this.provider.
|
|
2514
|
+
await this.provider.store({
|
|
2451
2515
|
key: `finding:${report.id}:${finding.id}`,
|
|
2452
2516
|
scope: "project",
|
|
2517
|
+
category: "problems",
|
|
2453
2518
|
content: `[${finding.severity}] ${finding.title} \u2014 ${finding.detail}`,
|
|
2454
2519
|
tags: ["known-problem", report.agent]
|
|
2455
2520
|
});
|
|
2456
2521
|
}
|
|
2457
2522
|
} catch (error) {
|
|
2458
|
-
this.
|
|
2459
|
-
|
|
2523
|
+
this.handleFailure("store", error, void 0);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
format(entries) {
|
|
2527
|
+
if (entries.length === 0) return { text: "", entries, truncated: false };
|
|
2528
|
+
const byScope = /* @__PURE__ */ new Map();
|
|
2529
|
+
for (const entry of entries) {
|
|
2530
|
+
byScope.set(entry.scope, [...byScope.get(entry.scope) ?? [], entry]);
|
|
2531
|
+
}
|
|
2532
|
+
const parts = [];
|
|
2533
|
+
for (const scope of ["project", "task", "role", "knowledge"]) {
|
|
2534
|
+
const scopeEntries = byScope.get(scope) ?? [];
|
|
2535
|
+
if (scopeEntries.length === 0) continue;
|
|
2536
|
+
const lines = scopeEntries.map((entry) => {
|
|
2537
|
+
const category = entry.category ? `[${entry.category}] ` : "";
|
|
2538
|
+
return `- ${category}${entry.content}`;
|
|
2539
|
+
}).join("\n");
|
|
2540
|
+
parts.push(`### Relevant memory (${scope})
|
|
2541
|
+
${lines}`);
|
|
2542
|
+
}
|
|
2543
|
+
let text = parts.join("\n\n");
|
|
2544
|
+
const truncated = text.length > this.maxContextChars;
|
|
2545
|
+
if (truncated) text = `${text.slice(0, this.maxContextChars - 1)}\u2026`;
|
|
2546
|
+
return { text, entries, truncated };
|
|
2547
|
+
}
|
|
2548
|
+
/**
|
|
2549
|
+
* Failure policy (§12): continue unless memory is explicitly required.
|
|
2550
|
+
*/
|
|
2551
|
+
handleFailure(operation, error, fallback) {
|
|
2552
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2553
|
+
if (this.required) {
|
|
2554
|
+
throw new MemoryError(
|
|
2555
|
+
`Memory is marked required, but ${operation} failed: ${message}`,
|
|
2556
|
+
{ cause: error }
|
|
2460
2557
|
);
|
|
2461
2558
|
}
|
|
2559
|
+
this.log.warn(`Memory ${operation} failed (continuing without memory): ${message}`);
|
|
2560
|
+
return fallback ?? { text: "", entries: [], truncated: false };
|
|
2462
2561
|
}
|
|
2463
2562
|
};
|
|
2464
2563
|
|
|
@@ -2470,7 +2569,11 @@ function createTaskEngine(config, log = logger, directory) {
|
|
|
2470
2569
|
agents,
|
|
2471
2570
|
roles,
|
|
2472
2571
|
store: new FileTaskStore(directory),
|
|
2473
|
-
...config.project.memory !== void 0 ? {
|
|
2572
|
+
...config.project.memory !== void 0 ? {
|
|
2573
|
+
memory: new MemoryService(createMemoryProvider(config.project.memory), log, {
|
|
2574
|
+
required: config.project.memory.required
|
|
2575
|
+
})
|
|
2576
|
+
} : {},
|
|
2474
2577
|
audit: new FileAuditLog(),
|
|
2475
2578
|
log
|
|
2476
2579
|
});
|
|
@@ -3298,6 +3401,91 @@ function buildPlanner(plannerConfig, chat, log = logger) {
|
|
|
3298
3401
|
|
|
3299
3402
|
// src/reports/aggregate.ts
|
|
3300
3403
|
import { randomBytes as randomBytes5 } from "crypto";
|
|
3404
|
+
|
|
3405
|
+
// src/reports/schema.ts
|
|
3406
|
+
import { z as z3 } from "zod";
|
|
3407
|
+
var evidenceSchema = z3.union([
|
|
3408
|
+
z3.string().transform((excerpt) => ({ kind: "observation", excerpt })),
|
|
3409
|
+
z3.object({
|
|
3410
|
+
kind: z3.enum(["file", "line", "url", "command", "observation", "artifact"]),
|
|
3411
|
+
ref: z3.string().optional(),
|
|
3412
|
+
line: z3.number().int().optional(),
|
|
3413
|
+
excerpt: z3.string().optional(),
|
|
3414
|
+
agent: z3.string().optional()
|
|
3415
|
+
})
|
|
3416
|
+
]);
|
|
3417
|
+
var findingSchema = z3.object({
|
|
3418
|
+
id: z3.string().min(1),
|
|
3419
|
+
title: z3.string().min(1),
|
|
3420
|
+
detail: z3.string().default(""),
|
|
3421
|
+
description: z3.string().optional(),
|
|
3422
|
+
severity: z3.enum(["info", "low", "medium", "high", "critical"]).optional(),
|
|
3423
|
+
confidence: z3.enum(["low", "medium", "high"]).optional(),
|
|
3424
|
+
evidence: z3.array(evidenceSchema).optional(),
|
|
3425
|
+
location: z3.string().optional(),
|
|
3426
|
+
tags: z3.array(z3.string()).optional(),
|
|
3427
|
+
source: z3.object({ agent: z3.string().optional(), reportId: z3.string().optional(), pipelineRunId: z3.string().optional() }).optional(),
|
|
3428
|
+
recommendation: z3.string().optional()
|
|
3429
|
+
});
|
|
3430
|
+
var artifactSchema = z3.object({
|
|
3431
|
+
kind: z3.enum(["file", "patch", "log", "screenshot", "document", "data"]),
|
|
3432
|
+
ref: z3.string().min(1),
|
|
3433
|
+
description: z3.string().optional(),
|
|
3434
|
+
mediaType: z3.string().optional(),
|
|
3435
|
+
bytes: z3.number().int().optional()
|
|
3436
|
+
});
|
|
3437
|
+
var reportSchema = z3.object({
|
|
3438
|
+
id: z3.string().min(1),
|
|
3439
|
+
taskId: z3.string().min(1),
|
|
3440
|
+
agent: z3.string().min(1),
|
|
3441
|
+
agentId: z3.string().optional(),
|
|
3442
|
+
pipelineRunId: z3.string().optional(),
|
|
3443
|
+
model: z3.string().optional(),
|
|
3444
|
+
summary: z3.string(),
|
|
3445
|
+
findings: z3.array(findingSchema),
|
|
3446
|
+
recommendations: z3.array(z3.string()),
|
|
3447
|
+
confidence: z3.enum(["low", "medium", "high"]).optional(),
|
|
3448
|
+
evidence: z3.array(evidenceSchema).optional(),
|
|
3449
|
+
artifacts: z3.array(artifactSchema).optional(),
|
|
3450
|
+
createdAt: z3.string().min(1),
|
|
3451
|
+
metadata: z3.record(z3.unknown()).optional()
|
|
3452
|
+
});
|
|
3453
|
+
function validateReport(value) {
|
|
3454
|
+
const parsed = reportSchema.safeParse(value);
|
|
3455
|
+
if (!parsed.success) {
|
|
3456
|
+
const issues = parsed.error.issues.map((issue) => ({
|
|
3457
|
+
path: issue.path.join(".") || "(root)",
|
|
3458
|
+
message: issue.message
|
|
3459
|
+
}));
|
|
3460
|
+
return {
|
|
3461
|
+
valid: false,
|
|
3462
|
+
issues,
|
|
3463
|
+
reason: `report failed schema validation (${issues.length} issue(s))`
|
|
3464
|
+
};
|
|
3465
|
+
}
|
|
3466
|
+
const report = parsed.data;
|
|
3467
|
+
report.findings = report.findings.map((finding) => ({
|
|
3468
|
+
...finding,
|
|
3469
|
+
description: finding.description ?? finding.detail,
|
|
3470
|
+
...finding.source === void 0 ? { source: { agent: report.agent, reportId: report.id, ...report.pipelineRunId !== void 0 ? { pipelineRunId: report.pipelineRunId } : {} } } : {}
|
|
3471
|
+
}));
|
|
3472
|
+
return { valid: true, report };
|
|
3473
|
+
}
|
|
3474
|
+
function normalizeEvidence(input) {
|
|
3475
|
+
if (input === void 0) return void 0;
|
|
3476
|
+
return input.map(
|
|
3477
|
+
(item) => typeof item === "string" ? { kind: "observation", excerpt: item } : item
|
|
3478
|
+
);
|
|
3479
|
+
}
|
|
3480
|
+
function normalizeFinding(finding) {
|
|
3481
|
+
return {
|
|
3482
|
+
...finding,
|
|
3483
|
+
description: finding.description ?? finding.detail,
|
|
3484
|
+
evidence: normalizeEvidence(finding.evidence)
|
|
3485
|
+
};
|
|
3486
|
+
}
|
|
3487
|
+
|
|
3488
|
+
// src/reports/aggregate.ts
|
|
3301
3489
|
var SEVERITY_RANK2 = {
|
|
3302
3490
|
info: 0,
|
|
3303
3491
|
low: 1,
|
|
@@ -3344,7 +3532,7 @@ function mergeFinding(groups, finding, report, threshold) {
|
|
|
3344
3532
|
group.occurrences += 1;
|
|
3345
3533
|
group.details.push(finding.detail);
|
|
3346
3534
|
group.sources.push(source);
|
|
3347
|
-
group.evidence.push(...finding.evidence ?? []);
|
|
3535
|
+
group.evidence.push(...normalizeEvidence(finding.evidence) ?? []);
|
|
3348
3536
|
if (finding.severity && (!group.severity || SEVERITY_RANK2[finding.severity] > SEVERITY_RANK2[group.severity])) {
|
|
3349
3537
|
group.severity = finding.severity;
|
|
3350
3538
|
}
|
|
@@ -3356,7 +3544,7 @@ function mergeFinding(groups, finding, report, threshold) {
|
|
|
3356
3544
|
sources: [source],
|
|
3357
3545
|
occurrences: 1,
|
|
3358
3546
|
...finding.severity ? { severity: finding.severity } : {},
|
|
3359
|
-
evidence: [...finding.evidence ?? []]
|
|
3547
|
+
evidence: [...normalizeEvidence(finding.evidence) ?? []]
|
|
3360
3548
|
});
|
|
3361
3549
|
}
|
|
3362
3550
|
function mergeRecommendation(groups, text, report, threshold) {
|
|
@@ -3438,6 +3626,7 @@ function extractReportFromText(raw, meta) {
|
|
|
3438
3626
|
id: `${meta.taskId}-f-${index + 1}`,
|
|
3439
3627
|
title: truncate3(text, 120),
|
|
3440
3628
|
detail: text,
|
|
3629
|
+
description: text,
|
|
3441
3630
|
severity: guessSeverity(text)
|
|
3442
3631
|
}));
|
|
3443
3632
|
return {
|
|
@@ -3448,7 +3637,8 @@ function extractReportFromText(raw, meta) {
|
|
|
3448
3637
|
summary,
|
|
3449
3638
|
findings,
|
|
3450
3639
|
recommendations: recommendationTexts.map((t) => truncate3(t, 200)),
|
|
3451
|
-
|
|
3640
|
+
...evidenceTexts.length > 0 ? { evidence: evidenceTexts.map((excerpt) => ({ kind: "observation", excerpt })) } : {},
|
|
3641
|
+
metadata: evidenceTexts.length > 0 ? { evidenceCount: evidenceTexts.length } : void 0,
|
|
3452
3642
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3453
3643
|
};
|
|
3454
3644
|
}
|
|
@@ -3464,27 +3654,46 @@ var ReportService = class {
|
|
|
3464
3654
|
}
|
|
3465
3655
|
store;
|
|
3466
3656
|
log;
|
|
3657
|
+
/** Rejected reports from the last collection (§13 — malformed never enters aggregation). */
|
|
3658
|
+
lastDiagnostics = { collected: 0, accepted: 0, rejected: [] };
|
|
3467
3659
|
get storeRef() {
|
|
3468
3660
|
return this.store;
|
|
3469
3661
|
}
|
|
3470
|
-
/** Normalizes finished tasks into reports (§17 — normalizer)
|
|
3662
|
+
/** Normalizes finished tasks into reports (§17 — normalizer), validating each
|
|
3663
|
+
* one so malformed reports never reach aggregation (§13). */
|
|
3471
3664
|
async collectFromTasks(tasks) {
|
|
3472
|
-
const
|
|
3665
|
+
const candidates = [];
|
|
3473
3666
|
for (const task of tasks) {
|
|
3474
3667
|
const structured = task.result?.reports ?? [];
|
|
3475
3668
|
if (structured.length > 0) {
|
|
3476
|
-
|
|
3669
|
+
candidates.push(...structured);
|
|
3477
3670
|
continue;
|
|
3478
3671
|
}
|
|
3479
3672
|
const text = task.result?.rawOutput ?? task.result?.summary ?? "";
|
|
3480
3673
|
if (text.trim().length === 0) continue;
|
|
3481
|
-
|
|
3674
|
+
candidates.push(
|
|
3482
3675
|
extractReportFromText(text, {
|
|
3483
3676
|
taskId: task.id,
|
|
3484
3677
|
agent: task.agent ?? "unknown"
|
|
3485
3678
|
})
|
|
3486
3679
|
);
|
|
3487
3680
|
}
|
|
3681
|
+
const reports = [];
|
|
3682
|
+
const rejected = [];
|
|
3683
|
+
for (const candidate of candidates) {
|
|
3684
|
+
const result = validateReport(candidate);
|
|
3685
|
+
if (result.valid) {
|
|
3686
|
+
reports.push(result.report);
|
|
3687
|
+
} else {
|
|
3688
|
+
rejected.push({
|
|
3689
|
+
key: candidate?.id ?? "(unknown)",
|
|
3690
|
+
reason: result.reason,
|
|
3691
|
+
issues: result.issues.map((issue) => `${issue.path}: ${issue.message}`)
|
|
3692
|
+
});
|
|
3693
|
+
this.log.warn(`Rejected malformed report: ${result.reason}`);
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
this.lastDiagnostics = { collected: candidates.length, accepted: reports.length, rejected };
|
|
3488
3697
|
return reports;
|
|
3489
3698
|
}
|
|
3490
3699
|
async saveReports(reports) {
|
|
@@ -3552,7 +3761,11 @@ function buildPipelineEngine(config, log = logger) {
|
|
|
3552
3761
|
agents,
|
|
3553
3762
|
roles,
|
|
3554
3763
|
store: new FileTaskStore(),
|
|
3555
|
-
...config.project.memory !== void 0 ? {
|
|
3764
|
+
...config.project.memory !== void 0 ? {
|
|
3765
|
+
memory: new MemoryService(createMemoryProvider(config.project.memory), log, {
|
|
3766
|
+
required: config.project.memory.required
|
|
3767
|
+
})
|
|
3768
|
+
} : {},
|
|
3556
3769
|
audit: new FileAuditLog(),
|
|
3557
3770
|
log
|
|
3558
3771
|
});
|
|
@@ -3590,7 +3803,7 @@ var ProjectStores = class {
|
|
|
3590
3803
|
};
|
|
3591
3804
|
|
|
3592
3805
|
// src/version.ts
|
|
3593
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
3806
|
+
var OMNINODE_VERSION = "2.0.0-alpha.9";
|
|
3594
3807
|
export {
|
|
3595
3808
|
AgentAdapterRegistry,
|
|
3596
3809
|
AgentError,
|
|
@@ -3607,6 +3820,7 @@ export {
|
|
|
3607
3820
|
JsonFileStore,
|
|
3608
3821
|
LocalMemoryProvider,
|
|
3609
3822
|
Logger,
|
|
3823
|
+
MAX_CONTEXT_CHARS,
|
|
3610
3824
|
MAX_MESSAGE_BYTES,
|
|
3611
3825
|
MemoryError,
|
|
3612
3826
|
MemoryService,
|
|
@@ -3655,7 +3869,9 @@ export {
|
|
|
3655
3869
|
createTaskEngine,
|
|
3656
3870
|
decodeMessage,
|
|
3657
3871
|
decodeStream,
|
|
3872
|
+
defaultMetadata,
|
|
3658
3873
|
defaultProjectConfigYaml,
|
|
3874
|
+
defaultSearch,
|
|
3659
3875
|
describeExit,
|
|
3660
3876
|
encodeMessage,
|
|
3661
3877
|
envelope,
|
|
@@ -3674,6 +3890,8 @@ export {
|
|
|
3674
3890
|
loadConfig,
|
|
3675
3891
|
logger,
|
|
3676
3892
|
newMessageId,
|
|
3893
|
+
normalizeEvidence,
|
|
3894
|
+
normalizeFinding,
|
|
3677
3895
|
parseHello,
|
|
3678
3896
|
parsePlanJson,
|
|
3679
3897
|
parseRetryAfter,
|
|
@@ -3693,6 +3911,7 @@ export {
|
|
|
3693
3911
|
sanitizeChunk,
|
|
3694
3912
|
similar,
|
|
3695
3913
|
validateEnvelope,
|
|
3914
|
+
validateReport,
|
|
3696
3915
|
validateWorkingDirectory
|
|
3697
3916
|
};
|
|
3698
3917
|
//# sourceMappingURL=index.js.map
|