@probelabs/visor 0.1.82 → 0.1.84
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/defaults/.visor.yaml +4 -4
- package/dist/check-execution-engine.d.ts +5 -0
- package/dist/check-execution-engine.d.ts.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/defaults/.visor.yaml +4 -4
- package/dist/failure-condition-evaluator.d.ts.map +1 -1
- package/dist/generated/config-schema.d.ts +6 -2
- package/dist/generated/config-schema.d.ts.map +1 -1
- package/dist/generated/config-schema.json +9 -2
- package/dist/index.js +39774 -36632
- package/dist/output/code-review/schema.json +2 -2
- package/dist/providers/command-check-provider.d.ts.map +1 -1
- package/dist/sdk/{check-execution-engine-PO5XKTHP.mjs → check-execution-engine-X7VCV6KI.mjs} +2 -2
- package/dist/sdk/{chunk-G24UL45Z.mjs → chunk-Q55L5EPS.mjs} +150 -29
- package/dist/sdk/chunk-Q55L5EPS.mjs.map +1 -0
- package/dist/sdk/sdk.d.mts +4 -2
- package/dist/sdk/sdk.d.ts +4 -2
- package/dist/sdk/sdk.js +169 -33
- package/dist/sdk/sdk.js.map +1 -1
- package/dist/sdk/sdk.mjs +22 -7
- package/dist/sdk/sdk.mjs.map +1 -1
- package/dist/types/config.d.ts +4 -2
- package/dist/types/config.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/sdk/chunk-G24UL45Z.mjs.map +0 -1
- /package/dist/sdk/{check-execution-engine-PO5XKTHP.mjs.map → check-execution-engine-X7VCV6KI.mjs.map} +0 -0
package/dist/sdk/sdk.d.mts
CHANGED
|
@@ -248,6 +248,8 @@ interface CheckConfig {
|
|
|
248
248
|
claude_code?: ClaudeCodeConfig;
|
|
249
249
|
/** Environment variables for this check */
|
|
250
250
|
env?: EnvConfig;
|
|
251
|
+
/** Timeout in seconds for command execution (default: 60) */
|
|
252
|
+
timeout?: number;
|
|
251
253
|
/** Check IDs that this check depends on (optional) */
|
|
252
254
|
depends_on?: string[];
|
|
253
255
|
/** Group name for comment separation (e.g., "code-review", "pr-overview") - optional */
|
|
@@ -258,8 +260,8 @@ interface CheckConfig {
|
|
|
258
260
|
template?: CustomTemplateConfig;
|
|
259
261
|
/** Condition to determine if check should run - runs if expression evaluates to true */
|
|
260
262
|
if?: string;
|
|
261
|
-
/**
|
|
262
|
-
reuse_ai_session?: boolean;
|
|
263
|
+
/** Check name to reuse AI session from, or true to use first dependency (only works with depends_on) */
|
|
264
|
+
reuse_ai_session?: string | boolean;
|
|
263
265
|
/** Simple fail condition - fails check if expression evaluates to true */
|
|
264
266
|
fail_if?: string;
|
|
265
267
|
/** Check-specific failure conditions - optional (deprecated, use fail_if) */
|
package/dist/sdk/sdk.d.ts
CHANGED
|
@@ -248,6 +248,8 @@ interface CheckConfig {
|
|
|
248
248
|
claude_code?: ClaudeCodeConfig;
|
|
249
249
|
/** Environment variables for this check */
|
|
250
250
|
env?: EnvConfig;
|
|
251
|
+
/** Timeout in seconds for command execution (default: 60) */
|
|
252
|
+
timeout?: number;
|
|
251
253
|
/** Check IDs that this check depends on (optional) */
|
|
252
254
|
depends_on?: string[];
|
|
253
255
|
/** Group name for comment separation (e.g., "code-review", "pr-overview") - optional */
|
|
@@ -258,8 +260,8 @@ interface CheckConfig {
|
|
|
258
260
|
template?: CustomTemplateConfig;
|
|
259
261
|
/** Condition to determine if check should run - runs if expression evaluates to true */
|
|
260
262
|
if?: string;
|
|
261
|
-
/**
|
|
262
|
-
reuse_ai_session?: boolean;
|
|
263
|
+
/** Check name to reuse AI session from, or true to use first dependency (only works with depends_on) */
|
|
264
|
+
reuse_ai_session?: string | boolean;
|
|
263
265
|
/** Simple fail condition - fails check if expression evaluates to true */
|
|
264
266
|
fail_if?: string;
|
|
265
267
|
/** Check-specific failure conditions - optional (deprecated, use fail_if) */
|
package/dist/sdk/sdk.js
CHANGED
|
@@ -4127,6 +4127,7 @@ var init_command_check_provider = __esm({
|
|
|
4127
4127
|
try {
|
|
4128
4128
|
const parsed = JSON.parse(rawOutput);
|
|
4129
4129
|
output = parsed;
|
|
4130
|
+
logger.debug(`\u{1F527} Debug: Parsed entire output as JSON successfully`);
|
|
4130
4131
|
} catch {
|
|
4131
4132
|
const extracted2 = this.extractJsonFromEnd(rawOutput);
|
|
4132
4133
|
if (extracted2) {
|
|
@@ -4135,13 +4136,28 @@ var init_command_check_provider = __esm({
|
|
|
4135
4136
|
logger.debug(
|
|
4136
4137
|
`\u{1F527} Debug: Extracted and parsed JSON from end of output (${extracted2.length} chars from ${rawOutput.length} total)`
|
|
4137
4138
|
);
|
|
4138
|
-
|
|
4139
|
+
logger.debug(`\u{1F527} Debug: Extracted JSON content: ${extracted2.slice(0, 200)}`);
|
|
4140
|
+
} catch (parseError) {
|
|
4141
|
+
logger.debug(
|
|
4142
|
+
`\u{1F527} Debug: Extracted text is not valid JSON: ${parseError instanceof Error ? parseError.message : "Unknown error"}`
|
|
4143
|
+
);
|
|
4139
4144
|
output = rawOutput;
|
|
4140
4145
|
}
|
|
4141
4146
|
} else {
|
|
4147
|
+
logger.debug(`\u{1F527} Debug: No JSON found in output, keeping as string`);
|
|
4142
4148
|
output = rawOutput;
|
|
4143
4149
|
}
|
|
4144
4150
|
}
|
|
4151
|
+
if (output !== rawOutput) {
|
|
4152
|
+
try {
|
|
4153
|
+
const outputType = Array.isArray(output) ? `array[${output.length}]` : typeof output;
|
|
4154
|
+
logger.debug(`\u{1F527} Debug: Parsed output type: ${outputType}`);
|
|
4155
|
+
if (typeof output === "object" && output !== null) {
|
|
4156
|
+
logger.debug(`\u{1F527} Debug: Parsed output keys: ${Object.keys(output).join(", ")}`);
|
|
4157
|
+
}
|
|
4158
|
+
} catch {
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4145
4161
|
let finalOutput = output;
|
|
4146
4162
|
if (transform) {
|
|
4147
4163
|
try {
|
|
@@ -4316,6 +4332,16 @@ return ${returnTarget};
|
|
|
4316
4332
|
return result;
|
|
4317
4333
|
} catch (error) {
|
|
4318
4334
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
4335
|
+
let isTimeout = false;
|
|
4336
|
+
if (error && typeof error === "object") {
|
|
4337
|
+
const execError = error;
|
|
4338
|
+
if (execError.killed && execError.signal === "SIGTERM") {
|
|
4339
|
+
isTimeout = true;
|
|
4340
|
+
}
|
|
4341
|
+
if (execError.code === "ETIMEDOUT") {
|
|
4342
|
+
isTimeout = true;
|
|
4343
|
+
}
|
|
4344
|
+
}
|
|
4319
4345
|
let stderrOutput = "";
|
|
4320
4346
|
if (error && typeof error === "object") {
|
|
4321
4347
|
const execError = error;
|
|
@@ -4323,17 +4349,32 @@ return ${returnTarget};
|
|
|
4323
4349
|
stderrOutput = execError.stderr.trim();
|
|
4324
4350
|
}
|
|
4325
4351
|
}
|
|
4326
|
-
|
|
4352
|
+
let detailedMessage;
|
|
4353
|
+
let ruleId;
|
|
4354
|
+
if (isTimeout) {
|
|
4355
|
+
const timeoutSeconds = config.timeout || 60;
|
|
4356
|
+
detailedMessage = `Command execution timed out after ${timeoutSeconds} seconds`;
|
|
4357
|
+
if (stderrOutput) {
|
|
4358
|
+
detailedMessage += `
|
|
4359
|
+
|
|
4360
|
+
Stderr output:
|
|
4361
|
+
${stderrOutput}`;
|
|
4362
|
+
}
|
|
4363
|
+
ruleId = "command/timeout";
|
|
4364
|
+
} else {
|
|
4365
|
+
detailedMessage = stderrOutput ? `Command execution failed: ${errorMessage}
|
|
4327
4366
|
|
|
4328
4367
|
Stderr output:
|
|
4329
4368
|
${stderrOutput}` : `Command execution failed: ${errorMessage}`;
|
|
4369
|
+
ruleId = "command/execution_error";
|
|
4370
|
+
}
|
|
4330
4371
|
logger.error(`\u2717 ${detailedMessage}`);
|
|
4331
4372
|
return {
|
|
4332
4373
|
issues: [
|
|
4333
4374
|
{
|
|
4334
4375
|
file: "command",
|
|
4335
4376
|
line: 0,
|
|
4336
|
-
ruleId
|
|
4377
|
+
ruleId,
|
|
4337
4378
|
message: detailedMessage,
|
|
4338
4379
|
severity: "error",
|
|
4339
4380
|
category: "logic"
|
|
@@ -5411,6 +5452,14 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5411
5452
|
*/
|
|
5412
5453
|
buildEvaluationContext(checkName, checkSchema, checkGroup, reviewSummary, previousOutputs) {
|
|
5413
5454
|
const { issues, debug } = reviewSummary;
|
|
5455
|
+
const reviewSummaryWithOutput = reviewSummary;
|
|
5456
|
+
const {
|
|
5457
|
+
output: extractedOutput,
|
|
5458
|
+
// Exclude issues from otherFields since we handle it separately
|
|
5459
|
+
issues: _issues,
|
|
5460
|
+
// eslint-disable-line @typescript-eslint/no-unused-vars
|
|
5461
|
+
...otherFields
|
|
5462
|
+
} = reviewSummaryWithOutput;
|
|
5414
5463
|
const context = {
|
|
5415
5464
|
output: {
|
|
5416
5465
|
issues: (issues || []).map((issue) => ({
|
|
@@ -5427,9 +5476,9 @@ var init_failure_condition_evaluator = __esm({
|
|
|
5427
5476
|
replacement: issue.replacement
|
|
5428
5477
|
})),
|
|
5429
5478
|
// Include additional schema-specific data from reviewSummary
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5479
|
+
...otherFields,
|
|
5480
|
+
// Spread the extracted output directly (avoid output.output nesting)
|
|
5481
|
+
...extractedOutput && typeof extractedOutput === "object" ? extractedOutput : {}
|
|
5433
5482
|
},
|
|
5434
5483
|
outputs: (() => {
|
|
5435
5484
|
if (!previousOutputs) return {};
|
|
@@ -6869,6 +6918,31 @@ ${expr}
|
|
|
6869
6918
|
};
|
|
6870
6919
|
providerConfig.forEach = checkConfig.forEach;
|
|
6871
6920
|
const result = await provider.execute(prInfo, providerConfig);
|
|
6921
|
+
if (checkConfig.forEach && (!result.issues || result.issues.length === 0)) {
|
|
6922
|
+
const reviewSummaryWithOutput = result;
|
|
6923
|
+
const validation = this.validateAndNormalizeForEachOutput(
|
|
6924
|
+
checkName,
|
|
6925
|
+
reviewSummaryWithOutput.output,
|
|
6926
|
+
checkConfig.group
|
|
6927
|
+
);
|
|
6928
|
+
if (!validation.isValid) {
|
|
6929
|
+
return validation.error;
|
|
6930
|
+
}
|
|
6931
|
+
}
|
|
6932
|
+
if (config && (config.fail_if || checkConfig.fail_if)) {
|
|
6933
|
+
const failureResults = await this.evaluateFailureConditions(checkName, result, config);
|
|
6934
|
+
if (failureResults.length > 0) {
|
|
6935
|
+
const failureIssues = failureResults.filter((f) => f.failed).map((f) => ({
|
|
6936
|
+
file: "system",
|
|
6937
|
+
line: 0,
|
|
6938
|
+
ruleId: f.conditionName,
|
|
6939
|
+
message: f.message || `Failure condition met: ${f.expression}`,
|
|
6940
|
+
severity: f.severity || "error",
|
|
6941
|
+
category: "logic"
|
|
6942
|
+
}));
|
|
6943
|
+
result.issues = [...result.issues || [], ...failureIssues];
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6872
6946
|
const content = await this.renderCheckContent(checkName, result, checkConfig, prInfo);
|
|
6873
6947
|
return {
|
|
6874
6948
|
checkName,
|
|
@@ -6879,6 +6953,53 @@ ${expr}
|
|
|
6879
6953
|
// Include structured issues
|
|
6880
6954
|
};
|
|
6881
6955
|
}
|
|
6956
|
+
/**
|
|
6957
|
+
* Validate and normalize forEach output
|
|
6958
|
+
* Returns normalized array or throws validation error result
|
|
6959
|
+
*/
|
|
6960
|
+
validateAndNormalizeForEachOutput(checkName, output, checkGroup) {
|
|
6961
|
+
if (output === void 0) {
|
|
6962
|
+
logger.error(`\u2717 forEach check "${checkName}" produced undefined output`);
|
|
6963
|
+
return {
|
|
6964
|
+
isValid: false,
|
|
6965
|
+
error: {
|
|
6966
|
+
checkName,
|
|
6967
|
+
content: "",
|
|
6968
|
+
group: checkGroup || "default",
|
|
6969
|
+
issues: [
|
|
6970
|
+
{
|
|
6971
|
+
file: "system",
|
|
6972
|
+
line: 0,
|
|
6973
|
+
ruleId: "forEach/undefined_output",
|
|
6974
|
+
message: `forEach check "${checkName}" produced undefined output. Verify your command outputs valid data and your transform_js returns a value.`,
|
|
6975
|
+
severity: "error",
|
|
6976
|
+
category: "logic"
|
|
6977
|
+
}
|
|
6978
|
+
]
|
|
6979
|
+
}
|
|
6980
|
+
};
|
|
6981
|
+
}
|
|
6982
|
+
let normalizedOutput;
|
|
6983
|
+
if (Array.isArray(output)) {
|
|
6984
|
+
normalizedOutput = output;
|
|
6985
|
+
} else if (typeof output === "string") {
|
|
6986
|
+
try {
|
|
6987
|
+
const parsed = JSON.parse(output);
|
|
6988
|
+
normalizedOutput = Array.isArray(parsed) ? parsed : [parsed];
|
|
6989
|
+
} catch {
|
|
6990
|
+
normalizedOutput = [output];
|
|
6991
|
+
}
|
|
6992
|
+
} else if (output === null) {
|
|
6993
|
+
normalizedOutput = [];
|
|
6994
|
+
} else {
|
|
6995
|
+
normalizedOutput = [output];
|
|
6996
|
+
}
|
|
6997
|
+
logger.info(` Found ${normalizedOutput.length} items for forEach iteration`);
|
|
6998
|
+
return {
|
|
6999
|
+
isValid: true,
|
|
7000
|
+
normalizedOutput
|
|
7001
|
+
};
|
|
7002
|
+
}
|
|
6882
7003
|
/**
|
|
6883
7004
|
* Execute multiple checks with dependency awareness - return grouped results with statistics
|
|
6884
7005
|
*/
|
|
@@ -7088,10 +7209,14 @@ ${expr}
|
|
|
7088
7209
|
const checkConfig = config.checks[checkName];
|
|
7089
7210
|
if (checkConfig) {
|
|
7090
7211
|
dependencies[checkName] = checkConfig.depends_on || [];
|
|
7091
|
-
if (checkConfig.reuse_ai_session
|
|
7212
|
+
if (checkConfig.reuse_ai_session) {
|
|
7092
7213
|
sessionReuseChecks.add(checkName);
|
|
7093
|
-
if (
|
|
7094
|
-
sessionProviders.set(checkName, checkConfig.
|
|
7214
|
+
if (typeof checkConfig.reuse_ai_session === "string") {
|
|
7215
|
+
sessionProviders.set(checkName, checkConfig.reuse_ai_session);
|
|
7216
|
+
} else if (checkConfig.reuse_ai_session === true) {
|
|
7217
|
+
if (checkConfig.depends_on && checkConfig.depends_on.length > 0) {
|
|
7218
|
+
sessionProviders.set(checkName, checkConfig.depends_on[0]);
|
|
7219
|
+
}
|
|
7095
7220
|
}
|
|
7096
7221
|
}
|
|
7097
7222
|
} else {
|
|
@@ -7654,27 +7779,23 @@ ${expr}
|
|
|
7654
7779
|
}
|
|
7655
7780
|
const reviewResult = result.value.result;
|
|
7656
7781
|
const reviewSummaryWithOutput = reviewResult;
|
|
7657
|
-
if (checkConfig?.forEach &&
|
|
7782
|
+
if (checkConfig?.forEach && (!reviewResult.issues || reviewResult.issues.length === 0)) {
|
|
7783
|
+
const validation2 = this.validateAndNormalizeForEachOutput(
|
|
7784
|
+
checkName,
|
|
7785
|
+
reviewSummaryWithOutput.output,
|
|
7786
|
+
checkConfig.group
|
|
7787
|
+
);
|
|
7788
|
+
if (!validation2.isValid) {
|
|
7789
|
+
results.set(
|
|
7790
|
+
checkName,
|
|
7791
|
+
validation2.error.issues ? { issues: validation2.error.issues } : {}
|
|
7792
|
+
);
|
|
7793
|
+
continue;
|
|
7794
|
+
}
|
|
7795
|
+
const normalizedOutput = validation2.normalizedOutput;
|
|
7658
7796
|
logger.debug(
|
|
7659
7797
|
`\u{1F527} Debug: Raw output for forEach check ${checkName}: ${Array.isArray(reviewSummaryWithOutput.output) ? `array(${reviewSummaryWithOutput.output.length})` : typeof reviewSummaryWithOutput.output}`
|
|
7660
7798
|
);
|
|
7661
|
-
const rawOutput = reviewSummaryWithOutput.output;
|
|
7662
|
-
let normalizedOutput;
|
|
7663
|
-
if (Array.isArray(rawOutput)) {
|
|
7664
|
-
normalizedOutput = rawOutput;
|
|
7665
|
-
} else if (typeof rawOutput === "string") {
|
|
7666
|
-
try {
|
|
7667
|
-
const parsed = JSON.parse(rawOutput);
|
|
7668
|
-
normalizedOutput = Array.isArray(parsed) ? parsed : [parsed];
|
|
7669
|
-
} catch {
|
|
7670
|
-
normalizedOutput = [rawOutput];
|
|
7671
|
-
}
|
|
7672
|
-
} else if (rawOutput === void 0 || rawOutput === null) {
|
|
7673
|
-
normalizedOutput = [];
|
|
7674
|
-
} else {
|
|
7675
|
-
normalizedOutput = [rawOutput];
|
|
7676
|
-
}
|
|
7677
|
-
logger.info(` Found ${normalizedOutput.length} items for forEach iteration`);
|
|
7678
7799
|
try {
|
|
7679
7800
|
const preview = JSON.stringify(normalizedOutput);
|
|
7680
7801
|
logger.debug(
|
|
@@ -9368,6 +9489,10 @@ var init_config_schema = __esm({
|
|
|
9368
9489
|
$ref: "#/definitions/EnvConfig",
|
|
9369
9490
|
description: "Environment variables for this check"
|
|
9370
9491
|
},
|
|
9492
|
+
timeout: {
|
|
9493
|
+
type: "number",
|
|
9494
|
+
description: "Timeout in seconds for command execution (default: 60)"
|
|
9495
|
+
},
|
|
9371
9496
|
depends_on: {
|
|
9372
9497
|
type: "array",
|
|
9373
9498
|
items: {
|
|
@@ -9399,8 +9524,8 @@ var init_config_schema = __esm({
|
|
|
9399
9524
|
description: "Condition to determine if check should run - runs if expression evaluates to true"
|
|
9400
9525
|
},
|
|
9401
9526
|
reuse_ai_session: {
|
|
9402
|
-
type: "boolean",
|
|
9403
|
-
description: "
|
|
9527
|
+
type: ["string", "boolean"],
|
|
9528
|
+
description: "Check name to reuse AI session from, or true to use first dependency (only works with depends_on)"
|
|
9404
9529
|
},
|
|
9405
9530
|
fail_if: {
|
|
9406
9531
|
type: "string",
|
|
@@ -10737,7 +10862,7 @@ var ConfigManager = class {
|
|
|
10737
10862
|
if (!checkConfig.type) {
|
|
10738
10863
|
checkConfig.type = "ai";
|
|
10739
10864
|
}
|
|
10740
|
-
this.validateCheckConfig(checkName, checkConfig, errors);
|
|
10865
|
+
this.validateCheckConfig(checkName, checkConfig, errors, config);
|
|
10741
10866
|
if (checkConfig.ai_mcp_servers) {
|
|
10742
10867
|
this.validateMcpServersObject(
|
|
10743
10868
|
checkConfig.ai_mcp_servers,
|
|
@@ -10837,7 +10962,7 @@ var ConfigManager = class {
|
|
|
10837
10962
|
/**
|
|
10838
10963
|
* Validate individual check configuration
|
|
10839
10964
|
*/
|
|
10840
|
-
validateCheckConfig(checkName, checkConfig, errors) {
|
|
10965
|
+
validateCheckConfig(checkName, checkConfig, errors, config) {
|
|
10841
10966
|
if (!checkConfig.type) {
|
|
10842
10967
|
checkConfig.type = "ai";
|
|
10843
10968
|
}
|
|
@@ -10918,12 +11043,23 @@ var ConfigManager = class {
|
|
|
10918
11043
|
}
|
|
10919
11044
|
}
|
|
10920
11045
|
if (checkConfig.reuse_ai_session !== void 0) {
|
|
10921
|
-
|
|
11046
|
+
const isString = typeof checkConfig.reuse_ai_session === "string";
|
|
11047
|
+
const isBoolean = typeof checkConfig.reuse_ai_session === "boolean";
|
|
11048
|
+
if (!isString && !isBoolean) {
|
|
10922
11049
|
errors.push({
|
|
10923
11050
|
field: `checks.${checkName}.reuse_ai_session`,
|
|
10924
|
-
message: `Invalid reuse_ai_session value for "${checkName}": must be boolean`,
|
|
11051
|
+
message: `Invalid reuse_ai_session value for "${checkName}": must be string (check name) or boolean`,
|
|
10925
11052
|
value: checkConfig.reuse_ai_session
|
|
10926
11053
|
});
|
|
11054
|
+
} else if (isString) {
|
|
11055
|
+
const targetCheckName = checkConfig.reuse_ai_session;
|
|
11056
|
+
if (!config?.checks || !config.checks[targetCheckName]) {
|
|
11057
|
+
errors.push({
|
|
11058
|
+
field: `checks.${checkName}.reuse_ai_session`,
|
|
11059
|
+
message: `Check "${checkName}" references non-existent check "${targetCheckName}" for session reuse`,
|
|
11060
|
+
value: checkConfig.reuse_ai_session
|
|
11061
|
+
});
|
|
11062
|
+
}
|
|
10927
11063
|
} else if (checkConfig.reuse_ai_session === true) {
|
|
10928
11064
|
if (!checkConfig.depends_on || !Array.isArray(checkConfig.depends_on) || checkConfig.depends_on.length === 0) {
|
|
10929
11065
|
errors.push({
|