@probelabs/visor 0.1.88 → 0.1.90
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/check-execution-engine.d.ts +3 -0
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/failure-condition-evaluator.d.ts +1 -0
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/index.js +5109 -4120
- package/dist/logger.d.ts.map +1 -1
- package/dist/providers/command-check-provider.d.ts +2 -0
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/sdk/{check-execution-engine-D6FPIIKR.mjs → check-execution-engine-Z2USLMN5.mjs} +2 -2
- package/dist/sdk/{chunk-N34GS4A5.mjs → chunk-N2PPFOSF.mjs} +1511 -246
- package/dist/sdk/chunk-N2PPFOSF.mjs.map +1 -0
- package/dist/sdk/sdk.js +1398 -143
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +3 -1
- package/dist/sdk/sdk.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/sdk/chunk-N34GS4A5.mjs.map +0 -1
- /package/dist/sdk/{check-execution-engine-D6FPIIKR.mjs.map → check-execution-engine-Z2USLMN5.mjs.map} +0 -0
package/dist/sdk/sdk.js
CHANGED
|
@@ -484,6 +484,11 @@ var init_session_registry = __esm({
|
|
|
484
484
|
});
|
|
485
485
|
|
|
486
486
|
// src/logger.ts
|
|
487
|
+
var logger_exports = {};
|
|
488
|
+
__export(logger_exports, {
|
|
489
|
+
configureLoggerFromCli: () => configureLoggerFromCli,
|
|
490
|
+
logger: () => logger
|
|
491
|
+
});
|
|
487
492
|
function levelToNumber(level) {
|
|
488
493
|
switch (level) {
|
|
489
494
|
case "silent":
|
|
@@ -500,6 +505,21 @@ function levelToNumber(level) {
|
|
|
500
505
|
return 50;
|
|
501
506
|
}
|
|
502
507
|
}
|
|
508
|
+
function configureLoggerFromCli(options) {
|
|
509
|
+
logger.configure({
|
|
510
|
+
outputFormat: options.output,
|
|
511
|
+
debug: options.debug,
|
|
512
|
+
verbose: options.verbose,
|
|
513
|
+
quiet: options.quiet
|
|
514
|
+
});
|
|
515
|
+
try {
|
|
516
|
+
if (options.output) process.env.VISOR_OUTPUT_FORMAT = String(options.output);
|
|
517
|
+
if (typeof options.debug === "boolean") {
|
|
518
|
+
process.env.VISOR_DEBUG = options.debug ? "true" : "false";
|
|
519
|
+
}
|
|
520
|
+
} catch {
|
|
521
|
+
}
|
|
522
|
+
}
|
|
503
523
|
var Logger, logger;
|
|
504
524
|
var init_logger = __esm({
|
|
505
525
|
"src/logger.ts"() {
|
|
@@ -4135,6 +4155,14 @@ var init_command_check_provider = __esm({
|
|
|
4135
4155
|
return true;
|
|
4136
4156
|
}
|
|
4137
4157
|
async execute(prInfo, config, dependencyResults) {
|
|
4158
|
+
try {
|
|
4159
|
+
logger.info(
|
|
4160
|
+
` command provider: executing check=${String(config.checkName || config.type)} hasTransformJs=${Boolean(
|
|
4161
|
+
config.transform_js
|
|
4162
|
+
)}`
|
|
4163
|
+
);
|
|
4164
|
+
} catch {
|
|
4165
|
+
}
|
|
4138
4166
|
const command = config.exec;
|
|
4139
4167
|
const transform = config.transform;
|
|
4140
4168
|
const transformJs = config.transform_js;
|
|
@@ -4194,33 +4222,29 @@ var init_command_check_provider = __esm({
|
|
|
4194
4222
|
output = parsed;
|
|
4195
4223
|
logger.debug(`\u{1F527} Debug: Parsed entire output as JSON successfully`);
|
|
4196
4224
|
} catch {
|
|
4197
|
-
const
|
|
4198
|
-
if (
|
|
4225
|
+
const extractedTail = this.extractJsonFromEnd(rawOutput);
|
|
4226
|
+
if (extractedTail) {
|
|
4199
4227
|
try {
|
|
4200
|
-
output = JSON.parse(
|
|
4201
|
-
|
|
4202
|
-
`\u{1F527} Debug: Extracted and parsed JSON from end of output (${extracted2.length} chars from ${rawOutput.length} total)`
|
|
4203
|
-
);
|
|
4204
|
-
logger.debug(`\u{1F527} Debug: Extracted JSON content: ${extracted2.slice(0, 200)}`);
|
|
4205
|
-
} catch (parseError) {
|
|
4206
|
-
logger.debug(
|
|
4207
|
-
`\u{1F527} Debug: Extracted text is not valid JSON: ${parseError instanceof Error ? parseError.message : "Unknown error"}`
|
|
4208
|
-
);
|
|
4228
|
+
output = JSON.parse(extractedTail);
|
|
4229
|
+
} catch {
|
|
4209
4230
|
output = rawOutput;
|
|
4210
4231
|
}
|
|
4211
4232
|
} else {
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4233
|
+
const extractedAny = this.extractJsonAnywhere(rawOutput);
|
|
4234
|
+
if (extractedAny) {
|
|
4235
|
+
try {
|
|
4236
|
+
output = JSON.parse(extractedAny);
|
|
4237
|
+
} catch {
|
|
4238
|
+
output = rawOutput;
|
|
4239
|
+
}
|
|
4240
|
+
} else {
|
|
4241
|
+
const m = /\berror\b\s*[:=]\s*(true|false)/i.exec(rawOutput);
|
|
4242
|
+
if (m) {
|
|
4243
|
+
output = { error: m[1].toLowerCase() === "true" };
|
|
4244
|
+
} else {
|
|
4245
|
+
output = rawOutput;
|
|
4246
|
+
}
|
|
4222
4247
|
}
|
|
4223
|
-
} catch {
|
|
4224
4248
|
}
|
|
4225
4249
|
}
|
|
4226
4250
|
let finalOutput = output;
|
|
@@ -4267,65 +4291,130 @@ var init_command_check_provider = __esm({
|
|
|
4267
4291
|
env: templateContext.env
|
|
4268
4292
|
};
|
|
4269
4293
|
const trimmedTransform = transformJs.trim();
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
const
|
|
4277
|
-
if (
|
|
4278
|
-
|
|
4279
|
-
const remaining = lines.slice(0, -1).join("\n");
|
|
4280
|
-
if (lastLine && !lastLine.includes("}") && !lastLine.includes("{")) {
|
|
4281
|
-
const returnTarget = lastLine.replace(/;$/, "");
|
|
4282
|
-
transformExpression = `(() => {
|
|
4283
|
-
${remaining}
|
|
4284
|
-
return ${returnTarget};
|
|
4285
|
-
})()`;
|
|
4286
|
-
} else {
|
|
4287
|
-
transformExpression = `(${trimmedTransform})`;
|
|
4288
|
-
}
|
|
4289
|
-
} else {
|
|
4290
|
-
transformExpression = `(${trimmedTransform})`;
|
|
4294
|
+
const buildBodyWithReturn = (raw) => {
|
|
4295
|
+
const t = raw.trim();
|
|
4296
|
+
const lines = t.split(/\n/);
|
|
4297
|
+
let i = lines.length - 1;
|
|
4298
|
+
while (i >= 0 && lines[i].trim().length === 0) i--;
|
|
4299
|
+
if (i < 0) return "return undefined;";
|
|
4300
|
+
const lastLine = lines[i].trim();
|
|
4301
|
+
if (/^return\b/i.test(lastLine)) {
|
|
4302
|
+
return t;
|
|
4291
4303
|
}
|
|
4292
|
-
|
|
4304
|
+
const idx = t.lastIndexOf(lastLine);
|
|
4305
|
+
const head = idx >= 0 ? t.slice(0, idx) : "";
|
|
4306
|
+
const lastExpr = lastLine.replace(/;\s*$/, "");
|
|
4307
|
+
return `${head}
|
|
4308
|
+
return (${lastExpr});`;
|
|
4309
|
+
};
|
|
4310
|
+
const bodyWithReturn = buildBodyWithReturn(trimmedTransform);
|
|
4293
4311
|
const code = `
|
|
4294
4312
|
const output = scope.output;
|
|
4295
4313
|
const pr = scope.pr;
|
|
4296
4314
|
const files = scope.files;
|
|
4297
4315
|
const outputs = scope.outputs;
|
|
4298
4316
|
const env = scope.env;
|
|
4299
|
-
const log = (...args) => {
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4317
|
+
const log = (...args) => { console.log('\u{1F50D} Debug:', ...args); };
|
|
4318
|
+
const __result = (function(){
|
|
4319
|
+
${bodyWithReturn}
|
|
4320
|
+
})();
|
|
4321
|
+
return __result;
|
|
4303
4322
|
`;
|
|
4323
|
+
if (!this.sandbox) {
|
|
4324
|
+
this.sandbox = this.createSecureSandbox();
|
|
4325
|
+
}
|
|
4326
|
+
let parsedFromSandboxJson = void 0;
|
|
4304
4327
|
try {
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4328
|
+
const stringifyCode = `
|
|
4329
|
+
const output = scope.output;
|
|
4330
|
+
const pr = scope.pr;
|
|
4331
|
+
const files = scope.files;
|
|
4332
|
+
const outputs = scope.outputs;
|
|
4333
|
+
const env = scope.env;
|
|
4334
|
+
const log = (...args) => { console.log('\u{1F50D} Debug:', ...args); };
|
|
4335
|
+
const __ret = (function(){
|
|
4336
|
+
${bodyWithReturn}
|
|
4337
|
+
})();
|
|
4338
|
+
return typeof __ret === 'object' && __ret !== null ? JSON.stringify(__ret) : null;
|
|
4339
|
+
`;
|
|
4340
|
+
const stringifyExec = this.sandbox.compile(stringifyCode);
|
|
4341
|
+
const jsonStr = stringifyExec({ scope: jsContext }).run();
|
|
4342
|
+
if (typeof jsonStr === "string" && jsonStr.trim().startsWith("{")) {
|
|
4343
|
+
parsedFromSandboxJson = JSON.parse(jsonStr);
|
|
4344
|
+
}
|
|
4309
4345
|
} catch {
|
|
4310
4346
|
}
|
|
4311
|
-
if (
|
|
4312
|
-
|
|
4347
|
+
if (parsedFromSandboxJson !== void 0) {
|
|
4348
|
+
finalOutput = parsedFromSandboxJson;
|
|
4349
|
+
} else {
|
|
4350
|
+
const exec2 = this.sandbox.compile(code);
|
|
4351
|
+
finalOutput = exec2({ scope: jsContext }).run();
|
|
4313
4352
|
}
|
|
4314
|
-
const exec2 = this.sandbox.compile(code);
|
|
4315
|
-
finalOutput = exec2({ scope: jsContext }).run();
|
|
4316
|
-
logger.verbose(`\u2713 Applied JavaScript transform successfully`);
|
|
4317
4353
|
try {
|
|
4318
|
-
|
|
4354
|
+
if (finalOutput && typeof finalOutput === "object" && !Array.isArray(finalOutput) && (finalOutput.error === void 0 || finalOutput.issues === void 0)) {
|
|
4355
|
+
const vm = await import("vm");
|
|
4356
|
+
const vmContext = vm.createContext({ scope: jsContext });
|
|
4357
|
+
const vmCode = `
|
|
4358
|
+
(function(){
|
|
4359
|
+
const output = scope.output; const pr = scope.pr; const files = scope.files; const outputs = scope.outputs; const env = scope.env; const log = ()=>{};
|
|
4360
|
+
${bodyWithReturn}
|
|
4361
|
+
})()
|
|
4362
|
+
`;
|
|
4363
|
+
const vmResult = vm.runInContext(vmCode, vmContext, { timeout: 1e3 });
|
|
4364
|
+
if (vmResult && typeof vmResult === "object") {
|
|
4365
|
+
finalOutput = vmResult;
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
} catch {
|
|
4369
|
+
}
|
|
4370
|
+
let finalSnapshot = null;
|
|
4371
|
+
try {
|
|
4372
|
+
if (finalOutput && typeof finalOutput === "object" && !Array.isArray(finalOutput)) {
|
|
4373
|
+
try {
|
|
4374
|
+
const stringifyExec = this.sandbox.compile("return JSON.stringify(scope.obj);");
|
|
4375
|
+
const jsonStr = stringifyExec({ obj: finalOutput }).run();
|
|
4376
|
+
if (typeof jsonStr === "string" && jsonStr.trim().startsWith("{")) {
|
|
4377
|
+
finalSnapshot = JSON.parse(jsonStr);
|
|
4378
|
+
}
|
|
4379
|
+
} catch {
|
|
4380
|
+
}
|
|
4381
|
+
if (!finalSnapshot) {
|
|
4382
|
+
try {
|
|
4383
|
+
finalSnapshot = JSON.parse(JSON.stringify(finalOutput));
|
|
4384
|
+
} catch {
|
|
4385
|
+
}
|
|
4386
|
+
}
|
|
4387
|
+
if (!finalSnapshot) {
|
|
4388
|
+
const tmp = {};
|
|
4389
|
+
for (const k of Object.keys(finalOutput)) {
|
|
4390
|
+
tmp[k] = finalOutput[k];
|
|
4391
|
+
}
|
|
4392
|
+
finalSnapshot = tmp;
|
|
4393
|
+
}
|
|
4394
|
+
}
|
|
4395
|
+
} catch {
|
|
4396
|
+
}
|
|
4397
|
+
this.__lastTransformSnapshot = finalSnapshot;
|
|
4398
|
+
try {
|
|
4399
|
+
const isObj = finalOutput && typeof finalOutput === "object" && !Array.isArray(finalOutput);
|
|
4400
|
+
const keys = isObj ? Object.keys(finalOutput).join(",") : typeof finalOutput;
|
|
4319
4401
|
logger.debug(
|
|
4320
|
-
|
|
4402
|
+
` transform_js: output typeof=${Array.isArray(finalOutput) ? "array" : typeof finalOutput} keys=${keys}`
|
|
4321
4403
|
);
|
|
4322
|
-
|
|
4404
|
+
if (isObj && finalOutput.issues) {
|
|
4405
|
+
const mi = finalOutput.issues;
|
|
4406
|
+
logger.debug(
|
|
4407
|
+
` transform_js: issues typeof=${Array.isArray(mi) ? "array" : typeof mi} len=${mi && mi.length || 0}`
|
|
4408
|
+
);
|
|
4409
|
+
}
|
|
4323
4410
|
try {
|
|
4324
|
-
|
|
4325
|
-
|
|
4411
|
+
if (isObj)
|
|
4412
|
+
logger.debug(` transform_js: error value=${String(finalOutput.error)}`);
|
|
4326
4413
|
} catch {
|
|
4327
4414
|
}
|
|
4415
|
+
} catch {
|
|
4328
4416
|
}
|
|
4417
|
+
logger.verbose(`\u2713 Applied JavaScript transform successfully`);
|
|
4329
4418
|
} catch (error) {
|
|
4330
4419
|
logger.error(
|
|
4331
4420
|
`\u2717 Failed to apply JavaScript transform: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
@@ -4346,13 +4435,175 @@ return ${returnTarget};
|
|
|
4346
4435
|
}
|
|
4347
4436
|
let issues = [];
|
|
4348
4437
|
let outputForDependents = finalOutput;
|
|
4438
|
+
const snapshotForExtraction = this.__lastTransformSnapshot || null;
|
|
4439
|
+
try {
|
|
4440
|
+
if (snapshotForExtraction) {
|
|
4441
|
+
logger.debug(` provider: snapshot keys=${Object.keys(snapshotForExtraction).join(",")}`);
|
|
4442
|
+
} else {
|
|
4443
|
+
logger.debug(` provider: snapshot is null`);
|
|
4444
|
+
}
|
|
4445
|
+
} catch {
|
|
4446
|
+
}
|
|
4447
|
+
try {
|
|
4448
|
+
if (Array.isArray(outputForDependents) && outputForDependents.length === 1) {
|
|
4449
|
+
const first = outputForDependents[0];
|
|
4450
|
+
if (typeof first === "string") {
|
|
4451
|
+
try {
|
|
4452
|
+
outputForDependents = JSON.parse(first);
|
|
4453
|
+
} catch {
|
|
4454
|
+
}
|
|
4455
|
+
} else if (first && typeof first === "object") {
|
|
4456
|
+
outputForDependents = first;
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
} catch {
|
|
4460
|
+
}
|
|
4349
4461
|
let content;
|
|
4350
4462
|
let extracted = null;
|
|
4351
4463
|
const trimmedRawOutput = typeof rawOutput === "string" ? rawOutput.trim() : void 0;
|
|
4352
4464
|
const commandConfig = config;
|
|
4353
4465
|
const isForEachParent = commandConfig.forEach === true;
|
|
4354
4466
|
if (!isForEachParent) {
|
|
4355
|
-
|
|
4467
|
+
try {
|
|
4468
|
+
const baseObj = snapshotForExtraction || finalOutput;
|
|
4469
|
+
if (baseObj && typeof baseObj === "object" && Object.prototype.hasOwnProperty.call(baseObj, "issues")) {
|
|
4470
|
+
const remaining = { ...baseObj };
|
|
4471
|
+
delete remaining.issues;
|
|
4472
|
+
outputForDependents = Object.keys(remaining).length > 0 ? remaining : void 0;
|
|
4473
|
+
try {
|
|
4474
|
+
const k = outputForDependents && typeof outputForDependents === "object" ? Object.keys(outputForDependents).join(",") : String(outputForDependents);
|
|
4475
|
+
logger.debug(` provider: generic-remaining keys=${k}`);
|
|
4476
|
+
} catch {
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
} catch {
|
|
4480
|
+
}
|
|
4481
|
+
const objForExtraction = snapshotForExtraction || finalOutput;
|
|
4482
|
+
if (objForExtraction && typeof objForExtraction === "object") {
|
|
4483
|
+
try {
|
|
4484
|
+
const rec = objForExtraction;
|
|
4485
|
+
const maybeIssues = rec.issues;
|
|
4486
|
+
const toPlainArray = (v) => {
|
|
4487
|
+
if (Array.isArray(v)) return v;
|
|
4488
|
+
try {
|
|
4489
|
+
if (v && typeof v === "object" && typeof v[Symbol.iterator] === "function") {
|
|
4490
|
+
return Array.from(v);
|
|
4491
|
+
}
|
|
4492
|
+
} catch {
|
|
4493
|
+
}
|
|
4494
|
+
const len = Number((v || {}).length);
|
|
4495
|
+
if (Number.isFinite(len) && len >= 0) {
|
|
4496
|
+
const arr2 = [];
|
|
4497
|
+
for (let i = 0; i < len; i++) arr2.push(v[i]);
|
|
4498
|
+
return arr2;
|
|
4499
|
+
}
|
|
4500
|
+
try {
|
|
4501
|
+
const cloned = JSON.parse(JSON.stringify(v));
|
|
4502
|
+
return Array.isArray(cloned) ? cloned : null;
|
|
4503
|
+
} catch {
|
|
4504
|
+
return null;
|
|
4505
|
+
}
|
|
4506
|
+
};
|
|
4507
|
+
try {
|
|
4508
|
+
const ctor = maybeIssues && maybeIssues.constructor ? maybeIssues.constructor.name : "unknown";
|
|
4509
|
+
logger.debug(
|
|
4510
|
+
` provider: issues inspect typeof=${typeof maybeIssues} Array.isArray=${Array.isArray(
|
|
4511
|
+
maybeIssues
|
|
4512
|
+
)} ctor=${ctor} keys=${Object.keys(maybeIssues || {}).join(",")}`
|
|
4513
|
+
);
|
|
4514
|
+
} catch {
|
|
4515
|
+
}
|
|
4516
|
+
const arr = toPlainArray(maybeIssues);
|
|
4517
|
+
if (arr) {
|
|
4518
|
+
const norm = this.normalizeIssueArray(arr);
|
|
4519
|
+
if (norm) {
|
|
4520
|
+
issues = norm;
|
|
4521
|
+
const remaining = { ...rec };
|
|
4522
|
+
delete remaining.issues;
|
|
4523
|
+
outputForDependents = Object.keys(remaining).length > 0 ? remaining : void 0;
|
|
4524
|
+
try {
|
|
4525
|
+
const keys = outputForDependents && typeof outputForDependents === "object" ? Object.keys(outputForDependents).join(",") : String(outputForDependents);
|
|
4526
|
+
logger.info(
|
|
4527
|
+
` provider: fast-path issues=${issues.length} remaining keys=${keys}`
|
|
4528
|
+
);
|
|
4529
|
+
} catch {
|
|
4530
|
+
}
|
|
4531
|
+
} else {
|
|
4532
|
+
try {
|
|
4533
|
+
logger.info(" provider: fast-path norm failed");
|
|
4534
|
+
} catch {
|
|
4535
|
+
}
|
|
4536
|
+
}
|
|
4537
|
+
} else {
|
|
4538
|
+
try {
|
|
4539
|
+
logger.info(" provider: fast-path arr unavailable");
|
|
4540
|
+
} catch {
|
|
4541
|
+
}
|
|
4542
|
+
}
|
|
4543
|
+
} catch {
|
|
4544
|
+
}
|
|
4545
|
+
}
|
|
4546
|
+
let extractionTarget = snapshotForExtraction || finalOutput;
|
|
4547
|
+
try {
|
|
4548
|
+
if (Array.isArray(extractionTarget) && extractionTarget.length === 1) {
|
|
4549
|
+
const first = extractionTarget[0];
|
|
4550
|
+
if (typeof first === "string") {
|
|
4551
|
+
try {
|
|
4552
|
+
extractionTarget = JSON.parse(first);
|
|
4553
|
+
} catch {
|
|
4554
|
+
extractionTarget = first;
|
|
4555
|
+
}
|
|
4556
|
+
} else if (first && typeof first === "object") {
|
|
4557
|
+
extractionTarget = first;
|
|
4558
|
+
}
|
|
4559
|
+
}
|
|
4560
|
+
} catch {
|
|
4561
|
+
}
|
|
4562
|
+
extracted = this.extractIssuesFromOutput(extractionTarget);
|
|
4563
|
+
try {
|
|
4564
|
+
if (extractionTarget !== (snapshotForExtraction || finalOutput)) {
|
|
4565
|
+
finalOutput = extractionTarget;
|
|
4566
|
+
}
|
|
4567
|
+
} catch {
|
|
4568
|
+
}
|
|
4569
|
+
if (!extracted && finalOutput && typeof finalOutput === "object") {
|
|
4570
|
+
try {
|
|
4571
|
+
const rec = finalOutput;
|
|
4572
|
+
const maybeIssues = rec.issues;
|
|
4573
|
+
if (maybeIssues && typeof maybeIssues === "object") {
|
|
4574
|
+
let arr = null;
|
|
4575
|
+
try {
|
|
4576
|
+
if (typeof maybeIssues[Symbol.iterator] === "function") {
|
|
4577
|
+
arr = Array.from(maybeIssues);
|
|
4578
|
+
}
|
|
4579
|
+
} catch {
|
|
4580
|
+
}
|
|
4581
|
+
if (!arr) {
|
|
4582
|
+
const len = Number(maybeIssues.length);
|
|
4583
|
+
if (Number.isFinite(len) && len >= 0) {
|
|
4584
|
+
arr = [];
|
|
4585
|
+
for (let i = 0; i < len; i++) arr.push(maybeIssues[i]);
|
|
4586
|
+
}
|
|
4587
|
+
}
|
|
4588
|
+
if (!arr) {
|
|
4589
|
+
try {
|
|
4590
|
+
arr = JSON.parse(JSON.stringify(maybeIssues));
|
|
4591
|
+
} catch {
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
if (arr && Array.isArray(arr)) {
|
|
4595
|
+
const norm = this.normalizeIssueArray(arr);
|
|
4596
|
+
if (norm) {
|
|
4597
|
+
issues = norm;
|
|
4598
|
+
const remaining = { ...rec };
|
|
4599
|
+
delete remaining.issues;
|
|
4600
|
+
outputForDependents = Object.keys(remaining).length > 0 ? remaining : void 0;
|
|
4601
|
+
}
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
} catch {
|
|
4605
|
+
}
|
|
4606
|
+
}
|
|
4356
4607
|
if (!extracted && typeof finalOutput === "string") {
|
|
4357
4608
|
try {
|
|
4358
4609
|
const parsed = JSON.parse(finalOutput);
|
|
@@ -4360,12 +4611,36 @@ return ${returnTarget};
|
|
|
4360
4611
|
if (extracted) {
|
|
4361
4612
|
issues = extracted.issues;
|
|
4362
4613
|
outputForDependents = extracted.remainingOutput;
|
|
4614
|
+
if (typeof extracted.remainingOutput === "object" && extracted.remainingOutput !== null && typeof extracted.remainingOutput.content === "string") {
|
|
4615
|
+
const c = String(extracted.remainingOutput.content).trim();
|
|
4616
|
+
if (c) content = c;
|
|
4617
|
+
}
|
|
4363
4618
|
}
|
|
4364
4619
|
} catch {
|
|
4620
|
+
try {
|
|
4621
|
+
const any = this.extractJsonAnywhere(finalOutput);
|
|
4622
|
+
if (any) {
|
|
4623
|
+
const parsed = JSON.parse(any);
|
|
4624
|
+
extracted = this.extractIssuesFromOutput(parsed);
|
|
4625
|
+
if (extracted) {
|
|
4626
|
+
issues = extracted.issues;
|
|
4627
|
+
outputForDependents = extracted.remainingOutput;
|
|
4628
|
+
if (typeof extracted.remainingOutput === "object" && extracted.remainingOutput !== null && typeof extracted.remainingOutput.content === "string") {
|
|
4629
|
+
const c = String(extracted.remainingOutput.content).trim();
|
|
4630
|
+
if (c) content = c;
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
} catch {
|
|
4635
|
+
}
|
|
4365
4636
|
}
|
|
4366
4637
|
} else if (extracted) {
|
|
4367
4638
|
issues = extracted.issues;
|
|
4368
4639
|
outputForDependents = extracted.remainingOutput;
|
|
4640
|
+
if (typeof extracted.remainingOutput === "object" && extracted.remainingOutput !== null && typeof extracted.remainingOutput.content === "string") {
|
|
4641
|
+
const c = String(extracted.remainingOutput.content).trim();
|
|
4642
|
+
if (c) content = c;
|
|
4643
|
+
}
|
|
4369
4644
|
}
|
|
4370
4645
|
if (!issues.length && this.shouldTreatAsTextOutput(trimmedRawOutput)) {
|
|
4371
4646
|
content = trimmedRawOutput;
|
|
@@ -4375,24 +4650,174 @@ return ${returnTarget};
|
|
|
4375
4650
|
content = trimmed;
|
|
4376
4651
|
}
|
|
4377
4652
|
}
|
|
4653
|
+
if (!issues.length && typeof trimmedRawOutput === "string") {
|
|
4654
|
+
try {
|
|
4655
|
+
const tryParsed = JSON.parse(trimmedRawOutput);
|
|
4656
|
+
const reextract = this.extractIssuesFromOutput(tryParsed);
|
|
4657
|
+
if (reextract && reextract.issues && reextract.issues.length) {
|
|
4658
|
+
issues = reextract.issues;
|
|
4659
|
+
if (!outputForDependents && reextract.remainingOutput) {
|
|
4660
|
+
outputForDependents = reextract.remainingOutput;
|
|
4661
|
+
}
|
|
4662
|
+
} else if (Array.isArray(tryParsed)) {
|
|
4663
|
+
const first = tryParsed[0];
|
|
4664
|
+
if (first && typeof first === "object" && Array.isArray(first.issues)) {
|
|
4665
|
+
const merged = [];
|
|
4666
|
+
for (const el of tryParsed) {
|
|
4667
|
+
if (el && typeof el === "object" && Array.isArray(el.issues)) {
|
|
4668
|
+
merged.push(...el.issues);
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
const flat = this.normalizeIssueArray(merged);
|
|
4672
|
+
if (flat) issues = flat;
|
|
4673
|
+
} else {
|
|
4674
|
+
const converted = [];
|
|
4675
|
+
for (const el of tryParsed) {
|
|
4676
|
+
if (typeof el === "string") {
|
|
4677
|
+
try {
|
|
4678
|
+
const obj = JSON.parse(el);
|
|
4679
|
+
converted.push(obj);
|
|
4680
|
+
} catch {
|
|
4681
|
+
}
|
|
4682
|
+
} else {
|
|
4683
|
+
converted.push(el);
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
const flat = this.normalizeIssueArray(converted);
|
|
4687
|
+
if (flat) issues = flat;
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
} catch {
|
|
4691
|
+
}
|
|
4692
|
+
if (!issues.length) {
|
|
4693
|
+
try {
|
|
4694
|
+
const any = this.extractJsonAnywhere(trimmedRawOutput);
|
|
4695
|
+
if (any) {
|
|
4696
|
+
const tryParsed = JSON.parse(any);
|
|
4697
|
+
const reextract = this.extractIssuesFromOutput(tryParsed);
|
|
4698
|
+
if (reextract && reextract.issues && reextract.issues.length) {
|
|
4699
|
+
issues = reextract.issues;
|
|
4700
|
+
if (!outputForDependents && reextract.remainingOutput) {
|
|
4701
|
+
outputForDependents = reextract.remainingOutput;
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
} catch {
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
}
|
|
4709
|
+
try {
|
|
4710
|
+
const srcObj = snapshotForExtraction || finalOutput;
|
|
4711
|
+
if (outputForDependents && typeof outputForDependents === "object" && srcObj && typeof srcObj === "object") {
|
|
4712
|
+
for (const k of Object.keys(srcObj)) {
|
|
4713
|
+
const v = srcObj[k];
|
|
4714
|
+
if (typeof v === "boolean" || typeof v === "number" || typeof v === "string") {
|
|
4715
|
+
outputForDependents[k] = v;
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
} catch {
|
|
4720
|
+
}
|
|
4721
|
+
try {
|
|
4722
|
+
if (outputForDependents && typeof outputForDependents === "object" && !Array.isArray(outputForDependents)) {
|
|
4723
|
+
const plain = {};
|
|
4724
|
+
for (const k of Object.keys(outputForDependents)) {
|
|
4725
|
+
plain[k] = outputForDependents[k];
|
|
4726
|
+
}
|
|
4727
|
+
outputForDependents = plain;
|
|
4728
|
+
}
|
|
4729
|
+
} catch {
|
|
4730
|
+
}
|
|
4378
4731
|
}
|
|
4379
4732
|
if (!content && this.shouldTreatAsTextOutput(trimmedRawOutput) && !isForEachParent) {
|
|
4380
4733
|
content = trimmedRawOutput;
|
|
4381
4734
|
}
|
|
4735
|
+
try {
|
|
4736
|
+
if (outputForDependents && typeof outputForDependents === "object") {
|
|
4737
|
+
outputForDependents = JSON.parse(JSON.stringify(outputForDependents));
|
|
4738
|
+
}
|
|
4739
|
+
} catch {
|
|
4740
|
+
}
|
|
4741
|
+
const promoted = {};
|
|
4742
|
+
try {
|
|
4743
|
+
const srcObj = snapshotForExtraction || finalOutput;
|
|
4744
|
+
if (srcObj && typeof srcObj === "object") {
|
|
4745
|
+
for (const k of Object.keys(srcObj)) {
|
|
4746
|
+
const v = srcObj[k];
|
|
4747
|
+
if (typeof v === "boolean") {
|
|
4748
|
+
if (v === true && promoted[k] === void 0) promoted[k] = true;
|
|
4749
|
+
} else if ((typeof v === "number" || typeof v === "string") && promoted[k] === void 0) {
|
|
4750
|
+
promoted[k] = v;
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
}
|
|
4754
|
+
} catch {
|
|
4755
|
+
}
|
|
4382
4756
|
const result = {
|
|
4383
4757
|
issues,
|
|
4384
4758
|
output: outputForDependents,
|
|
4385
|
-
...content ? { content } : {}
|
|
4759
|
+
...content ? { content } : {},
|
|
4760
|
+
...promoted
|
|
4386
4761
|
};
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
const
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4762
|
+
try {
|
|
4763
|
+
if (transformJs) {
|
|
4764
|
+
const rawObj = snapshotForExtraction || finalOutput;
|
|
4765
|
+
if (rawObj && typeof rawObj === "object") {
|
|
4766
|
+
result.__raw = rawObj;
|
|
4767
|
+
}
|
|
4768
|
+
}
|
|
4769
|
+
} catch {
|
|
4770
|
+
}
|
|
4771
|
+
try {
|
|
4772
|
+
const srcObj = snapshotForExtraction || finalOutput;
|
|
4773
|
+
const srcErr = (() => {
|
|
4774
|
+
try {
|
|
4775
|
+
if (snapshotForExtraction && typeof snapshotForExtraction === "object" && snapshotForExtraction.error !== void 0) {
|
|
4776
|
+
return Boolean(snapshotForExtraction.error);
|
|
4777
|
+
}
|
|
4778
|
+
if (finalOutput && typeof finalOutput === "object" && finalOutput.error !== void 0) {
|
|
4779
|
+
return Boolean(finalOutput.error);
|
|
4780
|
+
}
|
|
4781
|
+
} catch {
|
|
4782
|
+
}
|
|
4783
|
+
return void 0;
|
|
4784
|
+
})();
|
|
4785
|
+
const dst = result.output;
|
|
4786
|
+
if (srcObj && typeof srcObj === "object" && dst && typeof dst === "object") {
|
|
4787
|
+
try {
|
|
4788
|
+
logger.debug(
|
|
4789
|
+
` provider: safeguard src.error typeof=${typeof srcObj.error} val=${String(srcObj.error)} dst.hasErrorBefore=${String(dst.error !== void 0)}`
|
|
4790
|
+
);
|
|
4791
|
+
} catch {
|
|
4792
|
+
}
|
|
4793
|
+
for (const k of Object.keys(srcObj)) {
|
|
4794
|
+
const v = srcObj[k];
|
|
4795
|
+
if (typeof v === "boolean" || typeof v === "number" || typeof v === "string") {
|
|
4796
|
+
dst[k] = v;
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
if (srcErr !== void 0 && dst.error === void 0) {
|
|
4800
|
+
dst.error = srcErr;
|
|
4801
|
+
try {
|
|
4802
|
+
const k = Object.keys(dst).join(",");
|
|
4803
|
+
logger.debug(
|
|
4804
|
+
` provider: safeguard merged error -> output keys=${k} val=${String(dst.error)}`
|
|
4805
|
+
);
|
|
4806
|
+
} catch {
|
|
4807
|
+
}
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
} catch {
|
|
4811
|
+
}
|
|
4812
|
+
try {
|
|
4813
|
+
const out = result.output;
|
|
4814
|
+
if (out && typeof out === "object") {
|
|
4815
|
+
const k = Object.keys(out).join(",");
|
|
4816
|
+
logger.debug(` provider: return output keys=${k}`);
|
|
4817
|
+
} else {
|
|
4818
|
+
logger.debug(` provider: return output type=${typeof out}`);
|
|
4395
4819
|
}
|
|
4820
|
+
} catch {
|
|
4396
4821
|
}
|
|
4397
4822
|
return result;
|
|
4398
4823
|
} catch (error) {
|
|
@@ -4542,19 +4967,89 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4542
4967
|
* Looks for the last occurrence of { or [ and tries to parse from there
|
|
4543
4968
|
*/
|
|
4544
4969
|
extractJsonFromEnd(text) {
|
|
4545
|
-
const
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4970
|
+
const lastBrace = Math.max(text.lastIndexOf("}"), text.lastIndexOf("]"));
|
|
4971
|
+
if (lastBrace === -1) return null;
|
|
4972
|
+
let open = 0;
|
|
4973
|
+
for (let i = lastBrace; i >= 0; i--) {
|
|
4974
|
+
const ch = text[i];
|
|
4975
|
+
if (ch === "}" || ch === "]") open++;
|
|
4976
|
+
else if (ch === "{" || ch === "[") open--;
|
|
4977
|
+
if (open === 0 && (ch === "{" || ch === "[")) {
|
|
4978
|
+
const candidate = text.slice(i, lastBrace + 1).trim();
|
|
4979
|
+
try {
|
|
4980
|
+
JSON.parse(candidate);
|
|
4981
|
+
return candidate;
|
|
4982
|
+
} catch {
|
|
4983
|
+
return null;
|
|
4553
4984
|
}
|
|
4554
4985
|
}
|
|
4555
4986
|
}
|
|
4556
4987
|
return null;
|
|
4557
4988
|
}
|
|
4989
|
+
// Extract any balanced JSON object/array substring from anywhere in the text
|
|
4990
|
+
extractJsonAnywhere(text) {
|
|
4991
|
+
const n = text.length;
|
|
4992
|
+
let best = null;
|
|
4993
|
+
for (let i = 0; i < n; i++) {
|
|
4994
|
+
const start = text[i];
|
|
4995
|
+
if (start !== "{" && start !== "[") continue;
|
|
4996
|
+
let open = 0;
|
|
4997
|
+
let inString = false;
|
|
4998
|
+
let escape = false;
|
|
4999
|
+
for (let j = i; j < n; j++) {
|
|
5000
|
+
const ch = text[j];
|
|
5001
|
+
if (escape) {
|
|
5002
|
+
escape = false;
|
|
5003
|
+
continue;
|
|
5004
|
+
}
|
|
5005
|
+
if (ch === "\\") {
|
|
5006
|
+
escape = true;
|
|
5007
|
+
continue;
|
|
5008
|
+
}
|
|
5009
|
+
if (ch === '"') {
|
|
5010
|
+
inString = !inString;
|
|
5011
|
+
continue;
|
|
5012
|
+
}
|
|
5013
|
+
if (inString) continue;
|
|
5014
|
+
if (ch === "{" || ch === "[") open++;
|
|
5015
|
+
else if (ch === "}" || ch === "]") open--;
|
|
5016
|
+
if (open === 0 && (ch === "}" || ch === "]")) {
|
|
5017
|
+
const candidate = text.slice(i, j + 1).trim();
|
|
5018
|
+
try {
|
|
5019
|
+
JSON.parse(candidate);
|
|
5020
|
+
best = candidate;
|
|
5021
|
+
} catch {
|
|
5022
|
+
const strict = this.looseJsonToStrict(candidate);
|
|
5023
|
+
if (strict) {
|
|
5024
|
+
try {
|
|
5025
|
+
JSON.parse(strict);
|
|
5026
|
+
best = strict;
|
|
5027
|
+
} catch {
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
}
|
|
5031
|
+
break;
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return best;
|
|
5036
|
+
}
|
|
5037
|
+
// Best-effort conversion of object-literal-like strings to strict JSON
|
|
5038
|
+
looseJsonToStrict(candidate) {
|
|
5039
|
+
try {
|
|
5040
|
+
let s = candidate.trim();
|
|
5041
|
+
s = s.replace(/'/g, '"');
|
|
5042
|
+
s = s.replace(/([\{,]\s*)([A-Za-z_][A-Za-z0-9_-]*)\s*:/g, '$1"$2":');
|
|
5043
|
+
s = s.replace(/:\s*([A-Za-z_][A-Za-z0-9_-]*)\s*(?=[,}])/g, (m, word) => {
|
|
5044
|
+
const lw = String(word).toLowerCase();
|
|
5045
|
+
if (lw === "true" || lw === "false" || lw === "null") return `:${lw}`;
|
|
5046
|
+
return `:"${word}"`;
|
|
5047
|
+
});
|
|
5048
|
+
return s;
|
|
5049
|
+
} catch {
|
|
5050
|
+
return null;
|
|
5051
|
+
}
|
|
5052
|
+
}
|
|
4558
5053
|
/**
|
|
4559
5054
|
* Recursively apply JSON-smart wrapper to outputs object values
|
|
4560
5055
|
*/
|
|
@@ -4602,6 +5097,20 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4602
5097
|
];
|
|
4603
5098
|
}
|
|
4604
5099
|
extractIssuesFromOutput(output) {
|
|
5100
|
+
try {
|
|
5101
|
+
logger.info(
|
|
5102
|
+
` extractIssuesFromOutput: typeof=${Array.isArray(output) ? "array" : typeof output}`
|
|
5103
|
+
);
|
|
5104
|
+
if (typeof output === "object" && output) {
|
|
5105
|
+
const rec = output;
|
|
5106
|
+
logger.info(
|
|
5107
|
+
` extractIssuesFromOutput: keys=${Object.keys(rec).join(",")} issuesIsArray=${Array.isArray(
|
|
5108
|
+
rec.issues
|
|
5109
|
+
)}`
|
|
5110
|
+
);
|
|
5111
|
+
}
|
|
5112
|
+
} catch {
|
|
5113
|
+
}
|
|
4605
5114
|
if (output === null || output === void 0) {
|
|
4606
5115
|
return null;
|
|
4607
5116
|
}
|
|
@@ -4609,9 +5118,21 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4609
5118
|
return null;
|
|
4610
5119
|
}
|
|
4611
5120
|
if (Array.isArray(output)) {
|
|
4612
|
-
const
|
|
4613
|
-
if (issues) {
|
|
4614
|
-
|
|
5121
|
+
const first = output[0];
|
|
5122
|
+
if (first && typeof first === "object" && !Array.isArray(first.message) && Array.isArray(first.issues)) {
|
|
5123
|
+
const merged = [];
|
|
5124
|
+
for (const el of output) {
|
|
5125
|
+
if (el && typeof el === "object" && Array.isArray(el.issues)) {
|
|
5126
|
+
merged.push(...el.issues);
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
const flat = this.normalizeIssueArray(merged);
|
|
5130
|
+
if (flat) return { issues: flat, remainingOutput: void 0 };
|
|
5131
|
+
} else {
|
|
5132
|
+
const issues = this.normalizeIssueArray(output);
|
|
5133
|
+
if (issues) {
|
|
5134
|
+
return { issues, remainingOutput: void 0 };
|
|
5135
|
+
}
|
|
4615
5136
|
}
|
|
4616
5137
|
return null;
|
|
4617
5138
|
}
|
|
@@ -4739,10 +5260,28 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4739
5260
|
}
|
|
4740
5261
|
async renderCommandTemplate(template, context) {
|
|
4741
5262
|
try {
|
|
4742
|
-
|
|
5263
|
+
let tpl = template;
|
|
5264
|
+
if (tpl.includes("{{")) {
|
|
5265
|
+
tpl = tpl.replace(/\{\{([\s\S]*?)\}\}/g, (_m, inner) => {
|
|
5266
|
+
const fixed = String(inner).replace(/\[\"/g, "['").replace(/\"\]/g, "']");
|
|
5267
|
+
return `{{ ${fixed} }}`;
|
|
5268
|
+
});
|
|
5269
|
+
}
|
|
5270
|
+
let rendered = await this.liquid.parseAndRender(tpl, context);
|
|
5271
|
+
if (/\{\{[\s\S]*?\}\}/.test(rendered)) {
|
|
5272
|
+
try {
|
|
5273
|
+
rendered = this.renderWithJsExpressions(rendered, context);
|
|
5274
|
+
} catch {
|
|
5275
|
+
}
|
|
5276
|
+
}
|
|
5277
|
+
return rendered;
|
|
4743
5278
|
} catch (error) {
|
|
4744
|
-
logger.debug(`\u{1F527} Debug: Liquid
|
|
4745
|
-
|
|
5279
|
+
logger.debug(`\u{1F527} Debug: Liquid templating failed, trying JS-expression fallback: ${error}`);
|
|
5280
|
+
try {
|
|
5281
|
+
return this.renderWithJsExpressions(template, context);
|
|
5282
|
+
} catch {
|
|
5283
|
+
return template;
|
|
5284
|
+
}
|
|
4746
5285
|
}
|
|
4747
5286
|
}
|
|
4748
5287
|
renderWithJsExpressions(template, context) {
|
|
@@ -4755,9 +5294,7 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4755
5294
|
const expressionRegex = /\{\{\s*([^{}]+?)\s*\}\}/g;
|
|
4756
5295
|
return template.replace(expressionRegex, (_match, expr) => {
|
|
4757
5296
|
const expression = String(expr).trim();
|
|
4758
|
-
if (!expression)
|
|
4759
|
-
return "";
|
|
4760
|
-
}
|
|
5297
|
+
if (!expression) return "";
|
|
4761
5298
|
try {
|
|
4762
5299
|
const evalCode = `
|
|
4763
5300
|
const pr = scope.pr;
|
|
@@ -4766,14 +5303,11 @@ ${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
|
4766
5303
|
const env = scope.env;
|
|
4767
5304
|
return (${expression});
|
|
4768
5305
|
`;
|
|
4769
|
-
if (!this.sandbox)
|
|
4770
|
-
this.sandbox = this.createSecureSandbox();
|
|
4771
|
-
}
|
|
5306
|
+
if (!this.sandbox) this.sandbox = this.createSecureSandbox();
|
|
4772
5307
|
const evaluator = this.sandbox.compile(evalCode);
|
|
4773
5308
|
const result = evaluator({ scope }).run();
|
|
4774
5309
|
return result === void 0 || result === null ? "" : String(result);
|
|
4775
|
-
} catch
|
|
4776
|
-
logger.debug(`\u{1F527} Debug: Failed to evaluate expression: ${expression} - ${evaluationError}`);
|
|
5310
|
+
} catch {
|
|
4777
5311
|
return "";
|
|
4778
5312
|
}
|
|
4779
5313
|
});
|
|
@@ -5200,7 +5734,19 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5200
5734
|
previousOutputs
|
|
5201
5735
|
);
|
|
5202
5736
|
try {
|
|
5203
|
-
|
|
5737
|
+
try {
|
|
5738
|
+
const isObj = context.output && typeof context.output === "object";
|
|
5739
|
+
const keys = isObj ? Object.keys(context.output).join(",") : typeof context.output;
|
|
5740
|
+
let errorVal = void 0;
|
|
5741
|
+
if (isObj && context.output.error !== void 0)
|
|
5742
|
+
errorVal = context.output.error;
|
|
5743
|
+
(init_logger(), __toCommonJS(logger_exports)).logger.debug(
|
|
5744
|
+
` fail_if: evaluating '${expression}' with output keys=${keys} error=${String(errorVal)}`
|
|
5745
|
+
);
|
|
5746
|
+
} catch {
|
|
5747
|
+
}
|
|
5748
|
+
const res = this.evaluateExpression(expression, context);
|
|
5749
|
+
return res;
|
|
5204
5750
|
} catch (error) {
|
|
5205
5751
|
console.warn(`Failed to evaluate fail_if expression: ${error}`);
|
|
5206
5752
|
return false;
|
|
@@ -5304,6 +5850,16 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5304
5850
|
results.length = 0;
|
|
5305
5851
|
results.push(...filteredResults, ...checkResults);
|
|
5306
5852
|
}
|
|
5853
|
+
try {
|
|
5854
|
+
if (checkName === "B") {
|
|
5855
|
+
console.error(
|
|
5856
|
+
`\u{1F527} Debug: fail_if results for ${checkName}: ${JSON.stringify(results)} context.output=${JSON.stringify(
|
|
5857
|
+
context.output
|
|
5858
|
+
)}`
|
|
5859
|
+
);
|
|
5860
|
+
}
|
|
5861
|
+
} catch {
|
|
5862
|
+
}
|
|
5307
5863
|
return results;
|
|
5308
5864
|
}
|
|
5309
5865
|
/**
|
|
@@ -5484,6 +6040,10 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5484
6040
|
exec = this.sandbox.compile(`return (${normalizedExpr});`);
|
|
5485
6041
|
}
|
|
5486
6042
|
const result = exec(scope).run();
|
|
6043
|
+
try {
|
|
6044
|
+
(init_logger(), __toCommonJS(logger_exports)).logger.debug(` fail_if: result=${Boolean(result)}`);
|
|
6045
|
+
} catch {
|
|
6046
|
+
}
|
|
5487
6047
|
return Boolean(result);
|
|
5488
6048
|
} catch (error) {
|
|
5489
6049
|
console.error("\u274C Failed to evaluate expression:", condition, error);
|
|
@@ -5553,6 +6113,66 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5553
6113
|
} else if (extractedOutput && typeof extractedOutput === "object") {
|
|
5554
6114
|
Object.assign(aggregatedOutput, extractedOutput);
|
|
5555
6115
|
}
|
|
6116
|
+
try {
|
|
6117
|
+
const raw = reviewSummaryWithOutput.__raw;
|
|
6118
|
+
if (raw && typeof raw === "object") {
|
|
6119
|
+
Object.assign(aggregatedOutput, raw);
|
|
6120
|
+
}
|
|
6121
|
+
} catch {
|
|
6122
|
+
}
|
|
6123
|
+
try {
|
|
6124
|
+
if (typeof extractedOutput === "string") {
|
|
6125
|
+
const parsed = this.tryExtractJsonFromEnd(extractedOutput) ?? (() => {
|
|
6126
|
+
try {
|
|
6127
|
+
return JSON.parse(extractedOutput);
|
|
6128
|
+
} catch {
|
|
6129
|
+
return null;
|
|
6130
|
+
}
|
|
6131
|
+
})();
|
|
6132
|
+
if (parsed !== null) {
|
|
6133
|
+
if (Array.isArray(parsed)) {
|
|
6134
|
+
aggregatedOutput.items = parsed;
|
|
6135
|
+
} else if (typeof parsed === "object") {
|
|
6136
|
+
Object.assign(aggregatedOutput, parsed);
|
|
6137
|
+
}
|
|
6138
|
+
}
|
|
6139
|
+
const lower = extractedOutput.toLowerCase();
|
|
6140
|
+
const boolFrom = (key) => {
|
|
6141
|
+
const reTrue = new RegExp(
|
|
6142
|
+
`(?:^|[^a-z0-9_])${key}[^a-z0-9_]*[:=][^a-z0-9_]*true(?:[^a-z0-9_]|$)`
|
|
6143
|
+
);
|
|
6144
|
+
const reFalse = new RegExp(
|
|
6145
|
+
`(?:^|[^a-z0-9_])${key}[^a-z0-9_]*[:=][^a-z0-9_]*false(?:[^a-z0-9_]|$)`
|
|
6146
|
+
);
|
|
6147
|
+
if (reTrue.test(lower)) return true;
|
|
6148
|
+
if (reFalse.test(lower)) return false;
|
|
6149
|
+
return null;
|
|
6150
|
+
};
|
|
6151
|
+
const keys = ["error"];
|
|
6152
|
+
for (const k of keys) {
|
|
6153
|
+
const v = boolFrom(k);
|
|
6154
|
+
if (v !== null && aggregatedOutput[k] === void 0) {
|
|
6155
|
+
aggregatedOutput[k] = v;
|
|
6156
|
+
}
|
|
6157
|
+
}
|
|
6158
|
+
}
|
|
6159
|
+
} catch {
|
|
6160
|
+
}
|
|
6161
|
+
try {
|
|
6162
|
+
const rsAny = reviewSummaryWithOutput;
|
|
6163
|
+
const hasStructuredOutput = extractedOutput !== void 0 && extractedOutput !== null;
|
|
6164
|
+
if (!hasStructuredOutput && typeof rsAny?.content === "string") {
|
|
6165
|
+
const parsedFromContent = this.tryExtractJsonFromEnd(rsAny.content);
|
|
6166
|
+
if (parsedFromContent !== null && parsedFromContent !== void 0) {
|
|
6167
|
+
if (Array.isArray(parsedFromContent)) {
|
|
6168
|
+
aggregatedOutput.items = parsedFromContent;
|
|
6169
|
+
} else if (typeof parsedFromContent === "object") {
|
|
6170
|
+
Object.assign(aggregatedOutput, parsedFromContent);
|
|
6171
|
+
}
|
|
6172
|
+
}
|
|
6173
|
+
}
|
|
6174
|
+
} catch {
|
|
6175
|
+
}
|
|
5556
6176
|
const context = {
|
|
5557
6177
|
output: aggregatedOutput,
|
|
5558
6178
|
outputs: (() => {
|
|
@@ -5579,6 +6199,23 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5579
6199
|
}
|
|
5580
6200
|
return context;
|
|
5581
6201
|
}
|
|
6202
|
+
// Minimal JSON-from-end extractor for fail_if context fallback
|
|
6203
|
+
tryExtractJsonFromEnd(text) {
|
|
6204
|
+
try {
|
|
6205
|
+
const lines = text.split("\n");
|
|
6206
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
6207
|
+
const t = lines[i].trim();
|
|
6208
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
6209
|
+
const candidate = lines.slice(i).join("\n").trim();
|
|
6210
|
+
if (candidate.startsWith("{") && candidate.endsWith("}") || candidate.startsWith("[") && candidate.endsWith("]")) {
|
|
6211
|
+
return JSON.parse(candidate);
|
|
6212
|
+
}
|
|
6213
|
+
}
|
|
6214
|
+
}
|
|
6215
|
+
} catch {
|
|
6216
|
+
}
|
|
6217
|
+
return null;
|
|
6218
|
+
}
|
|
5582
6219
|
/**
|
|
5583
6220
|
* Check if any failure condition requires halting execution
|
|
5584
6221
|
*/
|
|
@@ -7059,6 +7696,8 @@ ${expr}
|
|
|
7059
7696
|
let normalizedOutput;
|
|
7060
7697
|
if (Array.isArray(output)) {
|
|
7061
7698
|
normalizedOutput = output;
|
|
7699
|
+
} else if (output && typeof output === "object" && Array.isArray(output.items)) {
|
|
7700
|
+
normalizedOutput = output.items;
|
|
7062
7701
|
} else if (typeof output === "string") {
|
|
7063
7702
|
try {
|
|
7064
7703
|
const parsed = JSON.parse(output);
|
|
@@ -7255,8 +7894,11 @@ ${expr}
|
|
|
7255
7894
|
const templatePath = path8.join(__dirname, `../output/${sanitizedSchema}/template.liquid`);
|
|
7256
7895
|
templateContent = await fs8.readFile(templatePath, "utf-8");
|
|
7257
7896
|
}
|
|
7897
|
+
const filteredIssues = (reviewSummary.issues || []).filter(
|
|
7898
|
+
(issue) => !(issue.file === "system" && issue.line === 0)
|
|
7899
|
+
);
|
|
7258
7900
|
const templateData = {
|
|
7259
|
-
issues:
|
|
7901
|
+
issues: filteredIssues,
|
|
7260
7902
|
checkName
|
|
7261
7903
|
};
|
|
7262
7904
|
const rendered = await liquid.parseAndRender(templateContent, templateData);
|
|
@@ -7356,6 +7998,13 @@ ${expr}
|
|
|
7356
7998
|
]
|
|
7357
7999
|
};
|
|
7358
8000
|
}
|
|
8001
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
8002
|
+
for (const [child, depsArr] of Object.entries(dependencies)) {
|
|
8003
|
+
for (const p of depsArr || []) {
|
|
8004
|
+
if (!childrenByParent.has(p)) childrenByParent.set(p, []);
|
|
8005
|
+
childrenByParent.get(p).push(child);
|
|
8006
|
+
}
|
|
8007
|
+
}
|
|
7359
8008
|
const stats = DependencyResolver.getExecutionStats(dependencyGraph);
|
|
7360
8009
|
if (debug) {
|
|
7361
8010
|
log2(
|
|
@@ -7391,7 +8040,12 @@ ${expr}
|
|
|
7391
8040
|
`\u{1F527} Debug: Executing level ${executionGroup.level} with ${executionGroup.parallel.length} checks (parallelism: ${actualParallelism})`
|
|
7392
8041
|
);
|
|
7393
8042
|
}
|
|
7394
|
-
const
|
|
8043
|
+
const levelChecks = executionGroup.parallel.filter((name) => !results.has(name));
|
|
8044
|
+
const levelTaskFunctions = levelChecks.map((checkName) => async () => {
|
|
8045
|
+
if (results.has(checkName)) {
|
|
8046
|
+
if (debug) log2(`\u{1F527} Debug: Skipping ${checkName} (already satisfied earlier)`);
|
|
8047
|
+
return { checkName, error: null, result: results.get(checkName) };
|
|
8048
|
+
}
|
|
7395
8049
|
const checkConfig = config.checks[checkName];
|
|
7396
8050
|
if (!checkConfig) {
|
|
7397
8051
|
return {
|
|
@@ -7464,13 +8118,21 @@ ${expr}
|
|
|
7464
8118
|
const id = issue.ruleId || "";
|
|
7465
8119
|
return id.endsWith("/__skipped");
|
|
7466
8120
|
});
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
|
|
7473
|
-
|
|
8121
|
+
const depExtended = depRes;
|
|
8122
|
+
const isDepForEachParent = !!depExtended.isForEach;
|
|
8123
|
+
let hasFatalFailure = false;
|
|
8124
|
+
if (!isDepForEachParent) {
|
|
8125
|
+
const issues = depRes.issues || [];
|
|
8126
|
+
hasFatalFailure = issues.some((issue) => {
|
|
8127
|
+
const id = issue.ruleId || "";
|
|
8128
|
+
return id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/timeout" || id.endsWith("/command/timeout") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output") || id.endsWith("/forEach/iteration_error") || id.endsWith("_fail_if") || id.endsWith("/global_fail_if");
|
|
8129
|
+
});
|
|
8130
|
+
if (!hasFatalFailure && config && (config.fail_if || config.checks[depId]?.fail_if)) {
|
|
8131
|
+
try {
|
|
8132
|
+
hasFatalFailure = await this.failIfTriggered(depId, depRes, config);
|
|
8133
|
+
} catch {
|
|
8134
|
+
}
|
|
8135
|
+
}
|
|
7474
8136
|
}
|
|
7475
8137
|
if (debug) {
|
|
7476
8138
|
log2(
|
|
@@ -7493,10 +8155,12 @@ ${expr}
|
|
|
7493
8155
|
if (results.has(depId)) {
|
|
7494
8156
|
const depResult = results.get(depId);
|
|
7495
8157
|
const depForEachResult = depResult;
|
|
7496
|
-
if (depForEachResult.isForEach
|
|
8158
|
+
if (depForEachResult.isForEach || Array.isArray(depForEachResult.forEachItemResults) || Array.isArray(depForEachResult.forEachItems)) {
|
|
7497
8159
|
if (!isForEachDependent) {
|
|
7498
8160
|
isForEachDependent = true;
|
|
7499
|
-
forEachItems = depForEachResult.forEachItems
|
|
8161
|
+
forEachItems = Array.isArray(depForEachResult.forEachItems) ? depForEachResult.forEachItems : new Array(
|
|
8162
|
+
Array.isArray(depForEachResult.forEachItemResults) ? depForEachResult.forEachItemResults.length : 0
|
|
8163
|
+
).fill(void 0);
|
|
7500
8164
|
forEachParentName = depId;
|
|
7501
8165
|
}
|
|
7502
8166
|
forEachParents.push(depId);
|
|
@@ -7537,6 +8201,18 @@ ${expr}
|
|
|
7537
8201
|
}
|
|
7538
8202
|
let finalResult;
|
|
7539
8203
|
if (isForEachDependent && forEachParentName) {
|
|
8204
|
+
if (!Array.isArray(forEachItems)) {
|
|
8205
|
+
forEachItems = [];
|
|
8206
|
+
}
|
|
8207
|
+
if (!Array.isArray(forEachItems)) {
|
|
8208
|
+
this.recordSkip(checkName, "dependency_failed");
|
|
8209
|
+
return {
|
|
8210
|
+
checkName,
|
|
8211
|
+
error: null,
|
|
8212
|
+
result: { issues: [] },
|
|
8213
|
+
skipped: true
|
|
8214
|
+
};
|
|
8215
|
+
}
|
|
7540
8216
|
this.recordForEachPreview(checkName, forEachItems);
|
|
7541
8217
|
if (forEachItems.length === 0) {
|
|
7542
8218
|
if (debug) {
|
|
@@ -7545,6 +8221,7 @@ ${expr}
|
|
|
7545
8221
|
);
|
|
7546
8222
|
}
|
|
7547
8223
|
logger.info(` forEach: no items from "${forEachParentName}", skipping check...`);
|
|
8224
|
+
this.recordSkip(checkName, "dependency_failed");
|
|
7548
8225
|
finalResult = {
|
|
7549
8226
|
issues: [],
|
|
7550
8227
|
output: []
|
|
@@ -7553,22 +8230,187 @@ ${expr}
|
|
|
7553
8230
|
finalResult.forEachItems = [];
|
|
7554
8231
|
} else {
|
|
7555
8232
|
if (debug) {
|
|
7556
|
-
|
|
8233
|
+
console.log(
|
|
7557
8234
|
`\u{1F504} Debug: Check "${checkName}" depends on forEach check "${forEachParentName}", executing ${forEachItems.length} times`
|
|
7558
8235
|
);
|
|
7559
8236
|
}
|
|
8237
|
+
const __itemCount = Array.isArray(forEachItems) ? forEachItems.length : 0;
|
|
7560
8238
|
logger.info(
|
|
7561
|
-
` forEach: processing ${
|
|
8239
|
+
` forEach: processing ${__itemCount} items from "${forEachParentName}"...`
|
|
7562
8240
|
);
|
|
7563
8241
|
const allIssues = [];
|
|
7564
|
-
const allOutputs =
|
|
8242
|
+
const allOutputs = new Array(forEachItems.length);
|
|
7565
8243
|
const aggregatedContents = [];
|
|
8244
|
+
const perItemResults = new Array(
|
|
8245
|
+
forEachItems.length
|
|
8246
|
+
);
|
|
8247
|
+
const inlineAgg = /* @__PURE__ */ new Map();
|
|
8248
|
+
const execInlineDescendants = async (parentName, itemIndex, baseDeps) => {
|
|
8249
|
+
const children = (childrenByParent.get(parentName) || []).filter((child) => {
|
|
8250
|
+
const deps = dependencies[child] || [];
|
|
8251
|
+
return deps.length === 1 && deps[0] === parentName;
|
|
8252
|
+
});
|
|
8253
|
+
for (const childName of children) {
|
|
8254
|
+
const childCfg = config.checks[childName];
|
|
8255
|
+
const childProviderType = childCfg.type || "ai";
|
|
8256
|
+
const childProv = this.providerRegistry.getProviderOrThrow(childProviderType);
|
|
8257
|
+
this.setProviderWebhookContext(childProv);
|
|
8258
|
+
const childProviderConfig = {
|
|
8259
|
+
type: childProviderType,
|
|
8260
|
+
prompt: childCfg.prompt,
|
|
8261
|
+
exec: childCfg.exec,
|
|
8262
|
+
focus: childCfg.focus || this.mapCheckNameToFocus(childName),
|
|
8263
|
+
schema: childCfg.schema,
|
|
8264
|
+
group: childCfg.group,
|
|
8265
|
+
checkName: childName,
|
|
8266
|
+
eventContext: prInfo.eventContext,
|
|
8267
|
+
transform: childCfg.transform,
|
|
8268
|
+
transform_js: childCfg.transform_js,
|
|
8269
|
+
env: childCfg.env,
|
|
8270
|
+
forEach: childCfg.forEach,
|
|
8271
|
+
ai: {
|
|
8272
|
+
timeout: timeout || 6e5,
|
|
8273
|
+
debug,
|
|
8274
|
+
...childCfg.ai || {}
|
|
8275
|
+
}
|
|
8276
|
+
};
|
|
8277
|
+
const childDepResults = /* @__PURE__ */ new Map();
|
|
8278
|
+
const childAllDeps = DependencyResolver.getAllDependencies(
|
|
8279
|
+
childName,
|
|
8280
|
+
dependencyGraph.nodes
|
|
8281
|
+
);
|
|
8282
|
+
for (const dep of childAllDeps) {
|
|
8283
|
+
const baseRes = baseDeps.get(dep);
|
|
8284
|
+
if (baseRes) {
|
|
8285
|
+
childDepResults.set(dep, baseRes);
|
|
8286
|
+
continue;
|
|
8287
|
+
}
|
|
8288
|
+
const globalRes = results.get(dep);
|
|
8289
|
+
if (!globalRes) continue;
|
|
8290
|
+
if (globalRes && (globalRes.isForEach || Array.isArray(globalRes.forEachItemResults) || Array.isArray(globalRes.output))) {
|
|
8291
|
+
if (Array.isArray(globalRes.forEachItemResults) && globalRes.forEachItemResults[itemIndex]) {
|
|
8292
|
+
childDepResults.set(dep, globalRes.forEachItemResults[itemIndex]);
|
|
8293
|
+
} else if (Array.isArray(globalRes.output) && globalRes.output[itemIndex] !== void 0) {
|
|
8294
|
+
childDepResults.set(dep, {
|
|
8295
|
+
issues: [],
|
|
8296
|
+
output: globalRes.output[itemIndex]
|
|
8297
|
+
});
|
|
8298
|
+
} else {
|
|
8299
|
+
childDepResults.set(dep, globalRes);
|
|
8300
|
+
}
|
|
8301
|
+
} else {
|
|
8302
|
+
childDepResults.set(dep, globalRes);
|
|
8303
|
+
}
|
|
8304
|
+
}
|
|
8305
|
+
const parentItemRes = childDepResults.get(parentName);
|
|
8306
|
+
if (parentItemRes) {
|
|
8307
|
+
try {
|
|
8308
|
+
const pout = parentItemRes.output;
|
|
8309
|
+
if (pout && typeof pout === "object" && pout.error === true) {
|
|
8310
|
+
continue;
|
|
8311
|
+
}
|
|
8312
|
+
} catch {
|
|
8313
|
+
}
|
|
8314
|
+
const fatal = (parentItemRes.issues || []).some((issue) => {
|
|
8315
|
+
const id = issue.ruleId || "";
|
|
8316
|
+
const sev = issue.severity || "error";
|
|
8317
|
+
return sev === "error" || sev === "critical" || id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/timeout" || id.endsWith("/command/timeout") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id.endsWith("/forEach/iteration_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output") || id.endsWith("_fail_if") || id.endsWith("/global_fail_if");
|
|
8318
|
+
});
|
|
8319
|
+
if (fatal) {
|
|
8320
|
+
continue;
|
|
8321
|
+
}
|
|
8322
|
+
}
|
|
8323
|
+
if (childCfg.if) {
|
|
8324
|
+
const condResults = new Map(results);
|
|
8325
|
+
for (const [k, v] of childDepResults) condResults.set(k, v);
|
|
8326
|
+
const shouldRunChild = await this.evaluateCheckCondition(
|
|
8327
|
+
childName,
|
|
8328
|
+
childCfg.if,
|
|
8329
|
+
prInfo,
|
|
8330
|
+
condResults,
|
|
8331
|
+
debug
|
|
8332
|
+
);
|
|
8333
|
+
if (!shouldRunChild) {
|
|
8334
|
+
continue;
|
|
8335
|
+
}
|
|
8336
|
+
}
|
|
8337
|
+
const childIterStart = this.recordIterationStart(childName);
|
|
8338
|
+
const childItemRes = await this.executeWithRouting(
|
|
8339
|
+
childName,
|
|
8340
|
+
childCfg,
|
|
8341
|
+
childProv,
|
|
8342
|
+
childProviderConfig,
|
|
8343
|
+
prInfo,
|
|
8344
|
+
childDepResults,
|
|
8345
|
+
sessionInfo,
|
|
8346
|
+
config,
|
|
8347
|
+
dependencyGraph,
|
|
8348
|
+
debug,
|
|
8349
|
+
results,
|
|
8350
|
+
{ index: itemIndex, total: forEachItems.length, parent: parentName }
|
|
8351
|
+
);
|
|
8352
|
+
if (config && (config.fail_if || childCfg.fail_if)) {
|
|
8353
|
+
const fRes = await this.evaluateFailureConditions(
|
|
8354
|
+
childName,
|
|
8355
|
+
childItemRes,
|
|
8356
|
+
config
|
|
8357
|
+
);
|
|
8358
|
+
if (fRes.length > 0) {
|
|
8359
|
+
const fIssues = fRes.filter((f) => f.failed).map((f) => ({
|
|
8360
|
+
file: "system",
|
|
8361
|
+
line: 0,
|
|
8362
|
+
ruleId: f.conditionName,
|
|
8363
|
+
message: f.message || `Failure condition met: ${f.expression}`,
|
|
8364
|
+
severity: f.severity || "error",
|
|
8365
|
+
category: "logic"
|
|
8366
|
+
}));
|
|
8367
|
+
childItemRes.issues = [...childItemRes.issues || [], ...fIssues];
|
|
8368
|
+
}
|
|
8369
|
+
}
|
|
8370
|
+
if (!inlineAgg.has(childName)) {
|
|
8371
|
+
inlineAgg.set(childName, {
|
|
8372
|
+
issues: [],
|
|
8373
|
+
outputs: new Array(forEachItems.length),
|
|
8374
|
+
contents: [],
|
|
8375
|
+
perItemResults: new Array(forEachItems.length)
|
|
8376
|
+
});
|
|
8377
|
+
}
|
|
8378
|
+
const agg = inlineAgg.get(childName);
|
|
8379
|
+
if (childItemRes.issues) agg.issues.push(...childItemRes.issues);
|
|
8380
|
+
const out = childItemRes.output;
|
|
8381
|
+
agg.outputs[itemIndex] = out;
|
|
8382
|
+
agg.perItemResults[itemIndex] = childItemRes;
|
|
8383
|
+
const c = childItemRes.content;
|
|
8384
|
+
if (typeof c === "string" && c.trim()) agg.contents.push(c.trim());
|
|
8385
|
+
const childHadFatal = this.hasFatal(childItemRes.issues || []);
|
|
8386
|
+
this.recordIterationComplete(
|
|
8387
|
+
childName,
|
|
8388
|
+
childIterStart,
|
|
8389
|
+
!childHadFatal,
|
|
8390
|
+
childItemRes.issues || [],
|
|
8391
|
+
childItemRes.output
|
|
8392
|
+
);
|
|
8393
|
+
const nextBase = new Map(baseDeps);
|
|
8394
|
+
nextBase.set(childName, childItemRes);
|
|
8395
|
+
await execInlineDescendants(childName, itemIndex, nextBase);
|
|
8396
|
+
}
|
|
8397
|
+
};
|
|
7566
8398
|
const itemTasks = forEachItems.map((item, itemIndex) => async () => {
|
|
7567
8399
|
const forEachDependencyResults = /* @__PURE__ */ new Map();
|
|
7568
8400
|
for (const [depName, depResult] of dependencyResults) {
|
|
7569
8401
|
if (forEachParents.includes(depName)) {
|
|
7570
8402
|
const depForEachResult = depResult;
|
|
7571
|
-
if (Array.isArray(depForEachResult.
|
|
8403
|
+
if (Array.isArray(depForEachResult.forEachItemResults) && depForEachResult.forEachItemResults[itemIndex]) {
|
|
8404
|
+
forEachDependencyResults.set(
|
|
8405
|
+
depName,
|
|
8406
|
+
depForEachResult.forEachItemResults[itemIndex]
|
|
8407
|
+
);
|
|
8408
|
+
const rawResult = {
|
|
8409
|
+
issues: [],
|
|
8410
|
+
output: depForEachResult.output
|
|
8411
|
+
};
|
|
8412
|
+
forEachDependencyResults.set(`${depName}-raw`, rawResult);
|
|
8413
|
+
} else if (Array.isArray(depForEachResult.output) && depForEachResult.output[itemIndex] !== void 0) {
|
|
7572
8414
|
const modifiedResult = {
|
|
7573
8415
|
issues: [],
|
|
7574
8416
|
output: depForEachResult.output[itemIndex]
|
|
@@ -7586,6 +8428,46 @@ ${expr}
|
|
|
7586
8428
|
forEachDependencyResults.set(depName, depResult);
|
|
7587
8429
|
}
|
|
7588
8430
|
}
|
|
8431
|
+
if ((checkConfig.depends_on || []).length > 0) {
|
|
8432
|
+
const directDeps2 = checkConfig.depends_on || [];
|
|
8433
|
+
for (const depId of directDeps2) {
|
|
8434
|
+
if (!forEachParents.includes(depId)) continue;
|
|
8435
|
+
const depItemRes = forEachDependencyResults.get(depId);
|
|
8436
|
+
if (!depItemRes) continue;
|
|
8437
|
+
const wasSkippedDep = (depItemRes.issues || []).some(
|
|
8438
|
+
(i) => (i.ruleId || "").endsWith("/__skipped")
|
|
8439
|
+
);
|
|
8440
|
+
let hasFatalDepFailure = (depItemRes.issues || []).some((issue) => {
|
|
8441
|
+
const id = issue.ruleId || "";
|
|
8442
|
+
return id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/timeout" || id.endsWith("/command/timeout") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id.endsWith("/forEach/iteration_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output") || id.endsWith("_fail_if") || id.endsWith("/global_fail_if");
|
|
8443
|
+
});
|
|
8444
|
+
if (!hasFatalDepFailure && config && (config.fail_if || config.checks[depId]?.fail_if)) {
|
|
8445
|
+
try {
|
|
8446
|
+
const depFailures = await this.evaluateFailureConditions(
|
|
8447
|
+
depId,
|
|
8448
|
+
depItemRes,
|
|
8449
|
+
config
|
|
8450
|
+
);
|
|
8451
|
+
hasFatalDepFailure = depFailures.some((f) => f.failed);
|
|
8452
|
+
} catch {
|
|
8453
|
+
}
|
|
8454
|
+
}
|
|
8455
|
+
const depAgg = dependencyResults.get(depId);
|
|
8456
|
+
const maskFatal = !!depAgg?.forEachFatalMask && depAgg.forEachFatalMask[itemIndex] === true;
|
|
8457
|
+
if (wasSkippedDep || hasFatalDepFailure || maskFatal) {
|
|
8458
|
+
if (debug) {
|
|
8459
|
+
log2(
|
|
8460
|
+
`\u{1F504} Debug: Skipping item ${itemIndex + 1}/${forEachItems.length} for check "${checkName}" due to failed dependency '${depId}'`
|
|
8461
|
+
);
|
|
8462
|
+
}
|
|
8463
|
+
return {
|
|
8464
|
+
index: itemIndex,
|
|
8465
|
+
itemResult: { issues: [] },
|
|
8466
|
+
skipped: true
|
|
8467
|
+
};
|
|
8468
|
+
}
|
|
8469
|
+
}
|
|
8470
|
+
}
|
|
7589
8471
|
if (checkConfig.if) {
|
|
7590
8472
|
const conditionResults = new Map(results);
|
|
7591
8473
|
for (const [depName, depResult] of forEachDependencyResults) {
|
|
@@ -7636,6 +8518,24 @@ ${expr}
|
|
|
7636
8518
|
parent: forEachParentName
|
|
7637
8519
|
}
|
|
7638
8520
|
);
|
|
8521
|
+
if (config && (config.fail_if || checkConfig.fail_if)) {
|
|
8522
|
+
const itemFailures = await this.evaluateFailureConditions(
|
|
8523
|
+
checkName,
|
|
8524
|
+
itemResult,
|
|
8525
|
+
config
|
|
8526
|
+
);
|
|
8527
|
+
if (itemFailures.length > 0) {
|
|
8528
|
+
const failureIssues = itemFailures.filter((f) => f.failed).map((f) => ({
|
|
8529
|
+
file: "system",
|
|
8530
|
+
line: 0,
|
|
8531
|
+
ruleId: f.conditionName,
|
|
8532
|
+
message: f.message || `Failure condition met: ${f.expression}`,
|
|
8533
|
+
severity: f.severity || "error",
|
|
8534
|
+
category: "logic"
|
|
8535
|
+
}));
|
|
8536
|
+
itemResult.issues = [...itemResult.issues || [], ...failureIssues];
|
|
8537
|
+
}
|
|
8538
|
+
}
|
|
7639
8539
|
const hadFatalError = (itemResult.issues || []).some((issue) => {
|
|
7640
8540
|
const id = issue.ruleId || "";
|
|
7641
8541
|
return id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output");
|
|
@@ -7649,25 +8549,286 @@ ${expr}
|
|
|
7649
8549
|
itemResult.issues || [],
|
|
7650
8550
|
itemResult.output
|
|
7651
8551
|
);
|
|
8552
|
+
const descendantSet = (() => {
|
|
8553
|
+
const visited = /* @__PURE__ */ new Set();
|
|
8554
|
+
const stack = [checkName];
|
|
8555
|
+
while (stack.length) {
|
|
8556
|
+
const p = stack.pop();
|
|
8557
|
+
const kids = childrenByParent.get(p) || [];
|
|
8558
|
+
for (const k of kids) {
|
|
8559
|
+
if (!visited.has(k)) {
|
|
8560
|
+
visited.add(k);
|
|
8561
|
+
stack.push(k);
|
|
8562
|
+
}
|
|
8563
|
+
}
|
|
8564
|
+
}
|
|
8565
|
+
return visited;
|
|
8566
|
+
})();
|
|
8567
|
+
const perItemDone = /* @__PURE__ */ new Set([...forEachParents, checkName]);
|
|
8568
|
+
const perItemDepMap = /* @__PURE__ */ new Map();
|
|
8569
|
+
for (const [k, v] of forEachDependencyResults) perItemDepMap.set(k, v);
|
|
8570
|
+
perItemDepMap.set(checkName, itemResult);
|
|
8571
|
+
const isFatal = (r) => {
|
|
8572
|
+
if (!r) return true;
|
|
8573
|
+
return this.hasFatal(r.issues || []);
|
|
8574
|
+
};
|
|
8575
|
+
while (true) {
|
|
8576
|
+
let progressed = false;
|
|
8577
|
+
for (const node of descendantSet) {
|
|
8578
|
+
if (perItemDone.has(node)) continue;
|
|
8579
|
+
const nodeCfg = config.checks[node];
|
|
8580
|
+
if (!nodeCfg) continue;
|
|
8581
|
+
const deps = dependencies[node] || [];
|
|
8582
|
+
let ready = true;
|
|
8583
|
+
const childDepsMap = /* @__PURE__ */ new Map();
|
|
8584
|
+
for (const d of deps) {
|
|
8585
|
+
const perItemRes = perItemDepMap.get(d);
|
|
8586
|
+
if (perItemRes) {
|
|
8587
|
+
if (isFatal(perItemRes)) {
|
|
8588
|
+
ready = false;
|
|
8589
|
+
break;
|
|
8590
|
+
}
|
|
8591
|
+
childDepsMap.set(d, perItemRes);
|
|
8592
|
+
continue;
|
|
8593
|
+
}
|
|
8594
|
+
const agg2 = results.get(d);
|
|
8595
|
+
if (agg2 && (agg2.isForEach || Array.isArray(agg2.forEachItemResults))) {
|
|
8596
|
+
const r = agg2.forEachItemResults && agg2.forEachItemResults[itemIndex] || void 0;
|
|
8597
|
+
const maskFatal = !!agg2.forEachFatalMask && agg2.forEachFatalMask[itemIndex] === true;
|
|
8598
|
+
if (!r || maskFatal || isFatal(r)) {
|
|
8599
|
+
ready = false;
|
|
8600
|
+
break;
|
|
8601
|
+
}
|
|
8602
|
+
childDepsMap.set(d, r);
|
|
8603
|
+
continue;
|
|
8604
|
+
}
|
|
8605
|
+
if (!agg2 || isFatal(agg2)) {
|
|
8606
|
+
ready = false;
|
|
8607
|
+
break;
|
|
8608
|
+
}
|
|
8609
|
+
childDepsMap.set(d, agg2);
|
|
8610
|
+
}
|
|
8611
|
+
if (!ready) continue;
|
|
8612
|
+
if (nodeCfg.if) {
|
|
8613
|
+
const condResults = new Map(results);
|
|
8614
|
+
for (const [k, v] of childDepsMap) condResults.set(k, v);
|
|
8615
|
+
const shouldRun = await this.evaluateCheckCondition(
|
|
8616
|
+
node,
|
|
8617
|
+
nodeCfg.if,
|
|
8618
|
+
prInfo,
|
|
8619
|
+
condResults,
|
|
8620
|
+
debug
|
|
8621
|
+
);
|
|
8622
|
+
if (!shouldRun) {
|
|
8623
|
+
perItemDone.add(node);
|
|
8624
|
+
progressed = true;
|
|
8625
|
+
continue;
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
const nodeProvType = nodeCfg.type || "ai";
|
|
8629
|
+
const nodeProv = this.providerRegistry.getProviderOrThrow(nodeProvType);
|
|
8630
|
+
this.setProviderWebhookContext(nodeProv);
|
|
8631
|
+
const nodeProviderConfig = {
|
|
8632
|
+
type: nodeProvType,
|
|
8633
|
+
prompt: nodeCfg.prompt,
|
|
8634
|
+
exec: nodeCfg.exec,
|
|
8635
|
+
focus: nodeCfg.focus || this.mapCheckNameToFocus(node),
|
|
8636
|
+
schema: nodeCfg.schema,
|
|
8637
|
+
group: nodeCfg.group,
|
|
8638
|
+
checkName: node,
|
|
8639
|
+
eventContext: prInfo.eventContext,
|
|
8640
|
+
transform: nodeCfg.transform,
|
|
8641
|
+
transform_js: nodeCfg.transform_js,
|
|
8642
|
+
env: nodeCfg.env,
|
|
8643
|
+
forEach: nodeCfg.forEach,
|
|
8644
|
+
ai: { timeout: timeout || 6e5, debug, ...nodeCfg.ai || {} }
|
|
8645
|
+
};
|
|
8646
|
+
const iterStart = this.recordIterationStart(node);
|
|
8647
|
+
const execDepMap = new Map(childDepsMap);
|
|
8648
|
+
const nodeAllDeps = DependencyResolver.getAllDependencies(
|
|
8649
|
+
node,
|
|
8650
|
+
dependencyGraph.nodes
|
|
8651
|
+
);
|
|
8652
|
+
for (const dep of nodeAllDeps) {
|
|
8653
|
+
if (execDepMap.has(dep)) continue;
|
|
8654
|
+
const perItemRes = perItemDepMap.get(dep);
|
|
8655
|
+
if (perItemRes) {
|
|
8656
|
+
execDepMap.set(dep, perItemRes);
|
|
8657
|
+
continue;
|
|
8658
|
+
}
|
|
8659
|
+
const agg2 = results.get(dep);
|
|
8660
|
+
if (!agg2) continue;
|
|
8661
|
+
if (agg2 && (agg2.isForEach || Array.isArray(agg2.forEachItemResults) || Array.isArray(agg2.output))) {
|
|
8662
|
+
if (Array.isArray(agg2.forEachItemResults) && agg2.forEachItemResults[itemIndex]) {
|
|
8663
|
+
execDepMap.set(dep, agg2.forEachItemResults[itemIndex]);
|
|
8664
|
+
} else if (Array.isArray(agg2.output) && agg2.output[itemIndex] !== void 0) {
|
|
8665
|
+
execDepMap.set(dep, {
|
|
8666
|
+
issues: [],
|
|
8667
|
+
output: agg2.output[itemIndex]
|
|
8668
|
+
});
|
|
8669
|
+
} else {
|
|
8670
|
+
execDepMap.set(dep, agg2);
|
|
8671
|
+
}
|
|
8672
|
+
} else {
|
|
8673
|
+
execDepMap.set(dep, agg2);
|
|
8674
|
+
}
|
|
8675
|
+
}
|
|
8676
|
+
const nodeItemRes = await this.executeWithRouting(
|
|
8677
|
+
node,
|
|
8678
|
+
nodeCfg,
|
|
8679
|
+
nodeProv,
|
|
8680
|
+
nodeProviderConfig,
|
|
8681
|
+
prInfo,
|
|
8682
|
+
execDepMap,
|
|
8683
|
+
sessionInfo,
|
|
8684
|
+
config,
|
|
8685
|
+
dependencyGraph,
|
|
8686
|
+
debug,
|
|
8687
|
+
results,
|
|
8688
|
+
{ index: itemIndex, total: forEachItems.length, parent: forEachParentName }
|
|
8689
|
+
);
|
|
8690
|
+
if (config && (config.fail_if || nodeCfg.fail_if)) {
|
|
8691
|
+
const fRes = await this.evaluateFailureConditions(node, nodeItemRes, config);
|
|
8692
|
+
if (fRes.length > 0) {
|
|
8693
|
+
const fIssues = fRes.filter((f) => f.failed).map((f) => ({
|
|
8694
|
+
file: "system",
|
|
8695
|
+
line: 0,
|
|
8696
|
+
ruleId: f.conditionName,
|
|
8697
|
+
message: f.message || `Failure condition met: ${f.expression}`,
|
|
8698
|
+
severity: f.severity || "error",
|
|
8699
|
+
category: "logic"
|
|
8700
|
+
}));
|
|
8701
|
+
nodeItemRes.issues = [...nodeItemRes.issues || [], ...fIssues];
|
|
8702
|
+
}
|
|
8703
|
+
}
|
|
8704
|
+
const hadFatal = isFatal(nodeItemRes);
|
|
8705
|
+
this.recordIterationComplete(
|
|
8706
|
+
node,
|
|
8707
|
+
iterStart,
|
|
8708
|
+
!hadFatal,
|
|
8709
|
+
nodeItemRes.issues || [],
|
|
8710
|
+
nodeItemRes.output
|
|
8711
|
+
);
|
|
8712
|
+
if (!inlineAgg.has(node))
|
|
8713
|
+
inlineAgg.set(node, {
|
|
8714
|
+
issues: [],
|
|
8715
|
+
outputs: [],
|
|
8716
|
+
contents: [],
|
|
8717
|
+
perItemResults: []
|
|
8718
|
+
});
|
|
8719
|
+
const agg = inlineAgg.get(node);
|
|
8720
|
+
if (nodeItemRes.issues) agg.issues.push(...nodeItemRes.issues);
|
|
8721
|
+
const nout = nodeItemRes.output;
|
|
8722
|
+
if (nout !== void 0) agg.outputs.push(nout);
|
|
8723
|
+
agg.perItemResults.push(nodeItemRes);
|
|
8724
|
+
const ncontent = nodeItemRes.content;
|
|
8725
|
+
if (typeof ncontent === "string" && ncontent.trim())
|
|
8726
|
+
agg.contents.push(ncontent.trim());
|
|
8727
|
+
perItemDepMap.set(node, nodeItemRes);
|
|
8728
|
+
perItemDone.add(node);
|
|
8729
|
+
progressed = true;
|
|
8730
|
+
}
|
|
8731
|
+
if (!progressed) break;
|
|
8732
|
+
}
|
|
7652
8733
|
logger.info(
|
|
7653
8734
|
` \u2714 ${itemIndex + 1}/${forEachItems.length} (${iterationDuration.toFixed(1)}s)`
|
|
7654
8735
|
);
|
|
8736
|
+
perItemResults[itemIndex] = itemResult;
|
|
7655
8737
|
return { index: itemIndex, itemResult };
|
|
7656
8738
|
});
|
|
8739
|
+
const directForEachParents = (checkConfig.depends_on || []).filter((dep) => {
|
|
8740
|
+
const r = results.get(dep);
|
|
8741
|
+
return !!r && (r.isForEach || Array.isArray(r.forEachItemResults) || Array.isArray(r.forEachItems));
|
|
8742
|
+
});
|
|
8743
|
+
if (directForEachParents.length > 0) {
|
|
8744
|
+
logger.debug(
|
|
8745
|
+
` forEach: direct parents for "${checkName}": ${directForEachParents.join(", ")}`
|
|
8746
|
+
);
|
|
8747
|
+
}
|
|
8748
|
+
const isIndexFatalForParent = async (parent, idx) => {
|
|
8749
|
+
const agg = results.get(parent);
|
|
8750
|
+
if (!agg) return false;
|
|
8751
|
+
if (agg.forEachFatalMask && agg.forEachFatalMask[idx] === true) return true;
|
|
8752
|
+
const r = agg.forEachItemResults && agg.forEachItemResults[idx] || void 0;
|
|
8753
|
+
if (!r) return false;
|
|
8754
|
+
const hadFatalByIssues = this.hasFatal(r.issues || []);
|
|
8755
|
+
if (hadFatalByIssues) return true;
|
|
8756
|
+
try {
|
|
8757
|
+
if (config && (config.fail_if || config.checks[parent]?.fail_if)) {
|
|
8758
|
+
let rForEval = r;
|
|
8759
|
+
const rawOut = r?.output;
|
|
8760
|
+
if (typeof rawOut === "string") {
|
|
8761
|
+
const parseTail = (text) => {
|
|
8762
|
+
try {
|
|
8763
|
+
const lines = text.split("\n");
|
|
8764
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
8765
|
+
const t = lines[i].trim();
|
|
8766
|
+
if (t.startsWith("{") || t.startsWith("[")) {
|
|
8767
|
+
const candidate = lines.slice(i).join("\n").trim();
|
|
8768
|
+
if (candidate.startsWith("{") && candidate.endsWith("}") || candidate.startsWith("[") && candidate.endsWith("]")) {
|
|
8769
|
+
return JSON.parse(candidate);
|
|
8770
|
+
}
|
|
8771
|
+
}
|
|
8772
|
+
}
|
|
8773
|
+
} catch {
|
|
8774
|
+
}
|
|
8775
|
+
try {
|
|
8776
|
+
return JSON.parse(text);
|
|
8777
|
+
} catch {
|
|
8778
|
+
return null;
|
|
8779
|
+
}
|
|
8780
|
+
};
|
|
8781
|
+
const parsed = parseTail(rawOut);
|
|
8782
|
+
if (parsed && typeof parsed === "object") {
|
|
8783
|
+
rForEval = { ...r, output: parsed };
|
|
8784
|
+
}
|
|
8785
|
+
}
|
|
8786
|
+
const failures = await this.evaluateFailureConditions(parent, rForEval, config);
|
|
8787
|
+
if (failures.some((f) => f.failed)) {
|
|
8788
|
+
}
|
|
8789
|
+
if (failures.some((f) => f.failed)) return true;
|
|
8790
|
+
}
|
|
8791
|
+
} catch {
|
|
8792
|
+
}
|
|
8793
|
+
return false;
|
|
8794
|
+
};
|
|
8795
|
+
const runnableIndices = [];
|
|
8796
|
+
for (let idx = 0; idx < forEachItems.length; idx++) {
|
|
8797
|
+
let ok = true;
|
|
8798
|
+
for (const p of directForEachParents) {
|
|
8799
|
+
if (await isIndexFatalForParent(p, idx)) {
|
|
8800
|
+
ok = false;
|
|
8801
|
+
break;
|
|
8802
|
+
}
|
|
8803
|
+
}
|
|
8804
|
+
if (ok && typeof itemTasks[idx] === "function") runnableIndices.push(idx);
|
|
8805
|
+
}
|
|
8806
|
+
if (runnableIndices.length === 0) {
|
|
8807
|
+
this.recordSkip(checkName, "dependency_failed");
|
|
8808
|
+
logger.info(`\u23ED Skipped (dependency failed: no runnable items)`);
|
|
8809
|
+
return {
|
|
8810
|
+
checkName,
|
|
8811
|
+
error: null,
|
|
8812
|
+
result: { issues: [] },
|
|
8813
|
+
skipped: true
|
|
8814
|
+
};
|
|
8815
|
+
}
|
|
7657
8816
|
const forEachConcurrency = Math.max(
|
|
7658
8817
|
1,
|
|
7659
|
-
Math.min(
|
|
8818
|
+
Math.min(runnableIndices.length, effectiveMaxParallelism)
|
|
7660
8819
|
);
|
|
7661
8820
|
if (debug && forEachConcurrency > 1) {
|
|
7662
8821
|
log2(
|
|
7663
8822
|
`\u{1F504} Debug: Limiting forEach concurrency for check "${checkName}" to ${forEachConcurrency}`
|
|
7664
8823
|
);
|
|
7665
8824
|
}
|
|
8825
|
+
const scheduledTasks = runnableIndices.map((i) => itemTasks[i]).filter((fn) => typeof fn === "function");
|
|
7666
8826
|
const forEachResults = await this.executeWithLimitedParallelism(
|
|
7667
|
-
|
|
8827
|
+
scheduledTasks,
|
|
7668
8828
|
forEachConcurrency,
|
|
7669
8829
|
false
|
|
7670
8830
|
);
|
|
8831
|
+
let processedCount = 0;
|
|
7671
8832
|
for (const result of forEachResults) {
|
|
7672
8833
|
if (result.status === "rejected") {
|
|
7673
8834
|
const error = result.reason;
|
|
@@ -7690,52 +8851,117 @@ ${expr}
|
|
|
7690
8851
|
if (result.value.skipped) {
|
|
7691
8852
|
continue;
|
|
7692
8853
|
}
|
|
7693
|
-
const { itemResult } = result.value;
|
|
8854
|
+
const { index: finishedIndex, itemResult } = result.value;
|
|
8855
|
+
processedCount++;
|
|
7694
8856
|
if (itemResult.issues) {
|
|
7695
8857
|
allIssues.push(...itemResult.issues);
|
|
7696
8858
|
}
|
|
7697
8859
|
const resultWithOutput = itemResult;
|
|
7698
|
-
|
|
7699
|
-
allOutputs.push(resultWithOutput.output);
|
|
7700
|
-
}
|
|
8860
|
+
allOutputs[finishedIndex] = resultWithOutput.output;
|
|
7701
8861
|
const itemContent = resultWithOutput.content;
|
|
7702
8862
|
if (typeof itemContent === "string" && itemContent.trim()) {
|
|
7703
8863
|
aggregatedContents.push(itemContent.trim());
|
|
8864
|
+
} else {
|
|
8865
|
+
const outStr = typeof resultWithOutput.output === "string" ? resultWithOutput.output.trim() : "";
|
|
8866
|
+
if (outStr) aggregatedContents.push(outStr);
|
|
7704
8867
|
}
|
|
7705
8868
|
}
|
|
8869
|
+
if (processedCount === 0) {
|
|
8870
|
+
this.recordSkip(checkName, "dependency_failed");
|
|
8871
|
+
logger.info(`\u23ED Skipped (dependency failed for all items)`);
|
|
8872
|
+
return {
|
|
8873
|
+
checkName,
|
|
8874
|
+
error: null,
|
|
8875
|
+
result: { issues: [] },
|
|
8876
|
+
skipped: true
|
|
8877
|
+
};
|
|
8878
|
+
}
|
|
7706
8879
|
const finalOutput = allOutputs.length > 0 ? allOutputs : void 0;
|
|
7707
8880
|
finalResult = {
|
|
7708
8881
|
issues: allIssues,
|
|
7709
8882
|
...finalOutput !== void 0 ? { output: finalOutput } : {}
|
|
7710
8883
|
};
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
8884
|
+
finalResult.isForEach = true;
|
|
8885
|
+
finalResult.forEachItems = allOutputs;
|
|
8886
|
+
finalResult.forEachItemResults = perItemResults;
|
|
8887
|
+
try {
|
|
8888
|
+
const mask = finalResult.forEachItemResults ? await Promise.all(
|
|
8889
|
+
Array.from({ length: forEachItems.length }, async (_, idx) => {
|
|
8890
|
+
const r = finalResult.forEachItemResults[idx];
|
|
8891
|
+
if (!r) return false;
|
|
8892
|
+
let hadFatal = this.hasFatal(r.issues || []);
|
|
8893
|
+
try {
|
|
8894
|
+
const ids = (r.issues || []).map((i) => i.ruleId).join(",");
|
|
8895
|
+
logger.debug(
|
|
8896
|
+
` forEach: item ${idx + 1}/${forEachItems.length} issues=${(r.issues || []).length} ids=[${ids}]`
|
|
8897
|
+
);
|
|
8898
|
+
} catch {
|
|
8899
|
+
}
|
|
8900
|
+
if (!hadFatal && config && (config.fail_if || checkConfig.fail_if)) {
|
|
8901
|
+
try {
|
|
8902
|
+
const failures = await this.evaluateFailureConditions(
|
|
8903
|
+
checkName,
|
|
8904
|
+
r,
|
|
8905
|
+
config
|
|
8906
|
+
);
|
|
8907
|
+
hadFatal = failures.some((f) => f.failed);
|
|
8908
|
+
} catch {
|
|
8909
|
+
}
|
|
8910
|
+
}
|
|
8911
|
+
return hadFatal;
|
|
8912
|
+
})
|
|
8913
|
+
) : [];
|
|
8914
|
+
finalResult.forEachFatalMask = mask;
|
|
8915
|
+
logger.debug(
|
|
8916
|
+
` forEach: mask for "${checkName}" \u2192 fatals=${mask.filter(Boolean).length}/${mask.length}`
|
|
7716
8917
|
);
|
|
7717
|
-
|
|
7718
|
-
const failureIssues = failureResults.filter((f) => f.failed).map((f) => ({
|
|
7719
|
-
file: "system",
|
|
7720
|
-
line: 0,
|
|
7721
|
-
ruleId: f.conditionName,
|
|
7722
|
-
message: f.message || `Failure condition met: ${f.expression}`,
|
|
7723
|
-
severity: f.severity || "error",
|
|
7724
|
-
category: "logic"
|
|
7725
|
-
}));
|
|
7726
|
-
finalResult.issues = [...finalResult.issues || [], ...failureIssues];
|
|
7727
|
-
}
|
|
7728
|
-
}
|
|
7729
|
-
if (allOutputs.length > 0) {
|
|
7730
|
-
finalResult.isForEach = true;
|
|
7731
|
-
finalResult.forEachItems = allOutputs;
|
|
8918
|
+
} catch {
|
|
7732
8919
|
}
|
|
7733
8920
|
if (aggregatedContents.length > 0) {
|
|
7734
8921
|
finalResult.content = aggregatedContents.join("\n");
|
|
7735
8922
|
}
|
|
7736
|
-
|
|
7737
|
-
|
|
7738
|
-
|
|
8923
|
+
for (const [childName, agg] of inlineAgg.entries()) {
|
|
8924
|
+
const childCfg = config.checks[childName];
|
|
8925
|
+
const childEnrichedIssues = (agg.issues || []).map((issue) => ({
|
|
8926
|
+
...issue,
|
|
8927
|
+
checkName: childName,
|
|
8928
|
+
ruleId: `${childName}/${issue.ruleId}`,
|
|
8929
|
+
group: childCfg.group,
|
|
8930
|
+
schema: typeof childCfg.schema === "object" ? "custom" : childCfg.schema,
|
|
8931
|
+
template: childCfg.template,
|
|
8932
|
+
timestamp: Date.now()
|
|
8933
|
+
}));
|
|
8934
|
+
const childFinal = {
|
|
8935
|
+
issues: childEnrichedIssues,
|
|
8936
|
+
...agg.outputs.length > 0 ? { output: agg.outputs } : {},
|
|
8937
|
+
isForEach: true,
|
|
8938
|
+
forEachItems: agg.outputs,
|
|
8939
|
+
forEachItemResults: agg.perItemResults,
|
|
8940
|
+
...agg.contents.length > 0 ? { content: agg.contents.join("\n") } : {}
|
|
8941
|
+
};
|
|
8942
|
+
try {
|
|
8943
|
+
const mask = Array.from(
|
|
8944
|
+
{ length: agg.perItemResults.length },
|
|
8945
|
+
(_, idx) => {
|
|
8946
|
+
const r = agg.perItemResults[idx];
|
|
8947
|
+
if (!r) return false;
|
|
8948
|
+
const hadFatal = (r.issues || []).some((issue) => {
|
|
8949
|
+
const id = issue.ruleId || "";
|
|
8950
|
+
return issue.severity === "error" || issue.severity === "critical" || id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/timeout" || id.endsWith("/command/timeout") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id.endsWith("/forEach/iteration_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output") || id.endsWith("_fail_if") || id.endsWith("/global_fail_if");
|
|
8951
|
+
});
|
|
8952
|
+
return hadFatal;
|
|
8953
|
+
}
|
|
8954
|
+
);
|
|
8955
|
+
childFinal.forEachFatalMask = mask;
|
|
8956
|
+
} catch {
|
|
8957
|
+
}
|
|
8958
|
+
results.set(childName, childFinal);
|
|
8959
|
+
}
|
|
8960
|
+
if (debug && process.env.VISOR_OUTPUT_FORMAT !== "json" && process.env.VISOR_OUTPUT_FORMAT !== "sarif") {
|
|
8961
|
+
console.log(
|
|
8962
|
+
`\u{1F504} Debug: Completed forEach execution for check "${checkName}", total issues: ${allIssues.length}`
|
|
8963
|
+
);
|
|
8964
|
+
}
|
|
7739
8965
|
}
|
|
7740
8966
|
} else {
|
|
7741
8967
|
if (checkConfig.if) {
|
|
@@ -7865,7 +9091,8 @@ ${expr}
|
|
|
7865
9091
|
result: enrichedResult
|
|
7866
9092
|
};
|
|
7867
9093
|
} catch (error) {
|
|
7868
|
-
const errorMessage = error instanceof Error ? error.message
|
|
9094
|
+
const errorMessage = error instanceof Error ? `${error.message}
|
|
9095
|
+
${error.stack || ""}` : String(error);
|
|
7869
9096
|
const checkDuration = ((Date.now() - checkStartTime) / 1e3).toFixed(1);
|
|
7870
9097
|
this.recordError(checkName, error instanceof Error ? error : new Error(String(error)));
|
|
7871
9098
|
this.recordIterationComplete(checkName, checkStartTime, false, [], void 0);
|
|
@@ -7885,8 +9112,9 @@ ${expr}
|
|
|
7885
9112
|
actualParallelism,
|
|
7886
9113
|
effectiveFailFast
|
|
7887
9114
|
);
|
|
9115
|
+
const levelChecksList = executionGroup.parallel.filter((name) => !results.has(name));
|
|
7888
9116
|
for (let i = 0; i < levelResults.length; i++) {
|
|
7889
|
-
const checkName =
|
|
9117
|
+
const checkName = levelChecksList[i];
|
|
7890
9118
|
const result = levelResults[i];
|
|
7891
9119
|
const checkConfig = config.checks[checkName];
|
|
7892
9120
|
if (result.status === "fulfilled" && result.value.result && !result.value.error) {
|
|
@@ -9020,9 +10248,22 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
9020
10248
|
*/
|
|
9021
10249
|
recordForEachPreview(checkName, items) {
|
|
9022
10250
|
const stats = this.executionStats.get(checkName);
|
|
9023
|
-
if (!stats
|
|
10251
|
+
if (!stats) return;
|
|
10252
|
+
if (!Array.isArray(items) || items.length === 0) return;
|
|
9024
10253
|
const preview = items.slice(0, 3).map((item) => {
|
|
9025
|
-
|
|
10254
|
+
let str;
|
|
10255
|
+
if (typeof item === "string") {
|
|
10256
|
+
str = item;
|
|
10257
|
+
} else if (item === void 0 || item === null) {
|
|
10258
|
+
str = "(empty)";
|
|
10259
|
+
} else {
|
|
10260
|
+
try {
|
|
10261
|
+
const j = JSON.stringify(item);
|
|
10262
|
+
str = typeof j === "string" ? j : String(item);
|
|
10263
|
+
} catch {
|
|
10264
|
+
str = String(item);
|
|
10265
|
+
}
|
|
10266
|
+
}
|
|
9026
10267
|
return str.length > 50 ? str.substring(0, 47) + "..." : str;
|
|
9027
10268
|
});
|
|
9028
10269
|
if (items.length > 3) {
|
|
@@ -9058,6 +10299,20 @@ ${result.value.result.debug.rawResponse}`;
|
|
|
9058
10299
|
checks
|
|
9059
10300
|
};
|
|
9060
10301
|
}
|
|
10302
|
+
// Generic fatality helpers to avoid duplication
|
|
10303
|
+
isFatalRule(id, severity) {
|
|
10304
|
+
const sev = (severity || "").toLowerCase();
|
|
10305
|
+
return sev === "error" || sev === "critical" || id === "command/execution_error" || id.endsWith("/command/execution_error") || id === "command/timeout" || id.endsWith("/command/timeout") || id === "command/transform_js_error" || id.endsWith("/command/transform_js_error") || id === "command/transform_error" || id.endsWith("/command/transform_error") || id.endsWith("/forEach/iteration_error") || id === "forEach/undefined_output" || id.endsWith("/forEach/undefined_output") || id.endsWith("_fail_if") || id.endsWith("/global_fail_if");
|
|
10306
|
+
}
|
|
10307
|
+
hasFatal(issues) {
|
|
10308
|
+
if (!issues || issues.length === 0) return false;
|
|
10309
|
+
return issues.some((i) => this.isFatalRule(i.ruleId || "", i.severity));
|
|
10310
|
+
}
|
|
10311
|
+
async failIfTriggered(checkName, result, config) {
|
|
10312
|
+
if (!config) return false;
|
|
10313
|
+
const failures = await this.evaluateFailureConditions(checkName, result, config);
|
|
10314
|
+
return failures.some((f) => f.failed);
|
|
10315
|
+
}
|
|
9061
10316
|
/**
|
|
9062
10317
|
* Truncate a string to max length with ellipsis
|
|
9063
10318
|
*/
|