@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syrin/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Syrin is a runtime intelligence system that makes MCP servers debuggable, testable, and safe to run in production.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"LICENSE"
|
|
24
24
|
],
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": ">=20.12.0"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"mcp",
|
|
@@ -55,52 +55,52 @@
|
|
|
55
55
|
},
|
|
56
56
|
"repository": {
|
|
57
57
|
"type": "git",
|
|
58
|
-
"url": "git+https://github.com/
|
|
58
|
+
"url": "git+https://github.com/Syrin-Labs/cli.git"
|
|
59
59
|
},
|
|
60
60
|
"author": "Syrin Labs Team",
|
|
61
61
|
"license": "ISC",
|
|
62
62
|
"bugs": {
|
|
63
|
-
"url": "https://github.com/
|
|
63
|
+
"url": "https://github.com/Syrin-Labs/cli/issues"
|
|
64
64
|
},
|
|
65
|
-
"homepage": "https://github.com/
|
|
65
|
+
"homepage": "https://github.com/Syrin-Labs/cli#readme",
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/inquirer": "^9.0.9",
|
|
71
71
|
"@types/js-yaml": "^4.0.9",
|
|
72
|
-
"@types/node": "^25.0
|
|
73
|
-
"@types/react": "^19.2.
|
|
72
|
+
"@types/node": "^25.2.0",
|
|
73
|
+
"@types/react": "^19.2.10",
|
|
74
74
|
"@types/uuid": "^10.0.0",
|
|
75
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
76
|
-
"@typescript-eslint/parser": "^8.
|
|
77
|
-
"@vitest/coverage-v8": "^
|
|
78
|
-
"@vitest/ui": "^
|
|
75
|
+
"@typescript-eslint/eslint-plugin": "^8.54.0",
|
|
76
|
+
"@typescript-eslint/parser": "^8.54.0",
|
|
77
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
78
|
+
"@vitest/ui": "^4.0.18",
|
|
79
79
|
"eslint": "^9.39.2",
|
|
80
80
|
"eslint-config-prettier": "^10.1.8",
|
|
81
81
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
82
82
|
"eslint-plugin-import": "^2.32.0",
|
|
83
|
-
"eslint-plugin-prettier": "^5.5.
|
|
84
|
-
"globals": "^17.
|
|
85
|
-
"prettier": "^3.
|
|
83
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
84
|
+
"globals": "^17.3.0",
|
|
85
|
+
"prettier": "^3.8.1",
|
|
86
86
|
"tsc-alias": "^1.8.16",
|
|
87
87
|
"tsconfig-paths": "^4.2.0",
|
|
88
88
|
"typescript": "^5.9.3",
|
|
89
|
-
"vitest": "^
|
|
89
|
+
"vitest": "^4.0.18"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@anthropic-ai/sdk": "^0.
|
|
93
|
-
"@apidevtools/json-schema-ref-parser": "^15.
|
|
94
|
-
"@modelcontextprotocol/sdk": "^1.25.
|
|
95
|
-
"commander": "^14.0.
|
|
92
|
+
"@anthropic-ai/sdk": "^0.72.1",
|
|
93
|
+
"@apidevtools/json-schema-ref-parser": "^15.2.2",
|
|
94
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
95
|
+
"commander": "^14.0.3",
|
|
96
96
|
"ink": "^6.6.0",
|
|
97
97
|
"ink-text-input": "^6.0.0",
|
|
98
|
-
"inquirer": "^13.
|
|
98
|
+
"inquirer": "^13.2.2",
|
|
99
99
|
"js-yaml": "^4.1.1",
|
|
100
100
|
"ollama": "^0.6.3",
|
|
101
|
-
"openai": "^6.
|
|
102
|
-
"react": "^19.2.
|
|
101
|
+
"openai": "^6.17.0",
|
|
102
|
+
"react": "^19.2.4",
|
|
103
103
|
"uuid": "^13.0.0",
|
|
104
|
-
"zod": "^4.3.
|
|
104
|
+
"zod": "^4.3.6"
|
|
105
105
|
}
|
|
106
106
|
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E001: Missing Output Schema
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool does not declare an output schema
|
|
5
|
-
*
|
|
6
|
-
* Why this is fatal:
|
|
7
|
-
* - Downstream tools cannot reason about outputs
|
|
8
|
-
* - LLM will invent structure
|
|
9
|
-
* - Reproducibility is impossible
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
declare class E001MissingOutputSchemaRule extends BaseRule {
|
|
14
|
-
readonly id: "E001";
|
|
15
|
-
readonly severity: "error";
|
|
16
|
-
readonly ruleName = "Missing Output Schema";
|
|
17
|
-
readonly description = "Tool does not declare an output schema. Downstream tools cannot safely consume its output.";
|
|
18
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
19
|
-
}
|
|
20
|
-
export declare const E001MissingOutputSchema: E001MissingOutputSchemaRule;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=e001-missing-output-schema.d.ts.map
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E001: Missing Output Schema
|
|
3
|
-
*
|
|
4
|
-
* Condition: Tool does not declare an output schema
|
|
5
|
-
*
|
|
6
|
-
* Why this is fatal:
|
|
7
|
-
* - Downstream tools cannot reason about outputs
|
|
8
|
-
* - LLM will invent structure
|
|
9
|
-
* - Reproducibility is impossible
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
13
|
-
class E001MissingOutputSchemaRule extends BaseRule {
|
|
14
|
-
id = ERROR_CODES.E001;
|
|
15
|
-
severity = 'error';
|
|
16
|
-
ruleName = 'Missing Output Schema';
|
|
17
|
-
description = 'Tool does not declare an output schema. Downstream tools cannot safely consume its output.';
|
|
18
|
-
check(ctx) {
|
|
19
|
-
const diagnostics = [];
|
|
20
|
-
for (const tool of ctx.tools) {
|
|
21
|
-
// Check if tool has no output fields
|
|
22
|
-
if (!tool.outputs || tool.outputs.length === 0) {
|
|
23
|
-
diagnostics.push(this.createDiagnostic(`Tool "${tool.name}" has no output schema. Downstream tools cannot safely consume its output.`, tool.name, undefined, 'Add an output schema to the tool definition to specify the structure of the output.'));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return diagnostics;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
export const E001MissingOutputSchema = new E001MissingOutputSchemaRule();
|
|
30
|
-
//# sourceMappingURL=e001-missing-output-schema.js.map
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E002: Underspecified Required Input
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Input parameter is required AND
|
|
6
|
-
* - Type is broad (string, any, object) AND
|
|
7
|
-
* - No description, constraints, enum, regex, or example
|
|
8
|
-
*
|
|
9
|
-
* Why:
|
|
10
|
-
* - LLM will hallucinate values
|
|
11
|
-
* - Tool invocation becomes nondeterministic
|
|
12
|
-
*/
|
|
13
|
-
import { BaseRule } from '../base.js';
|
|
14
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
15
|
-
declare class E002UnderspecifiedRequiredInputRule extends BaseRule {
|
|
16
|
-
readonly id: "E002";
|
|
17
|
-
readonly severity: "error";
|
|
18
|
-
readonly ruleName = "Underspecified Required Input";
|
|
19
|
-
readonly description = "Required parameter is underspecified. LLM may pass invalid or ambiguous values.";
|
|
20
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
21
|
-
}
|
|
22
|
-
export declare const E002UnderspecifiedRequiredInput: E002UnderspecifiedRequiredInputRule;
|
|
23
|
-
export {};
|
|
24
|
-
//# sourceMappingURL=e002-underspecified-input.d.ts.map
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E002: Underspecified Required Input
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Input parameter is required AND
|
|
6
|
-
* - Type is broad (string, any, object) AND
|
|
7
|
-
* - No description, constraints, enum, regex, or example
|
|
8
|
-
*
|
|
9
|
-
* Why:
|
|
10
|
-
* - LLM will hallucinate values
|
|
11
|
-
* - Tool invocation becomes nondeterministic
|
|
12
|
-
*/
|
|
13
|
-
import { BaseRule } from '../base.js';
|
|
14
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
15
|
-
class E002UnderspecifiedRequiredInputRule extends BaseRule {
|
|
16
|
-
id = ERROR_CODES.E002;
|
|
17
|
-
severity = 'error';
|
|
18
|
-
ruleName = 'Underspecified Required Input';
|
|
19
|
-
description = 'Required parameter is underspecified. LLM may pass invalid or ambiguous values.';
|
|
20
|
-
check(ctx) {
|
|
21
|
-
const diagnostics = [];
|
|
22
|
-
// Broad types that need constraints
|
|
23
|
-
const broadTypes = new Set(['string', 'any', 'object']);
|
|
24
|
-
for (const tool of ctx.tools) {
|
|
25
|
-
for (const input of tool.inputs) {
|
|
26
|
-
// Check if type is broad
|
|
27
|
-
if (!broadTypes.has(input.type)) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
// Check if it has any constraints
|
|
31
|
-
const hasDescription = Boolean(input.description && input.description.trim());
|
|
32
|
-
const hasEnum = Boolean(input.enum && input.enum.length > 0);
|
|
33
|
-
const hasPattern = Boolean(input.pattern);
|
|
34
|
-
const hasExample = input.example !== undefined;
|
|
35
|
-
// If it's broad and has no constraints, it's underspecified
|
|
36
|
-
if (!hasDescription && !hasEnum && !hasPattern && !hasExample) {
|
|
37
|
-
if (input.required) {
|
|
38
|
-
// Required parameter without constraints - error
|
|
39
|
-
diagnostics.push(this.createDiagnostic(`Required parameter "${input.name}" in tool "${tool.name}" is underspecified. LLM may pass invalid or ambiguous values.`, tool.name, input.name, `Add constraints to "${input.name}": provide a description, enum values, regex pattern, or example.`));
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
// Optional parameter without constraints - flag as warning since it's less critical
|
|
43
|
-
diagnostics.push(this.createDiagnostic(`Optional parameter "${input.name}" in tool "${tool.name}" is underspecified. LLM may pass invalid or ambiguous values.`, tool.name, input.name, `Add constraints to "${input.name}": provide a description, enum values, regex pattern, or example.`, undefined, 'warning'));
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return diagnostics;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
export const E002UnderspecifiedRequiredInput = new E002UnderspecifiedRequiredInputRule();
|
|
52
|
-
//# sourceMappingURL=e002-underspecified-input.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E003: Unsafe Tool Chaining (Type Mismatch)
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool A output flows into Tool B input AND
|
|
6
|
-
* - Output type incompatible with input type
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Tool chains silently break
|
|
10
|
-
* - Bugs appear "random"
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
14
|
-
declare class E003TypeMismatchRule extends BaseRule {
|
|
15
|
-
readonly id: "E003";
|
|
16
|
-
readonly severity: "error";
|
|
17
|
-
readonly ruleName = "Unsafe Tool Chaining (Type Mismatch)";
|
|
18
|
-
readonly description = "Output type incompatible with downstream input type. Tool chains will break.";
|
|
19
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
20
|
-
}
|
|
21
|
-
export declare const E003TypeMismatch: E003TypeMismatchRule;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=e003-type-mismatch.d.ts.map
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E003: Unsafe Tool Chaining (Type Mismatch)
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool A output flows into Tool B input AND
|
|
6
|
-
* - Output type incompatible with input type
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Tool chains silently break
|
|
10
|
-
* - Bugs appear "random"
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
14
|
-
/**
|
|
15
|
-
* Check if two types are incompatible.
|
|
16
|
-
*/
|
|
17
|
-
function areTypesIncompatible(outputType, inputType) {
|
|
18
|
-
// Exact match is always compatible
|
|
19
|
-
if (outputType === inputType) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
// String can accept almost anything (it's broad)
|
|
23
|
-
if (inputType === 'string') {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
// Incompatible type pairs
|
|
27
|
-
const incompatiblePairs = [
|
|
28
|
-
['string', 'number'],
|
|
29
|
-
['string', 'boolean'],
|
|
30
|
-
['string', 'integer'],
|
|
31
|
-
['number', 'boolean'],
|
|
32
|
-
['boolean', 'number'],
|
|
33
|
-
['array', 'object'],
|
|
34
|
-
['object', 'array'],
|
|
35
|
-
];
|
|
36
|
-
for (const [from, to] of incompatiblePairs) {
|
|
37
|
-
if (outputType === from && inputType === to) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
class E003TypeMismatchRule extends BaseRule {
|
|
44
|
-
id = ERROR_CODES.E003;
|
|
45
|
-
severity = 'error';
|
|
46
|
-
ruleName = 'Unsafe Tool Chaining (Type Mismatch)';
|
|
47
|
-
description = 'Output type incompatible with downstream input type. Tool chains will break.';
|
|
48
|
-
check(ctx) {
|
|
49
|
-
const diagnostics = [];
|
|
50
|
-
// Only check high-confidence dependencies (>= 0.8)
|
|
51
|
-
const highConfidenceDeps = ctx.dependencies.filter(d => d.confidence >= 0.8);
|
|
52
|
-
for (const dep of highConfidenceDeps) {
|
|
53
|
-
// Find the output and input fields
|
|
54
|
-
const fromTool = ctx.indexes.toolIndex.get(dep.fromTool.toLowerCase());
|
|
55
|
-
const toTool = ctx.indexes.toolIndex.get(dep.toTool.toLowerCase());
|
|
56
|
-
if (!fromTool || !toTool) {
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
const fromField = fromTool.outputs.find(f => f.name === dep.fromField);
|
|
60
|
-
const toField = toTool.inputs.find(f => f.name === dep.toField);
|
|
61
|
-
if (!fromField || !toField) {
|
|
62
|
-
continue;
|
|
63
|
-
}
|
|
64
|
-
// Check type compatibility
|
|
65
|
-
if (areTypesIncompatible(fromField.type, toField.type)) {
|
|
66
|
-
diagnostics.push(this.createDiagnostic(`Tool "${dep.toTool}" parameter "${dep.toField}" depends on output from "${dep.fromTool}", but types are incompatible (${fromField.type} → ${toField.type}).`, dep.toTool, dep.toField, `Ensure "${dep.fromTool}" outputs ${toField.type}, or modify "${dep.toTool}" to accept ${fromField.type}.`));
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return diagnostics;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export const E003TypeMismatch = new E003TypeMismatchRule();
|
|
73
|
-
//# sourceMappingURL=e003-type-mismatch.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E004: Unsafe Tool Chaining (Free Text Propagation)
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output is unconstrained string
|
|
6
|
-
* - Used as input to another tool
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - LLM passes sentences instead of data
|
|
10
|
-
* - Most common real-world failure
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
14
|
-
declare class E004FreeTextPropagationRule extends BaseRule {
|
|
15
|
-
readonly id: "E004";
|
|
16
|
-
readonly severity: "error";
|
|
17
|
-
readonly ruleName = "Unsafe Tool Chaining (Free Text Propagation)";
|
|
18
|
-
readonly description = "Free-text output is used by another tool. This is unsafe without constraints.";
|
|
19
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
20
|
-
}
|
|
21
|
-
export declare const E004FreeTextPropagation: E004FreeTextPropagationRule;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=e004-free-text-propagation.d.ts.map
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E004: Unsafe Tool Chaining (Free Text Propagation)
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Output is unconstrained string
|
|
6
|
-
* - Used as input to another tool
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - LLM passes sentences instead of data
|
|
10
|
-
* - Most common real-world failure
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
14
|
-
class E004FreeTextPropagationRule extends BaseRule {
|
|
15
|
-
id = ERROR_CODES.E004;
|
|
16
|
-
severity = 'error';
|
|
17
|
-
ruleName = 'Unsafe Tool Chaining (Free Text Propagation)';
|
|
18
|
-
description = 'Free-text output is used by another tool. This is unsafe without constraints.';
|
|
19
|
-
check(ctx) {
|
|
20
|
-
const diagnostics = [];
|
|
21
|
-
// Only check high-confidence dependencies (>= 0.8)
|
|
22
|
-
const highConfidenceDeps = ctx.dependencies.filter(d => d.confidence >= 0.8);
|
|
23
|
-
for (const dep of highConfidenceDeps) {
|
|
24
|
-
// Find the output field
|
|
25
|
-
const fromTool = ctx.indexes.toolIndex.get(dep.fromTool.toLowerCase());
|
|
26
|
-
if (!fromTool) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const fromField = fromTool.outputs.find(f => f.name === dep.fromField);
|
|
30
|
-
if (!fromField) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
// Check if output is unconstrained string
|
|
34
|
-
const isString = fromField.type === 'string';
|
|
35
|
-
const hasEnum = Boolean(fromField.enum && fromField.enum.length > 0);
|
|
36
|
-
const hasPattern = Boolean(fromField.pattern);
|
|
37
|
-
const hasDescription = Boolean(fromField.description && fromField.description.trim());
|
|
38
|
-
// If it's a string with no constraints, it's free text
|
|
39
|
-
if (isString && !hasEnum && !hasPattern && !hasDescription) {
|
|
40
|
-
diagnostics.push(this.createDiagnostic(`Free-text output from "${dep.fromTool}" (field: "${dep.fromField}") is used by "${dep.toTool}". This is unsafe without constraints.`, dep.toTool, dep.toField, `Constrain the output of "${dep.fromTool}" by adding enum values, regex pattern, or clear description of expected format.`));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return diagnostics;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
export const E004FreeTextPropagation = new E004FreeTextPropagationRule();
|
|
47
|
-
//# sourceMappingURL=e004-free-text-propagation.js.map
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E005: Hard Tool Ambiguity
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Two or more tools:
|
|
6
|
-
* - Overlapping descriptions
|
|
7
|
-
* - Overlapping schemas
|
|
8
|
-
* - No clear differentiator
|
|
9
|
-
*
|
|
10
|
-
* Why:
|
|
11
|
-
* - Tool selection becomes nondeterministic
|
|
12
|
-
* - Agent behavior changes across runs/models
|
|
13
|
-
*/
|
|
14
|
-
import { BaseRule } from '../base.js';
|
|
15
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
16
|
-
declare class E005ToolAmbiguityRule extends BaseRule {
|
|
17
|
-
readonly id: "E005";
|
|
18
|
-
readonly severity: "error";
|
|
19
|
-
readonly ruleName = "Hard Tool Ambiguity";
|
|
20
|
-
readonly description = "Multiple tools match the same intent. LLM tool selection is ambiguous.";
|
|
21
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
22
|
-
}
|
|
23
|
-
export declare const E005ToolAmbiguity: E005ToolAmbiguityRule;
|
|
24
|
-
export {};
|
|
25
|
-
//# sourceMappingURL=e005-tool-ambiguity.d.ts.map
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E005: Hard Tool Ambiguity
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Two or more tools:
|
|
6
|
-
* - Overlapping descriptions
|
|
7
|
-
* - Overlapping schemas
|
|
8
|
-
* - No clear differentiator
|
|
9
|
-
*
|
|
10
|
-
* Why:
|
|
11
|
-
* - Tool selection becomes nondeterministic
|
|
12
|
-
* - Agent behavior changes across runs/models
|
|
13
|
-
*/
|
|
14
|
-
import { BaseRule } from '../base.js';
|
|
15
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
16
|
-
/**
|
|
17
|
-
* Calculate similarity between two sets of tokens.
|
|
18
|
-
*/
|
|
19
|
-
function tokenSimilarity(tokens1, tokens2) {
|
|
20
|
-
if (tokens1.size === 0 || tokens2.size === 0) {
|
|
21
|
-
return 0.0;
|
|
22
|
-
}
|
|
23
|
-
const intersection = new Set([...tokens1].filter(t => tokens2.has(t)));
|
|
24
|
-
const union = new Set([...tokens1, ...tokens2]);
|
|
25
|
-
return intersection.size / union.size;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Calculate schema overlap between two tools.
|
|
29
|
-
*/
|
|
30
|
-
function schemaOverlap(inputs1, inputs2) {
|
|
31
|
-
const names1 = new Set(inputs1.map(i => i.name.toLowerCase()));
|
|
32
|
-
const names2 = new Set(inputs2.map(i => i.name.toLowerCase()));
|
|
33
|
-
const nameOverlapSet = new Set([...names1].filter(n => names2.has(n)));
|
|
34
|
-
const nameOverlap = nameOverlapSet.size;
|
|
35
|
-
const totalNames = new Set([...names1, ...names2]).size;
|
|
36
|
-
if (totalNames === 0) {
|
|
37
|
-
return 0.0;
|
|
38
|
-
}
|
|
39
|
-
return nameOverlap / totalNames;
|
|
40
|
-
}
|
|
41
|
-
class E005ToolAmbiguityRule extends BaseRule {
|
|
42
|
-
id = ERROR_CODES.E005;
|
|
43
|
-
severity = 'error';
|
|
44
|
-
ruleName = 'Hard Tool Ambiguity';
|
|
45
|
-
description = 'Multiple tools match the same intent. LLM tool selection is ambiguous.';
|
|
46
|
-
check(ctx) {
|
|
47
|
-
const diagnostics = [];
|
|
48
|
-
for (let i = 0; i < ctx.tools.length; i++) {
|
|
49
|
-
const tool1 = ctx.tools[i];
|
|
50
|
-
if (!tool1)
|
|
51
|
-
continue;
|
|
52
|
-
for (let j = i + 1; j < ctx.tools.length; j++) {
|
|
53
|
-
const tool2 = ctx.tools[j];
|
|
54
|
-
if (!tool2)
|
|
55
|
-
continue;
|
|
56
|
-
// Calculate description similarity
|
|
57
|
-
const descSimilarity = tokenSimilarity(tool1.descriptionTokens, tool2.descriptionTokens);
|
|
58
|
-
// Calculate schema overlap
|
|
59
|
-
const inputOverlap = schemaOverlap(tool1.inputs, tool2.inputs);
|
|
60
|
-
const outputOverlap = schemaOverlap(tool1.outputs, tool2.outputs);
|
|
61
|
-
const schemaOverlapScore = (inputOverlap + outputOverlap) / 2;
|
|
62
|
-
// If both description and schema are very similar, it's ambiguous
|
|
63
|
-
// Threshold: >0.7 description similarity AND >0.5 schema overlap
|
|
64
|
-
if (descSimilarity > 0.7 && schemaOverlapScore > 0.5) {
|
|
65
|
-
diagnostics.push(this.createDiagnostic(`Multiple tools match the same intent: "${tool1.name}", "${tool2.name}". LLM tool selection is ambiguous.`, undefined, undefined, `Differentiate "${tool1.name}" and "${tool2.name}" by making their descriptions and schemas more distinct.`));
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return diagnostics;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
export const E005ToolAmbiguity = new E005ToolAmbiguityRule();
|
|
73
|
-
//# sourceMappingURL=e005-tool-ambiguity.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E006: Required Input Not Mentioned in Description
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Required input exists
|
|
6
|
-
* - Tool description does not reference it directly or indirectly
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - LLM does not know parameter exists or matters
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
13
|
-
declare class E006ParamNotInDescriptionRule extends BaseRule {
|
|
14
|
-
readonly id: "E006";
|
|
15
|
-
readonly severity: "error";
|
|
16
|
-
readonly ruleName = "Required Input Not Mentioned in Description";
|
|
17
|
-
readonly description = "Required parameter is not referenced in tool description. LLM may not know parameter exists.";
|
|
18
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
19
|
-
}
|
|
20
|
-
export declare const E006ParamNotInDescription: E006ParamNotInDescriptionRule;
|
|
21
|
-
export {};
|
|
22
|
-
//# sourceMappingURL=e006-param-not-in-description.d.ts.map
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E006: Required Input Not Mentioned in Description
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Required input exists
|
|
6
|
-
* - Tool description does not reference it directly or indirectly
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - LLM does not know parameter exists or matters
|
|
10
|
-
*/
|
|
11
|
-
import { BaseRule } from '../base.js';
|
|
12
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
13
|
-
/**
|
|
14
|
-
* Check if a parameter name appears in the description (case-insensitive).
|
|
15
|
-
*/
|
|
16
|
-
function isParameterMentioned(description, paramName) {
|
|
17
|
-
const descLower = description.toLowerCase();
|
|
18
|
-
const paramLower = paramName.toLowerCase();
|
|
19
|
-
// Exact match
|
|
20
|
-
if (descLower.includes(paramLower)) {
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
// Check if words from param name appear in description
|
|
24
|
-
const paramWords = paramLower.split(/\W+/).filter(w => w.length > 2);
|
|
25
|
-
const descWords = descLower.split(/\W+/);
|
|
26
|
-
for (const word of paramWords) {
|
|
27
|
-
if (descWords.includes(word)) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
class E006ParamNotInDescriptionRule extends BaseRule {
|
|
34
|
-
id = ERROR_CODES.E006;
|
|
35
|
-
severity = 'error';
|
|
36
|
-
ruleName = 'Required Input Not Mentioned in Description';
|
|
37
|
-
description = 'Required parameter is not referenced in tool description. LLM may not know parameter exists.';
|
|
38
|
-
check(ctx) {
|
|
39
|
-
const diagnostics = [];
|
|
40
|
-
for (const tool of ctx.tools) {
|
|
41
|
-
const description = tool.description || '';
|
|
42
|
-
for (const input of tool.inputs) {
|
|
43
|
-
// Only check required inputs
|
|
44
|
-
if (!input.required) {
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
// Check if parameter is mentioned in description
|
|
48
|
-
if (!isParameterMentioned(description, input.name)) {
|
|
49
|
-
diagnostics.push(this.createDiagnostic(`Required parameter "${input.name}" is not referenced in "${tool.name}" description.`, tool.name, input.name, `Mention "${input.name}" in the tool description so the LLM knows it exists and is required.`));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return diagnostics;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
export const E006ParamNotInDescription = new E006ParamNotInDescriptionRule();
|
|
57
|
-
//# sourceMappingURL=e006-param-not-in-description.js.map
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E007: Output Used Downstream but Not Guaranteed
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool output is optional / nullable
|
|
6
|
-
* - Used downstream without fallback
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Silent null propagation
|
|
10
|
-
* - Hard-to-debug failures
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import type { AnalysisContext, Diagnostic } from '../../types.js';
|
|
14
|
-
declare class E007OutputNotGuaranteedRule extends BaseRule {
|
|
15
|
-
readonly id: "E007";
|
|
16
|
-
readonly severity: "error";
|
|
17
|
-
readonly ruleName = "Output Used Downstream but Not Guaranteed";
|
|
18
|
-
readonly description = "Output of tool is not guaranteed, but is used by downstream tools without fallback.";
|
|
19
|
-
check(ctx: AnalysisContext): Diagnostic[];
|
|
20
|
-
}
|
|
21
|
-
export declare const E007OutputNotGuaranteed: E007OutputNotGuaranteedRule;
|
|
22
|
-
export {};
|
|
23
|
-
//# sourceMappingURL=e007-output-not-guaranteed.d.ts.map
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E007: Output Used Downstream but Not Guaranteed
|
|
3
|
-
*
|
|
4
|
-
* Condition:
|
|
5
|
-
* - Tool output is optional / nullable
|
|
6
|
-
* - Used downstream without fallback
|
|
7
|
-
*
|
|
8
|
-
* Why:
|
|
9
|
-
* - Silent null propagation
|
|
10
|
-
* - Hard-to-debug failures
|
|
11
|
-
*/
|
|
12
|
-
import { BaseRule } from '../base.js';
|
|
13
|
-
import { ERROR_CODES } from '../error-codes.js';
|
|
14
|
-
class E007OutputNotGuaranteedRule extends BaseRule {
|
|
15
|
-
id = ERROR_CODES.E007;
|
|
16
|
-
severity = 'error';
|
|
17
|
-
ruleName = 'Output Used Downstream but Not Guaranteed';
|
|
18
|
-
description = 'Output of tool is not guaranteed, but is used by downstream tools without fallback.';
|
|
19
|
-
check(ctx) {
|
|
20
|
-
const diagnostics = [];
|
|
21
|
-
// Only check high-confidence dependencies (>= 0.8)
|
|
22
|
-
const highConfidenceDeps = ctx.dependencies.filter(d => d.confidence >= 0.8);
|
|
23
|
-
for (const dep of highConfidenceDeps) {
|
|
24
|
-
// Find the output field
|
|
25
|
-
const fromTool = ctx.indexes.toolIndex.get(dep.fromTool.toLowerCase());
|
|
26
|
-
if (!fromTool) {
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
|
-
const fromField = fromTool.outputs.find(f => f.name === dep.fromField);
|
|
30
|
-
if (!fromField) {
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
// Find the downstream input field
|
|
34
|
-
const toTool = ctx.indexes.toolIndex.get(dep.toTool.toLowerCase());
|
|
35
|
-
if (!toTool) {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
const toField = toTool.inputs.find(f => f.name === dep.toField);
|
|
39
|
-
if (!toField) {
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
// Check if output is not guaranteed and downstream requires it without fallback
|
|
43
|
-
// Optional upstream always triggers when downstream requires it
|
|
44
|
-
// Nullable upstream only triggers when downstream is required AND not nullable (can't handle null)
|
|
45
|
-
if ((!fromField.required && toField.required === true) ||
|
|
46
|
-
(fromField.nullable === true &&
|
|
47
|
-
toField.required === true &&
|
|
48
|
-
toField.nullable !== true)) {
|
|
49
|
-
diagnostics.push(this.createDiagnostic(`Output of "${dep.fromTool}" (field: "${dep.fromField}") is nullable but is used by "${dep.toTool}" without fallback.`, dep.fromTool, dep.fromField, `Make the output of "${dep.fromTool}" non-nullable, or ensure "${dep.toTool}" handles null values.`));
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return diagnostics;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
export const E007OutputNotGuaranteed = new E007OutputNotGuaranteedRule();
|
|
56
|
-
//# sourceMappingURL=e007-output-not-guaranteed.js.map
|