@syrin/cli 1.3.2 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -152
- package/dist/cli/commands/config.d.ts +47 -0
- package/dist/cli/commands/config.js +360 -0
- package/dist/cli/commands/dev.d.ts +6 -0
- package/dist/cli/commands/dev.js +67 -15
- package/dist/cli/commands/doctor.js +49 -13
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.js +89 -18
- package/dist/cli/commands/status.d.ts +10 -0
- package/dist/cli/commands/status.js +162 -0
- package/dist/cli/index.js +211 -12
- package/dist/cli/prompts/init-prompt.d.ts +18 -0
- package/dist/cli/prompts/init-prompt.js +159 -99
- package/dist/cli/utils/command-error-handler.js +2 -5
- package/dist/config/env-checker.d.ts +12 -2
- package/dist/config/env-checker.js +88 -38
- package/dist/config/env-templates.d.ts +15 -0
- package/dist/config/env-templates.js +49 -0
- package/dist/config/generator.js +17 -0
- package/dist/config/global-loader.d.ts +50 -0
- package/dist/config/global-loader.js +244 -0
- package/dist/config/loader.d.ts +28 -0
- package/dist/config/loader.js +95 -9
- package/dist/config/merger.d.ts +37 -0
- package/dist/config/merger.js +68 -0
- package/dist/config/schema.d.ts +26 -1
- package/dist/config/schema.js +73 -8
- package/dist/config/types.d.ts +19 -0
- package/dist/config/types.js +26 -1
- package/dist/constants/messages.d.ts +7 -0
- package/dist/constants/messages.js +8 -0
- package/dist/constants/paths.d.ts +6 -0
- package/dist/constants/paths.js +10 -0
- package/dist/events/emitter.js +7 -7
- package/dist/index.js +0 -0
- package/dist/presentation/config-ui.d.ts +34 -0
- package/dist/presentation/config-ui.js +139 -0
- package/dist/presentation/doctor-ui.d.ts +11 -0
- package/dist/presentation/doctor-ui.js +52 -1
- package/dist/presentation/init-ui.d.ts +9 -0
- package/dist/presentation/init-ui.js +33 -0
- package/dist/runtime/analysis/analyser.js +2 -2
- package/dist/runtime/analysis/rules/warnings/w104-generic-description.d.ts +1 -1
- package/dist/runtime/analysis/rules/warnings/w104-generic-description.js +1 -1
- package/dist/runtime/dev/event-mapper.js +19 -3
- package/dist/runtime/dev/session.d.ts +4 -0
- package/dist/runtime/dev/session.js +52 -3
- package/dist/runtime/llm/ollama.js +4 -4
- package/dist/runtime/mcp/client/manager.js +3 -3
- package/dist/runtime/sandbox/executor.js +5 -5
- package/dist/runtime/test/orchestrator.js +4 -4
- package/dist/utils/editor.d.ts +37 -0
- package/dist/utils/editor.js +137 -0
- package/dist/utils/logger.d.ts +24 -6
- package/dist/utils/logger.js +51 -8
- package/package.json +23 -23
- package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e001-missing-output-schema.js +0 -30
- package/dist/runtime/analysis/rules/errors/e002-underspecified-input.d.ts +0 -24
- package/dist/runtime/analysis/rules/errors/e002-underspecified-input.js +0 -52
- package/dist/runtime/analysis/rules/errors/e003-type-mismatch.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e003-type-mismatch.js +0 -73
- package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e004-free-text-propagation.js +0 -47
- package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.d.ts +0 -25
- package/dist/runtime/analysis/rules/errors/e005-tool-ambiguity.js +0 -73
- package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e006-param-not-in-description.js +0 -57
- package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e007-output-not-guaranteed.js +0 -56
- package/dist/runtime/analysis/rules/errors/e008-circular-dependency.d.ts +0 -22
- package/dist/runtime/analysis/rules/errors/e008-circular-dependency.js +0 -84
- package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.d.ts +0 -23
- package/dist/runtime/analysis/rules/errors/e009-implicit-user-input.js +0 -89
- package/dist/runtime/analysis/rules/errors/e010-non-serializable.d.ts +0 -25
- package/dist/runtime/analysis/rules/errors/e010-non-serializable.js +0 -46
- package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.d.ts +0 -24
- package/dist/runtime/analysis/rules/errors/e011-missing-tool-description.js +0 -33
- package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e012-side-effect-detected.js +0 -40
- package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.d.ts +0 -37
- package/dist/runtime/analysis/rules/errors/e013-non-deterministic-output.js +0 -34
- package/dist/runtime/analysis/rules/errors/e013-output-explosion.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e013-output-explosion.js +0 -36
- package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.d.ts +0 -42
- package/dist/runtime/analysis/rules/errors/e014-hidden-dependency.js +0 -46
- package/dist/runtime/analysis/rules/errors/e014-output-explosion.d.ts +0 -39
- package/dist/runtime/analysis/rules/errors/e014-output-explosion.js +0 -36
- package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.d.ts +0 -42
- package/dist/runtime/analysis/rules/errors/e015-hidden-dependency.js +0 -46
- package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.d.ts +0 -44
- package/dist/runtime/analysis/rules/errors/e015-unbounded-execution.js +0 -66
- package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.d.ts +0 -43
- package/dist/runtime/analysis/rules/errors/e016-output-validation-failed.js +0 -42
- package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.d.ts +0 -44
- package/dist/runtime/analysis/rules/errors/e016-unbounded-execution.js +0 -66
- package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.d.ts +0 -57
- package/dist/runtime/analysis/rules/errors/e017-input-validation-failed.js +0 -80
- package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.d.ts +0 -43
- package/dist/runtime/analysis/rules/errors/e017-output-validation-failed.js +0 -42
- package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.d.ts +0 -57
- package/dist/runtime/analysis/rules/errors/e018-input-validation-failed.js +0 -80
- package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.d.ts +0 -38
- package/dist/runtime/analysis/rules/errors/e018-tool-execution-failed.js +0 -37
- package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.d.ts +0 -38
- package/dist/runtime/analysis/rules/errors/e019-tool-execution-failed.js +0 -37
- package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.d.ts +0 -65
- package/dist/runtime/analysis/rules/errors/e019-unexpected-test-result.js +0 -109
- package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.d.ts +0 -65
- package/dist/runtime/analysis/rules/errors/e020-unexpected-test-result.js +0 -109
- package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w001-implicit-dependency.js +0 -39
- package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.d.ts +0 -24
- package/dist/runtime/analysis/rules/warnings/w002-free-text-without-normalization.js +0 -40
- package/dist/runtime/analysis/rules/warnings/w003-missing-examples.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w003-missing-examples.js +0 -84
- package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w004-overloaded-responsibility.js +0 -96
- package/dist/runtime/analysis/rules/warnings/w005-generic-description.d.ts +0 -53
- package/dist/runtime/analysis/rules/warnings/w005-generic-description.js +0 -108
- package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w006-optional-as-required.js +0 -44
- package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w007-broad-output-schema.js +0 -37
- package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w008-multiple-entry-points.js +0 -97
- package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.d.ts +0 -23
- package/dist/runtime/analysis/rules/warnings/w009-hidden-side-effects.js +0 -88
- package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.d.ts +0 -22
- package/dist/runtime/analysis/rules/warnings/w010-output-not-reusable.js +0 -81
- package/dist/runtime/analysis/rules/warnings/w021-weak-schema.d.ts +0 -40
- package/dist/runtime/analysis/rules/warnings/w021-weak-schema.js +0 -32
- package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.d.ts +0 -39
- package/dist/runtime/analysis/rules/warnings/w022-high-entropy-output.js +0 -36
- package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.d.ts +0 -38
- package/dist/runtime/analysis/rules/warnings/w023-unstable-defaults.js +0 -36
- package/dist/runtime/test/dependency-tracker.d.ts +0 -66
- package/dist/runtime/test/dependency-tracker.js +0 -80
- package/dist/runtime/test/formatters.d.ts +0 -18
- package/dist/runtime/test/formatters.js +0 -172
- package/dist/runtime/test/input-generator.d.ts +0 -33
- package/dist/runtime/test/input-generator.js +0 -498
- package/dist/runtime/test/mcp-root-detector.d.ts +0 -31
- package/dist/runtime/test/mcp-root-detector.js +0 -105
- package/dist/runtime/test/retry-tester.d.ts +0 -44
- package/dist/runtime/test/retry-tester.js +0 -103
- package/dist/runtime/test/synthetic-input-generator.d.ts +0 -11
- package/dist/runtime/test/synthetic-input-generator.js +0 -154
- package/dist/runtime/test/test-runner.d.ts +0 -28
- package/dist/runtime/test/test-runner.js +0 -55
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W006: Optional Input Used as Required Downstream
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Input marked optional
|
|
6
|
-
* - Treated as required in chaining
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Hidden contract violation
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
class W006OptionalAsRequiredRule extends BaseRule {
|
|
13
|
-
id = 'W006';
|
|
14
|
-
severity = 'warning';
|
|
15
|
-
ruleName = 'Optional Input Used as Required Downstream';
|
|
16
|
-
description = 'Optional input is treated as required downstream. Hidden contract violation.';
|
|
17
|
-
check(ctx) {
|
|
18
|
-
const diagnostics = [];
|
|
19
|
-
// Check high-confidence dependencies (>= 0.8)
|
|
20
|
-
const highConfidenceDeps = ctx.dependencies.filter(d => d.confidence >= 0.8);
|
|
21
|
-
for (const dep of highConfidenceDeps) {
|
|
22
|
-
// Find the source output
|
|
23
|
-
const fromTool = ctx.indexes.toolIndex.get(dep.fromTool.toLowerCase());
|
|
24
|
-
const toTool = ctx.indexes.toolIndex.get(dep.toTool.toLowerCase());
|
|
25
|
-
if (!fromTool || !toTool) {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
const fromField = fromTool.outputs.find(f => f.name === dep.fromField);
|
|
29
|
-
const toField = toTool.inputs.find(f => f.name === dep.toField);
|
|
30
|
-
if (!fromField || !toField) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
// Check if source is optional/nullable but target is required
|
|
34
|
-
const isSourceOptional = fromField.nullable === true;
|
|
35
|
-
const isTargetRequired = toField.required === true;
|
|
36
|
-
if (isSourceOptional && isTargetRequired) {
|
|
37
|
-
diagnostics.push(this.createDiagnostic(`Source field "${dep.fromTool}.${dep.fromField}" is nullable/optional but is being wired into required input "${dep.toTool}.${dep.toField}".`, dep.toTool, dep.toField, `Make "${dep.fromTool}.${dep.fromField}" non-nullable, or make "${dep.toTool}.${dep.toField}" optional.`));
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return diagnostics;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
export const W006OptionalAsRequired = new W006OptionalAsRequiredRule();
|
|
44
|
-
//# sourceMappingURL=w006-optional-as-required.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W007: Output Schema Too Broad
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output type is object with no properties
|
|
6
|
-
* - Or any
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - No contract enforcement
|
|
10
|
-
* - Breaks evolution
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
14
|
-
declare class W007BroadOutputSchemaRule extends BaseRule {
|
|
15
|
-
readonly id = "W007";
|
|
16
|
-
readonly severity: "warning";
|
|
17
|
-
readonly ruleName = "Output Schema Too Broad";
|
|
18
|
-
readonly description = "Output schema of tool is too broad. No contract enforcement.";
|
|
19
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
20
|
-
}
|
|
21
|
-
export declare const W007BroadOutputSchema: W007BroadOutputSchemaRule;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=w007-broad-output-schema.d.ts.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W007: Output Schema Too Broad
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output type is object with no properties
|
|
6
|
-
* - Or any
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - No contract enforcement
|
|
10
|
-
* - Breaks evolution
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
class W007BroadOutputSchemaRule extends BaseRule {
|
|
14
|
-
id = 'W007';
|
|
15
|
-
severity = 'warning';
|
|
16
|
-
ruleName = 'Output Schema Too Broad';
|
|
17
|
-
description = 'Output schema of tool is too broad. No contract enforcement.';
|
|
18
|
-
check(ctx) {
|
|
19
|
-
const diagnostics = [];
|
|
20
|
-
for (const tool of ctx.tools) {
|
|
21
|
-
for (const output of tool.outputs) {
|
|
22
|
-
// Check if output is "any" type
|
|
23
|
-
if (output.type === 'any') {
|
|
24
|
-
diagnostics.push(this.createDiagnostic(`Output schema of "${tool.name}" (field: "${output.name}") is too broad (type: "any").`, tool.name, output.name, `Specify a concrete type for "${output.name}" instead of "any".`));
|
|
25
|
-
}
|
|
26
|
-
// Check if output is object with no properties
|
|
27
|
-
if (output.type === 'object' &&
|
|
28
|
-
(!output.properties || output.properties.length === 0)) {
|
|
29
|
-
diagnostics.push(this.createDiagnostic(`Output schema of "${tool.name}" (field: "${output.name}") is an object with no properties defined.`, tool.name, output.name, `Define the properties of the object schema for "${output.name}".`));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
return diagnostics;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export const W007BroadOutputSchema = new W007BroadOutputSchemaRule();
|
|
37
|
-
//# sourceMappingURL=w007-broad-output-schema.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W008: Multiple Entry Points for Same Concept
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Multiple tools ask user for same conceptual data
|
|
6
|
-
* (e.g. location, user_id)
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Conflicting sources of truth
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
declare class W008MultipleEntryPointsRule extends BaseRule {
|
|
14
|
-
readonly id = "W008";
|
|
15
|
-
readonly severity: "warning";
|
|
16
|
-
readonly ruleName = "Multiple Entry Points for Same Concept";
|
|
17
|
-
readonly description = "Multiple tools capture the same concept. Conflicting sources of truth.";
|
|
18
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
19
|
-
}
|
|
20
|
-
export declare const W008MultipleEntryPoints: W008MultipleEntryPointsRule;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=w008-multiple-entry-points.d.ts.map
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W008: Multiple Entry Points for Same Concept
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Multiple tools ask user for same conceptual data
|
|
6
|
-
* (e.g. location, user_id)
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Conflicting sources of truth
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import { escapeRegex } from '../../utils.js';
|
|
13
|
-
/**
|
|
14
|
-
* Extract the concept from an input field name.
|
|
15
|
-
*/
|
|
16
|
-
function extractConcept(fieldName) {
|
|
17
|
-
// Split field name into tokens (on non-word characters and camelCase boundaries)
|
|
18
|
-
// Preserve case for camelCase detection, then lowercase tokens individually
|
|
19
|
-
const tokens = fieldName
|
|
20
|
-
.split(/[^\w]+|(?<=[a-z])(?=[A-Z])/)
|
|
21
|
-
.filter(t => t.length > 0)
|
|
22
|
-
.map(t => t.toLowerCase());
|
|
23
|
-
const name = fieldName.toLowerCase();
|
|
24
|
-
// Common concepts
|
|
25
|
-
const concepts = [
|
|
26
|
-
[['location', 'loc', 'place', 'address', 'city', 'country'], 'location'],
|
|
27
|
-
[['user', 'user_id', 'userid', 'username', 'person'], 'user'],
|
|
28
|
-
[['email', 'e-mail', 'mail'], 'email'],
|
|
29
|
-
[['phone', 'telephone', 'mobile'], 'phone'],
|
|
30
|
-
[['name', 'fullname', 'full_name'], 'name'],
|
|
31
|
-
[['id', 'identifier'], 'id'],
|
|
32
|
-
];
|
|
33
|
-
for (const [keywords, concept] of concepts) {
|
|
34
|
-
for (const keyword of keywords) {
|
|
35
|
-
// Check for exact token match or word-boundary match
|
|
36
|
-
// Escape keyword to prevent regex injection
|
|
37
|
-
const escapedKeyword = escapeRegex(keyword);
|
|
38
|
-
const keywordRegex = new RegExp(`\\b${escapedKeyword}\\b`, 'i');
|
|
39
|
-
if (tokens.includes(keyword) || keywordRegex.test(name)) {
|
|
40
|
-
return concept;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
class W008MultipleEntryPointsRule extends BaseRule {
|
|
47
|
-
id = 'W008';
|
|
48
|
-
severity = 'warning';
|
|
49
|
-
ruleName = 'Multiple Entry Points for Same Concept';
|
|
50
|
-
description = 'Multiple tools capture the same concept. Conflicting sources of truth.';
|
|
51
|
-
check(ctx) {
|
|
52
|
-
const diagnostics = [];
|
|
53
|
-
// Map concept to tools that have it
|
|
54
|
-
const conceptToTools = new Map();
|
|
55
|
-
for (const tool of ctx.tools) {
|
|
56
|
-
for (const input of tool.inputs) {
|
|
57
|
-
// Only check user-facing inputs
|
|
58
|
-
if (!input.required) {
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
const concept = extractConcept(input.name);
|
|
62
|
-
if (!concept) {
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
if (!conceptToTools.has(concept)) {
|
|
66
|
-
conceptToTools.set(concept, []);
|
|
67
|
-
}
|
|
68
|
-
conceptToTools.get(concept).push({
|
|
69
|
-
tool: tool.name,
|
|
70
|
-
field: input.name,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
// Check for concepts that appear in multiple tools
|
|
75
|
-
for (const [concept, tools] of conceptToTools.entries()) {
|
|
76
|
-
if (tools.length > 1) {
|
|
77
|
-
const toolNames = tools.map(t => `"${t.tool}"`).join(', ');
|
|
78
|
-
// Group by tool name in case same tool appears multiple times
|
|
79
|
-
const toolFieldsMap = new Map();
|
|
80
|
-
for (const toolEntry of tools) {
|
|
81
|
-
if (!toolFieldsMap.has(toolEntry.tool)) {
|
|
82
|
-
toolFieldsMap.set(toolEntry.tool, []);
|
|
83
|
-
}
|
|
84
|
-
toolFieldsMap.get(toolEntry.tool).push(toolEntry.field);
|
|
85
|
-
}
|
|
86
|
-
const context = {};
|
|
87
|
-
for (const [tool, fields] of toolFieldsMap.entries()) {
|
|
88
|
-
context[tool] = fields.join(', ');
|
|
89
|
-
}
|
|
90
|
-
diagnostics.push(this.createDiagnostic(`Multiple tools capture the same concept: "${concept}" (${toolNames}).`, undefined, undefined, `Consolidate "${concept}" collection into a single tool to avoid conflicting sources of truth.`, context));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return diagnostics;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
export const W008MultipleEntryPoints = new W008MultipleEntryPointsRule();
|
|
97
|
-
//# sourceMappingURL=w008-multiple-entry-points.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W009: Hidden Side Effects
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool name/description suggests mutation
|
|
6
|
-
* - But schema does not reflect it
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Execution surprises
|
|
10
|
-
* - Hard to reason
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
14
|
-
declare class W009HiddenSideEffectsRule extends BaseRule {
|
|
15
|
-
readonly id = "W009";
|
|
16
|
-
readonly severity: "warning";
|
|
17
|
-
readonly ruleName = "Hidden Side Effects";
|
|
18
|
-
readonly description = "Tool appears to have side effects not reflected in schema. Execution surprises.";
|
|
19
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
20
|
-
}
|
|
21
|
-
export declare const W009HiddenSideEffects: W009HiddenSideEffectsRule;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=w009-hidden-side-effects.d.ts.map
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W009: Hidden Side Effects
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool name/description suggests mutation
|
|
6
|
-
* - But schema does not reflect it
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Execution surprises
|
|
10
|
-
* - Hard to reason
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
/**
|
|
14
|
-
* Check if a tool name/description suggests mutation.
|
|
15
|
-
*/
|
|
16
|
-
function suggestsMutation(toolName, description) {
|
|
17
|
-
const combined = `${toolName} ${description}`.toLowerCase();
|
|
18
|
-
// Mutation verbs
|
|
19
|
-
const mutationVerbs = [
|
|
20
|
-
'create',
|
|
21
|
-
'delete',
|
|
22
|
-
'remove',
|
|
23
|
-
'update',
|
|
24
|
-
'modify',
|
|
25
|
-
'change',
|
|
26
|
-
'set',
|
|
27
|
-
'save',
|
|
28
|
-
'write',
|
|
29
|
-
'add',
|
|
30
|
-
'insert',
|
|
31
|
-
'destroy',
|
|
32
|
-
'drop',
|
|
33
|
-
'clear',
|
|
34
|
-
'reset',
|
|
35
|
-
];
|
|
36
|
-
return mutationVerbs.some(verb => {
|
|
37
|
-
const regex = new RegExp(`\\b${verb}\\b`, 'i');
|
|
38
|
-
return regex.test(combined);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if schema reflects mutation (has outputs that suggest state change).
|
|
43
|
-
*/
|
|
44
|
-
function schemaReflectsMutation(tool) {
|
|
45
|
-
// If no outputs, it might be a mutation (void operation)
|
|
46
|
-
if (tool.outputs.length === 0) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
// Check if outputs suggest mutation confirmation
|
|
50
|
-
const mutationOutputs = [
|
|
51
|
-
'success',
|
|
52
|
-
'id',
|
|
53
|
-
'result',
|
|
54
|
-
'status',
|
|
55
|
-
'created',
|
|
56
|
-
'updated',
|
|
57
|
-
'deleted',
|
|
58
|
-
];
|
|
59
|
-
for (const output of tool.outputs) {
|
|
60
|
-
const name = output.name.toLowerCase();
|
|
61
|
-
const desc = (output.description || '').toLowerCase();
|
|
62
|
-
if (mutationOutputs.some(mo => name.includes(mo) || desc.includes(mo))) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
class W009HiddenSideEffectsRule extends BaseRule {
|
|
69
|
-
id = 'W009';
|
|
70
|
-
severity = 'warning';
|
|
71
|
-
ruleName = 'Hidden Side Effects';
|
|
72
|
-
description = 'Tool appears to have side effects not reflected in schema. Execution surprises.';
|
|
73
|
-
check(ctx) {
|
|
74
|
-
const diagnostics = [];
|
|
75
|
-
for (const tool of ctx.tools) {
|
|
76
|
-
const description = tool.description || '';
|
|
77
|
-
const suggestsMut = suggestsMutation(tool.name, description);
|
|
78
|
-
const reflectsMut = schemaReflectsMutation(tool);
|
|
79
|
-
// If it suggests mutation but schema doesn't reflect it
|
|
80
|
-
if (suggestsMut && !reflectsMut) {
|
|
81
|
-
diagnostics.push(this.createDiagnostic(`Tool "${tool.name}" appears to have side effects not reflected in schema.`, tool.name, undefined, `Update the output schema of "${tool.name}" to reflect state changes (e.g., add success status, created ID, etc.).`));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return diagnostics;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
export const W009HiddenSideEffects = new W009HiddenSideEffectsRule();
|
|
88
|
-
//# sourceMappingURL=w009-hidden-side-effects.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W010: Tool Output Not Reusable
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output tailored only for natural language
|
|
6
|
-
* - Not structured for reuse
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Limits composability
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
declare class W010OutputNotReusableRule extends BaseRule {
|
|
14
|
-
readonly id = "W010";
|
|
15
|
-
readonly severity: "warning";
|
|
16
|
-
readonly ruleName = "Tool Output Not Reusable";
|
|
17
|
-
readonly description = "Output of tool is not designed for reuse. Limits composability.";
|
|
18
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
19
|
-
}
|
|
20
|
-
export declare const W010OutputNotReusable: W010OutputNotReusableRule;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=w010-output-not-reusable.d.ts.map
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W010: Tool Output Not Reusable
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output tailored only for natural language
|
|
6
|
-
* - Not structured for reuse
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Limits composability
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
/**
|
|
13
|
-
* Check if output appears to be only for natural language display.
|
|
14
|
-
*/
|
|
15
|
-
function isNaturalLanguageOnly(output) {
|
|
16
|
-
const name = output.name.toLowerCase();
|
|
17
|
-
const desc = (output.description || '').toLowerCase();
|
|
18
|
-
const combined = `${name} ${desc}`;
|
|
19
|
-
// Indicators that output is only for display
|
|
20
|
-
const displayOnlyIndicators = [
|
|
21
|
-
'message',
|
|
22
|
-
'response',
|
|
23
|
-
'reply',
|
|
24
|
-
'answer',
|
|
25
|
-
'text',
|
|
26
|
-
'description',
|
|
27
|
-
'summary',
|
|
28
|
-
'note',
|
|
29
|
-
'comment',
|
|
30
|
-
'info',
|
|
31
|
-
];
|
|
32
|
-
// If it's a string type and name suggests display-only
|
|
33
|
-
if (output.type === 'string') {
|
|
34
|
-
return displayOnlyIndicators.some(indicator => combined.includes(indicator));
|
|
35
|
-
}
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Check if output is structured (object or array).
|
|
40
|
-
*/
|
|
41
|
-
function isStructured(output) {
|
|
42
|
-
if (output.type === 'object' || output.type === 'array') {
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
if (output.properties && typeof output.properties === 'object') {
|
|
46
|
-
if (Array.isArray(output.properties) && output.properties.length > 0) {
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
// Also check if it's a Record with keys
|
|
50
|
-
if (!Array.isArray(output.properties) &&
|
|
51
|
-
Object.keys(output.properties).length > 0) {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
class W010OutputNotReusableRule extends BaseRule {
|
|
58
|
-
id = 'W010';
|
|
59
|
-
severity = 'warning';
|
|
60
|
-
ruleName = 'Tool Output Not Reusable';
|
|
61
|
-
description = 'Output of tool is not designed for reuse. Limits composability.';
|
|
62
|
-
check(ctx) {
|
|
63
|
-
const diagnostics = [];
|
|
64
|
-
for (const tool of ctx.tools) {
|
|
65
|
-
// Only check tools that have outputs
|
|
66
|
-
if (tool.outputs.length === 0) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
// Check if all outputs are natural language only
|
|
70
|
-
const allNaturalLanguage = tool.outputs.every(output => isNaturalLanguageOnly(output));
|
|
71
|
-
const hasStructured = tool.outputs.some(output => isStructured(output));
|
|
72
|
-
// If all outputs are natural language and none are structured
|
|
73
|
-
if (allNaturalLanguage && !hasStructured) {
|
|
74
|
-
diagnostics.push(this.createDiagnostic(`Output of "${tool.name}" is not designed for reuse (only natural language output).`, tool.name, undefined, `Add structured output fields (objects/arrays) to "${tool.name}" to improve composability with other tools.`));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return diagnostics;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
export const W010OutputNotReusable = new W010OutputNotReusableRule();
|
|
81
|
-
//# sourceMappingURL=w010-output-not-reusable.js.map
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W021: Weak Schema
|
|
3
|
-
*
|
|
4
|
-
* Condition: Contract schema is too loose or doesn't match MCP tool schema structure
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - Loose schemas make validation less effective
|
|
8
|
-
* - Mismatch between contract and actual tool schema indicates contract needs update
|
|
9
|
-
*/
|
|
10
|
-
import { BaseRule } from '../base.js';
|
|
11
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
12
|
-
/**
|
|
13
|
-
* Context for weak schema detection.
|
|
14
|
-
*/
|
|
15
|
-
export interface WeakSchemaContext {
|
|
16
|
-
/** Tool name */
|
|
17
|
-
toolName: string;
|
|
18
|
-
/** Contract input schema name */
|
|
19
|
-
contractInputSchema: string;
|
|
20
|
-
/** Contract output schema name */
|
|
21
|
-
contractOutputSchema: string;
|
|
22
|
-
/** Whether schemas match actual MCP tool schemas */
|
|
23
|
-
schemasMatch: boolean;
|
|
24
|
-
/** Details about mismatch (if any) */
|
|
25
|
-
mismatchDetails?: string;
|
|
26
|
-
}
|
|
27
|
-
declare class W021WeakSchemaRule extends BaseRule {
|
|
28
|
-
readonly id = "W021";
|
|
29
|
-
readonly severity: "warning";
|
|
30
|
-
readonly ruleName = "Weak Schema";
|
|
31
|
-
readonly description = "Contract schema is too loose or does not match MCP tool schema structure.";
|
|
32
|
-
check(_ctx: AnalysisContext): Diagnostic[];
|
|
33
|
-
/**
|
|
34
|
-
* Check with behavioral context (called from test orchestrator).
|
|
35
|
-
*/
|
|
36
|
-
checkWithBehavioralContext(behavioralCtx: WeakSchemaContext): Diagnostic[];
|
|
37
|
-
}
|
|
38
|
-
export declare const W021WeakSchema: W021WeakSchemaRule;
|
|
39
|
-
export {};
|
|
40
|
-
//# sourceMappingURL=w021-weak-schema.d.ts.map
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W021: Weak Schema
|
|
3
|
-
*
|
|
4
|
-
* Condition: Contract schema is too loose or doesn't match MCP tool schema structure
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - Loose schemas make validation less effective
|
|
8
|
-
* - Mismatch between contract and actual tool schema indicates contract needs update
|
|
9
|
-
*/
|
|
10
|
-
import { BaseRule } from '../base.js';
|
|
11
|
-
class W021WeakSchemaRule extends BaseRule {
|
|
12
|
-
id = 'W021';
|
|
13
|
-
severity = 'warning';
|
|
14
|
-
ruleName = 'Weak Schema';
|
|
15
|
-
description = 'Contract schema is too loose or does not match MCP tool schema structure.';
|
|
16
|
-
check(_ctx) {
|
|
17
|
-
// This rule requires behavioral context (schema comparison)
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Check with behavioral context (called from test orchestrator).
|
|
22
|
-
*/
|
|
23
|
-
checkWithBehavioralContext(behavioralCtx) {
|
|
24
|
-
const diagnostics = [];
|
|
25
|
-
if (!behavioralCtx.schemasMatch) {
|
|
26
|
-
diagnostics.push(this.createDiagnostic(`Tool "${behavioralCtx.toolName}" contract schemas do not match actual MCP tool schemas.${behavioralCtx.mismatchDetails ? ` ${behavioralCtx.mismatchDetails}` : ''}`, behavioralCtx.toolName, undefined, 'Update contract to match actual tool schema structure. Ensure input_schema and output_schema names reference correct schemas.'));
|
|
27
|
-
}
|
|
28
|
-
return diagnostics;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
export const W021WeakSchema = new W021WeakSchemaRule();
|
|
32
|
-
//# sourceMappingURL=w021-weak-schema.js.map
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W022: High Entropy Output
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool output has high entropy (random, unpredictable structure)
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - High entropy makes it hard for LLM to reason about output
|
|
8
|
-
* - Indicates potential design issues
|
|
9
|
-
* - May indicate non-determinism
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
/**
|
|
14
|
-
* Context for high entropy detection.
|
|
15
|
-
*/
|
|
16
|
-
export interface HighEntropyContext {
|
|
17
|
-
/** Tool name */
|
|
18
|
-
toolName: string;
|
|
19
|
-
/** Entropy score (0-1, higher = more entropy) */
|
|
20
|
-
entropyScore: number;
|
|
21
|
-
/** Reason for high entropy */
|
|
22
|
-
reason?: string;
|
|
23
|
-
/** Optional custom entropy threshold (defaults to 0.7 if not provided) */
|
|
24
|
-
entropyThreshold?: number;
|
|
25
|
-
}
|
|
26
|
-
declare class W022HighEntropyOutputRule extends BaseRule {
|
|
27
|
-
readonly id = "W022";
|
|
28
|
-
readonly severity: "warning";
|
|
29
|
-
readonly ruleName = "High Entropy Output";
|
|
30
|
-
readonly description = "Tool output has high entropy, making it difficult for LLM to reason about.";
|
|
31
|
-
check(_ctx: AnalysisContext): Diagnostic[];
|
|
32
|
-
/**
|
|
33
|
-
* Check with behavioral context (called from test orchestrator).
|
|
34
|
-
*/
|
|
35
|
-
checkWithBehavioralContext(behavioralCtx: HighEntropyContext): Diagnostic[];
|
|
36
|
-
}
|
|
37
|
-
export declare const W022HighEntropyOutput: W022HighEntropyOutputRule;
|
|
38
|
-
export {};
|
|
39
|
-
//# sourceMappingURL=w022-high-entropy-output.d.ts.map
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W022: High Entropy Output
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool output has high entropy (random, unpredictable structure)
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - High entropy makes it hard for LLM to reason about output
|
|
8
|
-
* - Indicates potential design issues
|
|
9
|
-
* - May indicate non-determinism
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
class W022HighEntropyOutputRule extends BaseRule {
|
|
13
|
-
id = 'W022';
|
|
14
|
-
severity = 'warning';
|
|
15
|
-
ruleName = 'High Entropy Output';
|
|
16
|
-
description = 'Tool output has high entropy, making it difficult for LLM to reason about.';
|
|
17
|
-
check(_ctx) {
|
|
18
|
-
// This rule requires behavioral context
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Check with behavioral context (called from test orchestrator).
|
|
23
|
-
*/
|
|
24
|
-
checkWithBehavioralContext(behavioralCtx) {
|
|
25
|
-
const diagnostics = [];
|
|
26
|
-
// Use configured threshold or fall back to default 0.7
|
|
27
|
-
const threshold = behavioralCtx.entropyThreshold ?? 0.7;
|
|
28
|
-
// Threshold: entropy above configured value is considered high
|
|
29
|
-
if (behavioralCtx.entropyScore > threshold) {
|
|
30
|
-
diagnostics.push(this.createDiagnostic(`Tool "${behavioralCtx.toolName}" produces high entropy output (score: ${behavioralCtx.entropyScore.toFixed(2)}, threshold: ${threshold.toFixed(2)}).${behavioralCtx.reason ? ` ${behavioralCtx.reason}` : ''}`, behavioralCtx.toolName, undefined, 'Consider normalizing output structure, reducing randomness, or providing more predictable output format.'));
|
|
31
|
-
}
|
|
32
|
-
return diagnostics;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export const W022HighEntropyOutput = new W022HighEntropyOutputRule();
|
|
36
|
-
//# sourceMappingURL=w022-high-entropy-output.js.map
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W023: Unstable Defaults
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool behavior changes significantly with default values
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - Defaults should be stable and predictable
|
|
8
|
-
* - Changing defaults breaks agent expectations
|
|
9
|
-
* - Indicates design inconsistency
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
/**
|
|
14
|
-
* Context for unstable defaults detection.
|
|
15
|
-
*/
|
|
16
|
-
export interface UnstableDefaultsContext {
|
|
17
|
-
/** Tool name */
|
|
18
|
-
toolName: string;
|
|
19
|
-
/** Fields with unstable defaults */
|
|
20
|
-
unstableFields: Array<{
|
|
21
|
-
fieldName: string;
|
|
22
|
-
reason: string;
|
|
23
|
-
}>;
|
|
24
|
-
}
|
|
25
|
-
declare class W023UnstableDefaultsRule extends BaseRule {
|
|
26
|
-
readonly id = "W023";
|
|
27
|
-
readonly severity: "warning";
|
|
28
|
-
readonly ruleName = "Unstable Defaults";
|
|
29
|
-
readonly description = "Tool behavior changes significantly with default values, breaking agent expectations.";
|
|
30
|
-
check(_ctx: AnalysisContext): Diagnostic[];
|
|
31
|
-
/**
|
|
32
|
-
* Check with behavioral context (called from test orchestrator).
|
|
33
|
-
*/
|
|
34
|
-
checkWithBehavioralContext(behavioralCtx: UnstableDefaultsContext): Diagnostic[];
|
|
35
|
-
}
|
|
36
|
-
export declare const W023UnstableDefaults: W023UnstableDefaultsRule;
|
|
37
|
-
export {};
|
|
38
|
-
//# sourceMappingURL=w023-unstable-defaults.d.ts.map
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* W023: Unstable Defaults
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool behavior changes significantly with default values
|
|
5
|
-
*
|
|
6
|
-
* Why this is a warning:
|
|
7
|
-
* - Defaults should be stable and predictable
|
|
8
|
-
* - Changing defaults breaks agent expectations
|
|
9
|
-
* - Indicates design inconsistency
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
class W023UnstableDefaultsRule extends BaseRule {
|
|
13
|
-
id = 'W023';
|
|
14
|
-
severity = 'warning';
|
|
15
|
-
ruleName = 'Unstable Defaults';
|
|
16
|
-
description = 'Tool behavior changes significantly with default values, breaking agent expectations.';
|
|
17
|
-
check(_ctx) {
|
|
18
|
-
// This rule requires behavioral context
|
|
19
|
-
return [];
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Check with behavioral context (called from test orchestrator).
|
|
23
|
-
*/
|
|
24
|
-
checkWithBehavioralContext(behavioralCtx) {
|
|
25
|
-
const diagnostics = [];
|
|
26
|
-
if (behavioralCtx.unstableFields.length > 0) {
|
|
27
|
-
const fieldList = behavioralCtx.unstableFields
|
|
28
|
-
.map(f => ` - ${f.fieldName}: ${f.reason}`)
|
|
29
|
-
.join('\n');
|
|
30
|
-
diagnostics.push(this.createDiagnostic(`Tool "${behavioralCtx.toolName}" has unstable default values:\n${fieldList}`, behavioralCtx.toolName, undefined, 'Ensure default values are stable and predictable. Avoid defaults that change behavior significantly.'));
|
|
31
|
-
}
|
|
32
|
-
return diagnostics;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export const W023UnstableDefaults = new W023UnstableDefaultsRule();
|
|
36
|
-
//# sourceMappingURL=w023-unstable-defaults.js.map
|