@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/dist/config/schema.js
CHANGED
|
@@ -5,6 +5,20 @@
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { ConfigurationError } from '../utils/errors.js';
|
|
7
7
|
import { makeProjectName, makeAgentName, makeMCPURL, makeAPIKey, makeModelName, makeScriptCommand, makeSyrinVersion, } from '../types/factories.js';
|
|
8
|
+
/**
|
|
9
|
+
* Helper function to check if at least one LLM provider is set as default.
|
|
10
|
+
* @param llm - Record of LLM provider configurations
|
|
11
|
+
* @returns true if at least one provider has default === true
|
|
12
|
+
*/
|
|
13
|
+
function hasDefaultLLMProvider(llm) {
|
|
14
|
+
const providers = Object.values(llm);
|
|
15
|
+
return providers.some(provider => {
|
|
16
|
+
return (provider &&
|
|
17
|
+
typeof provider === 'object' &&
|
|
18
|
+
'default' in provider &&
|
|
19
|
+
provider.default === true);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
8
22
|
/**
|
|
9
23
|
* Schema for LLM provider configuration.
|
|
10
24
|
*/
|
|
@@ -86,14 +100,26 @@ export const ConfigSchema = z
|
|
|
86
100
|
message: 'script is required when transport is "stdio"',
|
|
87
101
|
path: ['script'],
|
|
88
102
|
})
|
|
89
|
-
.refine(data => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
.refine(data => hasDefaultLLMProvider(data.llm), {
|
|
104
|
+
message: 'At least one LLM provider must be set as default',
|
|
105
|
+
path: ['llm'],
|
|
106
|
+
});
|
|
107
|
+
/**
|
|
108
|
+
* Global configuration schema (LLM settings only).
|
|
109
|
+
* No transport, mcp_url, or script fields.
|
|
110
|
+
*/
|
|
111
|
+
export const GlobalConfigSchema = z
|
|
112
|
+
.object({
|
|
113
|
+
version: z.string().min(1, 'Version is required'),
|
|
114
|
+
project_name: z.literal('GlobalSyrin'),
|
|
115
|
+
agent_name: z.string().min(1, 'Agent name is required'),
|
|
116
|
+
llm: z
|
|
117
|
+
.record(z.string(), LLMProviderSchema)
|
|
118
|
+
.refine(obj => Object.keys(obj).length > 0, {
|
|
119
|
+
message: 'At least one LLM provider is required',
|
|
120
|
+
}),
|
|
121
|
+
})
|
|
122
|
+
.refine(data => hasDefaultLLMProvider(data.llm), {
|
|
97
123
|
message: 'At least one LLM provider must be set as default',
|
|
98
124
|
path: ['llm'],
|
|
99
125
|
});
|
|
@@ -178,4 +204,43 @@ export function validateConfig(config) {
|
|
|
178
204
|
throw error;
|
|
179
205
|
}
|
|
180
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Validate a global configuration object against the schema.
|
|
209
|
+
* @param config - Global configuration object to validate
|
|
210
|
+
* @returns Validated global configuration with opaque types
|
|
211
|
+
* @throws {ConfigurationError} If validation fails
|
|
212
|
+
*/
|
|
213
|
+
export function validateGlobalConfig(config) {
|
|
214
|
+
try {
|
|
215
|
+
const parsed = GlobalConfigSchema.parse(config);
|
|
216
|
+
// Transform to opaque types
|
|
217
|
+
// Note: project_name must be literal 'GlobalSyrin' for global config
|
|
218
|
+
const validated = {
|
|
219
|
+
version: makeSyrinVersion(parsed.version),
|
|
220
|
+
project_name: 'GlobalSyrin',
|
|
221
|
+
agent_name: makeAgentName(parsed.agent_name),
|
|
222
|
+
llm: Object.fromEntries(Object.entries(parsed.llm).map(([key, provider]) => [
|
|
223
|
+
key,
|
|
224
|
+
{
|
|
225
|
+
API_KEY: provider.API_KEY
|
|
226
|
+
? makeAPIKey(provider.API_KEY)
|
|
227
|
+
: undefined,
|
|
228
|
+
MODEL_NAME: provider.MODEL_NAME
|
|
229
|
+
? makeModelName(provider.MODEL_NAME)
|
|
230
|
+
: undefined,
|
|
231
|
+
default: provider.default,
|
|
232
|
+
},
|
|
233
|
+
])),
|
|
234
|
+
};
|
|
235
|
+
return validated;
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
if (error instanceof z.ZodError) {
|
|
239
|
+
throw new ConfigurationError(formatValidationError(error), {
|
|
240
|
+
context: { errors: error.issues },
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
181
246
|
//# sourceMappingURL=schema.js.map
|
package/dist/config/types.d.ts
CHANGED
|
@@ -50,6 +50,25 @@ export interface SyrinConfig {
|
|
|
50
50
|
/** Tool testing configuration (v1.3.0) */
|
|
51
51
|
check?: CheckConfig;
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* Global Syrin configuration (LLM settings only).
|
|
55
|
+
* Stored at ~/.syrin/syrin.yaml
|
|
56
|
+
*/
|
|
57
|
+
export interface GlobalSyrinConfig {
|
|
58
|
+
/** Configuration version */
|
|
59
|
+
version: SyrinVersion;
|
|
60
|
+
/** Project name (always "GlobalSyrin") */
|
|
61
|
+
project_name: 'GlobalSyrin';
|
|
62
|
+
/** Agent name (defaults to system username, can be customized) */
|
|
63
|
+
agent_name: AgentName;
|
|
64
|
+
/** LLM provider configurations */
|
|
65
|
+
llm: Record<string, LLMProviderConfig>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get default agent name from system.
|
|
69
|
+
* Tries: process.env.USER -> process.env.USERNAME -> os.userInfo().username -> 'Syrin'
|
|
70
|
+
*/
|
|
71
|
+
export declare function getDefaultAgentName(): string;
|
|
53
72
|
/**
|
|
54
73
|
* Options for initializing a new Syrin project.
|
|
55
74
|
*/
|
package/dist/config/types.js
CHANGED
|
@@ -2,5 +2,30 @@
|
|
|
2
2
|
* Configuration type definitions for Syrin.
|
|
3
3
|
* These types represent the structure of the syrin.yaml file.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
import * as os from 'os';
|
|
6
|
+
/**
|
|
7
|
+
* Get default agent name from system.
|
|
8
|
+
* Tries: process.env.USER -> process.env.USERNAME -> os.userInfo().username -> 'Syrin'
|
|
9
|
+
*/
|
|
10
|
+
export function getDefaultAgentName() {
|
|
11
|
+
// Try process.env first (safest)
|
|
12
|
+
if (process.env.USER) {
|
|
13
|
+
return process.env.USER;
|
|
14
|
+
}
|
|
15
|
+
if (process.env.USERNAME) {
|
|
16
|
+
return process.env.USERNAME;
|
|
17
|
+
}
|
|
18
|
+
// Try os.userInfo() with error handling (can throw on some platforms)
|
|
19
|
+
try {
|
|
20
|
+
const username = os.userInfo().username;
|
|
21
|
+
if (username) {
|
|
22
|
+
return username;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Swallow any exceptions from os.userInfo()
|
|
27
|
+
}
|
|
28
|
+
// Fallback to default
|
|
29
|
+
return 'Syrin';
|
|
30
|
+
}
|
|
6
31
|
//# sourceMappingURL=types.js.map
|
|
@@ -17,6 +17,13 @@ export declare const Messages: {
|
|
|
17
17
|
readonly INIT_SETUP_ENV_VARS: "Set up your environment variables (API keys, etc.)";
|
|
18
18
|
readonly INIT_RUN_DOCTOR: (doctorCommand: string) => string;
|
|
19
19
|
readonly INIT_RUN_DEV: (devCommand: string) => string;
|
|
20
|
+
readonly GLOBAL_INIT_ALREADY_INITIALIZED: "Global Syrin configuration already exists!";
|
|
21
|
+
readonly GLOBAL_INIT_CONFIG_FILE: (configPath: string) => string;
|
|
22
|
+
readonly GLOBAL_INIT_SUCCESS: "Global Syrin configuration created successfully!";
|
|
23
|
+
readonly GLOBAL_INIT_EDIT_CONFIG: "Run `syrin config edit --global` to edit the configuration";
|
|
24
|
+
readonly GLOBAL_INIT_EDIT_ENV: "Run `syrin config edit-env --global` to set API keys";
|
|
25
|
+
readonly GLOBAL_INIT_REINITIALIZE_TIP: "Want to re-initialize?";
|
|
26
|
+
readonly GLOBAL_INIT_REINITIALIZE_INSTRUCTION: "Delete ~/.syrin/syrin.yaml and run `syrin init --global` again.";
|
|
20
27
|
readonly ERROR_UNEXPECTED: "An unexpected error occurred";
|
|
21
28
|
readonly ERROR_LOADING_CONFIG: "Failed to load configuration file";
|
|
22
29
|
readonly ERROR_VALIDATION_FAILED: "Configuration validation failed";
|
|
@@ -19,6 +19,14 @@ export const Messages = {
|
|
|
19
19
|
INIT_SETUP_ENV_VARS: 'Set up your environment variables (API keys, etc.)',
|
|
20
20
|
INIT_RUN_DOCTOR: (doctorCommand) => `Run \`${doctorCommand}\` to verify your Syrin setup`,
|
|
21
21
|
INIT_RUN_DEV: (devCommand) => `Run \`${devCommand}\` to start development mode`,
|
|
22
|
+
// Global Init Command Messages
|
|
23
|
+
GLOBAL_INIT_ALREADY_INITIALIZED: 'Global Syrin configuration already exists!',
|
|
24
|
+
GLOBAL_INIT_CONFIG_FILE: (configPath) => `Configuration file: ${configPath}`,
|
|
25
|
+
GLOBAL_INIT_SUCCESS: 'Global Syrin configuration created successfully!',
|
|
26
|
+
GLOBAL_INIT_EDIT_CONFIG: 'Run `syrin config edit --global` to edit the configuration',
|
|
27
|
+
GLOBAL_INIT_EDIT_ENV: 'Run `syrin config edit-env --global` to set API keys',
|
|
28
|
+
GLOBAL_INIT_REINITIALIZE_TIP: 'Want to re-initialize?',
|
|
29
|
+
GLOBAL_INIT_REINITIALIZE_INSTRUCTION: 'Delete ~/.syrin/syrin.yaml and run `syrin init --global` again.',
|
|
22
30
|
// Error Messages
|
|
23
31
|
ERROR_UNEXPECTED: 'An unexpected error occurred',
|
|
24
32
|
ERROR_LOADING_CONFIG: 'Failed to load configuration file',
|
|
@@ -19,6 +19,12 @@ export declare const Paths: {
|
|
|
19
19
|
readonly DEV_HISTORY_FILE: ".syrin/.dev-history";
|
|
20
20
|
/** Data directory for JSON exports (relative to project root) */
|
|
21
21
|
readonly DATA_DIR: ".syrin/data";
|
|
22
|
+
/** Global Syrin configuration directory (absolute path) */
|
|
23
|
+
readonly GLOBAL_SYRIN_DIR: string;
|
|
24
|
+
/** Global configuration file (absolute path) - derived from GLOBAL_SYRIN_DIR */
|
|
25
|
+
readonly GLOBAL_CONFIG_FILE: string;
|
|
26
|
+
/** Global environment file (absolute path) - derived from GLOBAL_SYRIN_DIR */
|
|
27
|
+
readonly GLOBAL_ENV_FILE: string;
|
|
22
28
|
};
|
|
23
29
|
/**
|
|
24
30
|
* File extension constants.
|
package/dist/constants/paths.js
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
* File and directory path constants.
|
|
3
3
|
* Centralized paths used throughout the application.
|
|
4
4
|
*/
|
|
5
|
+
import * as os from 'os';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
// Compute global directory once
|
|
8
|
+
const GLOBAL_SYRIN_DIR = path.join(os.homedir(), '.syrin');
|
|
5
9
|
export const Paths = {
|
|
6
10
|
/** Syrin configuration directory name */
|
|
7
11
|
SYRIN_DIR: '.syrin',
|
|
@@ -19,6 +23,12 @@ export const Paths = {
|
|
|
19
23
|
DEV_HISTORY_FILE: '.syrin/.dev-history',
|
|
20
24
|
/** Data directory for JSON exports (relative to project root) */
|
|
21
25
|
DATA_DIR: '.syrin/data',
|
|
26
|
+
/** Global Syrin configuration directory (absolute path) */
|
|
27
|
+
GLOBAL_SYRIN_DIR,
|
|
28
|
+
/** Global configuration file (absolute path) - derived from GLOBAL_SYRIN_DIR */
|
|
29
|
+
GLOBAL_CONFIG_FILE: path.join(GLOBAL_SYRIN_DIR, 'syrin.yaml'),
|
|
30
|
+
/** Global environment file (absolute path) - derived from GLOBAL_SYRIN_DIR */
|
|
31
|
+
GLOBAL_ENV_FILE: path.join(GLOBAL_SYRIN_DIR, '.env'),
|
|
22
32
|
};
|
|
23
33
|
/**
|
|
24
34
|
* File extension constants.
|
package/dist/events/emitter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { makeEventID, makeTimestamp } from '../types/factories.js';
|
|
2
|
-
import {
|
|
2
|
+
import { log } from '../utils/logger.js';
|
|
3
3
|
import { EventStoreError } from '../utils/errors.js';
|
|
4
4
|
/**
|
|
5
5
|
* Runtime event emitter implementation.
|
|
@@ -37,7 +37,7 @@ export class RuntimeEventEmitter {
|
|
|
37
37
|
if (appendResult instanceof Promise) {
|
|
38
38
|
return appendResult
|
|
39
39
|
.then(() => {
|
|
40
|
-
|
|
40
|
+
log.debug(`Event emitted: ${eventType}`, {
|
|
41
41
|
event_id: event.event_id,
|
|
42
42
|
sequence: event.sequence,
|
|
43
43
|
});
|
|
@@ -47,7 +47,7 @@ export class RuntimeEventEmitter {
|
|
|
47
47
|
})
|
|
48
48
|
.catch((error) => {
|
|
49
49
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
50
|
-
|
|
50
|
+
log.error(`Error: ${err.message}`, err, {
|
|
51
51
|
event_id: event.event_id,
|
|
52
52
|
event_type: eventType,
|
|
53
53
|
});
|
|
@@ -59,7 +59,7 @@ export class RuntimeEventEmitter {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
// Sync store
|
|
62
|
-
|
|
62
|
+
log.debug(`Event emitted: ${eventType}`, {
|
|
63
63
|
event_id: event.event_id,
|
|
64
64
|
sequence: event.sequence,
|
|
65
65
|
});
|
|
@@ -69,7 +69,7 @@ export class RuntimeEventEmitter {
|
|
|
69
69
|
}
|
|
70
70
|
catch (error) {
|
|
71
71
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
72
|
-
|
|
72
|
+
log.error(`Error: ${err.message}`, err, {
|
|
73
73
|
event_id: event.event_id,
|
|
74
74
|
event_type: eventType,
|
|
75
75
|
});
|
|
@@ -119,7 +119,7 @@ export class RuntimeEventEmitter {
|
|
|
119
119
|
if (result instanceof Promise) {
|
|
120
120
|
result.catch((error) => {
|
|
121
121
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
122
|
-
|
|
122
|
+
log.error(`Error: ${err.message}`, err, {
|
|
123
123
|
event_id: event.event_id,
|
|
124
124
|
event_type: event.event_type,
|
|
125
125
|
});
|
|
@@ -128,7 +128,7 @@ export class RuntimeEventEmitter {
|
|
|
128
128
|
}
|
|
129
129
|
catch (error) {
|
|
130
130
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
131
|
-
|
|
131
|
+
log.error(`Error: ${err.message}`, err, {
|
|
132
132
|
event_id: event.event_id,
|
|
133
133
|
event_type: event.event_type,
|
|
134
134
|
});
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation layer for config command UI.
|
|
3
|
+
* Separates display logic from business logic.
|
|
4
|
+
*/
|
|
5
|
+
import type { SyrinConfig, GlobalSyrinConfig } from '../config/types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Display configuration list/show output.
|
|
8
|
+
*/
|
|
9
|
+
export declare function displayConfigList(config: SyrinConfig | GlobalSyrinConfig, context: 'local' | 'global', configPath: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Display success message for config update.
|
|
12
|
+
*/
|
|
13
|
+
export declare function displayConfigUpdated(key: string, value: string, context: 'local' | 'global', configPath: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Display message for opening editor.
|
|
16
|
+
*/
|
|
17
|
+
export declare function displayEditorOpening(context: 'local' | 'global', filePath: string, editorName: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Display message after editor closes.
|
|
20
|
+
*/
|
|
21
|
+
export declare function displayEditorClosed(fileType: 'config' | 'env'): void;
|
|
22
|
+
/**
|
|
23
|
+
* Display setup completion message.
|
|
24
|
+
*/
|
|
25
|
+
export declare function displaySetupComplete(isGlobal: boolean): void;
|
|
26
|
+
/**
|
|
27
|
+
* Display default provider set message.
|
|
28
|
+
*/
|
|
29
|
+
export declare function displayDefaultProviderSet(provider: string, context: 'local' | 'global'): void;
|
|
30
|
+
/**
|
|
31
|
+
* Display provider removed message.
|
|
32
|
+
*/
|
|
33
|
+
export declare function displayProviderRemoved(provider: string, context: 'local' | 'global'): void;
|
|
34
|
+
//# sourceMappingURL=config-ui.d.ts.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presentation layer for config command UI.
|
|
3
|
+
* Separates display logic from business logic.
|
|
4
|
+
*/
|
|
5
|
+
import { log } from '../utils/logger.js';
|
|
6
|
+
import { Icons } from '../constants/index.js';
|
|
7
|
+
import { getGlobalConfigPath } from '../config/global-loader.js';
|
|
8
|
+
/**
|
|
9
|
+
* Mask an API key to show only first 4 and last 4 characters.
|
|
10
|
+
*/
|
|
11
|
+
function maskApiKey(apiKey) {
|
|
12
|
+
if (!apiKey || apiKey.length <= 8) {
|
|
13
|
+
return '****';
|
|
14
|
+
}
|
|
15
|
+
// If it looks like an env var reference (e.g., OPENAI_API_KEY), don't mask
|
|
16
|
+
if (/^[A-Z][A-Z0-9_]*$/.test(apiKey)) {
|
|
17
|
+
return apiKey;
|
|
18
|
+
}
|
|
19
|
+
return `${apiKey.slice(0, 4)}...${apiKey.slice(-4)}`;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Display configuration list/show output.
|
|
23
|
+
*/
|
|
24
|
+
export function displayConfigList(config, context, configPath) {
|
|
25
|
+
log.blank();
|
|
26
|
+
log.heading(`${context === 'local' ? 'Local' : 'Global'} Configuration`);
|
|
27
|
+
log.blank();
|
|
28
|
+
log.labelValue(`${Icons.FOLDER} Path`, configPath);
|
|
29
|
+
log.blank();
|
|
30
|
+
if (context === 'local' && 'transport' in config) {
|
|
31
|
+
log.heading('Project Settings');
|
|
32
|
+
log.labelValue(' project_name', String(config.project_name));
|
|
33
|
+
log.labelValue(' agent_name', String(config.agent_name));
|
|
34
|
+
log.labelValue(' transport', config.transport);
|
|
35
|
+
if (config.mcp_url) {
|
|
36
|
+
log.labelValue(' mcp_url', String(config.mcp_url));
|
|
37
|
+
}
|
|
38
|
+
if (config.script) {
|
|
39
|
+
log.labelValue(' script', String(config.script));
|
|
40
|
+
}
|
|
41
|
+
log.blank();
|
|
42
|
+
}
|
|
43
|
+
log.heading('LLM Providers');
|
|
44
|
+
const providers = Object.entries(config.llm);
|
|
45
|
+
if (providers.length === 0) {
|
|
46
|
+
log.plain(' No providers configured');
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
for (const [provider, settings] of providers) {
|
|
50
|
+
const isDefault = settings.default || false;
|
|
51
|
+
const defaultMarker = isDefault ? ' (default)' : '';
|
|
52
|
+
log.label(` ${provider}${defaultMarker}`);
|
|
53
|
+
if (settings.API_KEY) {
|
|
54
|
+
log.labelValue(' API_KEY', maskApiKey(String(settings.API_KEY)));
|
|
55
|
+
}
|
|
56
|
+
if (settings.MODEL_NAME) {
|
|
57
|
+
log.labelValue(' MODEL_NAME', String(settings.MODEL_NAME));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
log.blank();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Display success message for config update.
|
|
65
|
+
*/
|
|
66
|
+
export function displayConfigUpdated(key, value, context, configPath) {
|
|
67
|
+
log.blank();
|
|
68
|
+
log.success(`${Icons.CHECK} Configuration updated successfully`);
|
|
69
|
+
log.blank();
|
|
70
|
+
log.labelValue(' Key', key);
|
|
71
|
+
log.labelValue(' Value', value);
|
|
72
|
+
log.labelValue(' Config', `${context} (${configPath})`);
|
|
73
|
+
log.blank();
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Display message for opening editor.
|
|
77
|
+
*/
|
|
78
|
+
export function displayEditorOpening(context, filePath, editorName) {
|
|
79
|
+
log.blank();
|
|
80
|
+
log.info(`Opening ${context} config in editor...`);
|
|
81
|
+
log.labelValue(` ${Icons.FOLDER} File`, filePath);
|
|
82
|
+
log.labelValue(` ${Icons.DOCUMENT} Editor`, editorName);
|
|
83
|
+
log.blank();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Display message after editor closes.
|
|
87
|
+
*/
|
|
88
|
+
export function displayEditorClosed(fileType) {
|
|
89
|
+
log.blank();
|
|
90
|
+
if (fileType === 'config') {
|
|
91
|
+
log.success(`Config file updated`);
|
|
92
|
+
log.blank();
|
|
93
|
+
log.info(`Run \`syrin doctor\` to validate your changes`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
log.success(`${Icons.CHECK} Environment file updated`);
|
|
97
|
+
}
|
|
98
|
+
log.blank();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Display setup completion message.
|
|
102
|
+
*/
|
|
103
|
+
export function displaySetupComplete(isGlobal) {
|
|
104
|
+
log.blank();
|
|
105
|
+
if (isGlobal) {
|
|
106
|
+
log.success(`${Icons.CHECK} Global configuration created`);
|
|
107
|
+
log.blank();
|
|
108
|
+
log.labelValue(` ${Icons.FOLDER} Config`, getGlobalConfigPath());
|
|
109
|
+
log.blank();
|
|
110
|
+
log.info(`${Icons.DOCUMENT} Next steps:`);
|
|
111
|
+
log.plain(' 1. Set your API keys in ~/.syrin/.env or as environment variables');
|
|
112
|
+
log.plain(' 2. Run `syrin config edit-env --global` to edit the environment file');
|
|
113
|
+
log.plain(' 3. Run `syrin doctor` to validate your setup');
|
|
114
|
+
}
|
|
115
|
+
log.blank();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Display default provider set message.
|
|
119
|
+
*/
|
|
120
|
+
export function displayDefaultProviderSet(provider, context) {
|
|
121
|
+
log.blank();
|
|
122
|
+
log.success(`${Icons.CHECK} Default provider updated`);
|
|
123
|
+
log.blank();
|
|
124
|
+
log.labelValue(' Provider', provider);
|
|
125
|
+
log.labelValue(' Config', context);
|
|
126
|
+
log.blank();
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Display provider removed message.
|
|
130
|
+
*/
|
|
131
|
+
export function displayProviderRemoved(provider, context) {
|
|
132
|
+
log.blank();
|
|
133
|
+
log.success(`${Icons.CHECK} Provider removed`);
|
|
134
|
+
log.blank();
|
|
135
|
+
log.labelValue(' Provider', provider);
|
|
136
|
+
log.labelValue(' Config', context);
|
|
137
|
+
log.blank();
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=config-ui.js.map
|
|
@@ -17,6 +17,9 @@ interface DoctorReport {
|
|
|
17
17
|
mcp_url?: unknown;
|
|
18
18
|
script?: unknown;
|
|
19
19
|
};
|
|
20
|
+
configSource?: 'local' | 'global';
|
|
21
|
+
configPath?: string;
|
|
22
|
+
envSource?: 'local.env' | 'global.env' | 'process.env';
|
|
20
23
|
transportCheck: CheckResult;
|
|
21
24
|
scriptCheck: CheckResult | null;
|
|
22
25
|
llmChecks: Array<{
|
|
@@ -31,6 +34,14 @@ interface DoctorReport {
|
|
|
31
34
|
modelName?: string;
|
|
32
35
|
}>;
|
|
33
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Display global config validation results.
|
|
39
|
+
*/
|
|
40
|
+
export declare function displayGlobalConfigValidation(globalConfigPath: string, globalEnvPath: string, globalEnvExists: boolean, llmChecks: Array<{
|
|
41
|
+
provider: string;
|
|
42
|
+
apiKeyCheck: CheckResult;
|
|
43
|
+
modelCheck: CheckResult;
|
|
44
|
+
}>): void;
|
|
34
45
|
/**
|
|
35
46
|
* Display doctor report using plain console output.
|
|
36
47
|
* This avoids Ink taking control of stdin, which disables terminal history.
|
|
@@ -1,11 +1,49 @@
|
|
|
1
1
|
import { getVersionDisplayString } from '../utils/version-display.js';
|
|
2
2
|
import { log } from '../utils/logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Display global config validation results.
|
|
5
|
+
*/
|
|
6
|
+
export function displayGlobalConfigValidation(globalConfigPath, globalEnvPath, globalEnvExists, llmChecks) {
|
|
7
|
+
log.blank();
|
|
8
|
+
log.heading('Validating Syrin configuration...');
|
|
9
|
+
log.blank();
|
|
10
|
+
log.label('No local config found at ./syrin.yaml');
|
|
11
|
+
log.label('Using global configuration...');
|
|
12
|
+
log.blank();
|
|
13
|
+
log.labelValue('Global Config:', globalConfigPath);
|
|
14
|
+
if (globalEnvExists) {
|
|
15
|
+
log.labelValue('Global Environment:', globalEnvPath);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
log.labelValue('Global Environment:', `${globalEnvPath} (not found)`);
|
|
19
|
+
}
|
|
20
|
+
log.blank();
|
|
21
|
+
const hasErrors = llmChecks.some(check => !check.apiKeyCheck.isValid || !check.modelCheck.isValid);
|
|
22
|
+
if (hasErrors) {
|
|
23
|
+
log.heading('Global configuration has issues:');
|
|
24
|
+
log.blank();
|
|
25
|
+
for (const check of llmChecks) {
|
|
26
|
+
if (!check.apiKeyCheck.isValid) {
|
|
27
|
+
log.plain(` • ${check.provider} API Key: ${check.apiKeyCheck.fix || 'Missing'}`);
|
|
28
|
+
}
|
|
29
|
+
if (!check.modelCheck.isValid) {
|
|
30
|
+
log.plain(` • ${check.provider} Model: ${check.modelCheck.fix || 'Missing'}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
log.blank();
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
log.success('Global configuration is valid!');
|
|
37
|
+
log.label('To create a local config, run: syrin init');
|
|
38
|
+
log.blank();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
3
41
|
/**
|
|
4
42
|
* Display doctor report using plain console output.
|
|
5
43
|
* This avoids Ink taking control of stdin, which disables terminal history.
|
|
6
44
|
*/
|
|
7
45
|
export async function displayDoctorReport(report) {
|
|
8
|
-
const { config, transportCheck, scriptCheck, llmChecks, localLlmChecks } = report;
|
|
46
|
+
const { config, configSource, configPath, envSource, transportCheck, scriptCheck, llmChecks, localLlmChecks, } = report;
|
|
9
47
|
const allValid = transportCheck.isValid &&
|
|
10
48
|
(scriptCheck === null || scriptCheck.isValid) &&
|
|
11
49
|
llmChecks.every(l => l.apiKeyCheck.isValid && l.modelCheck.isValid) &&
|
|
@@ -19,6 +57,19 @@ export async function displayDoctorReport(report) {
|
|
|
19
57
|
log.label('═══════════════════');
|
|
20
58
|
log.labelValue('Version:', versionDisplayString);
|
|
21
59
|
log.blank();
|
|
60
|
+
// Config Source Info
|
|
61
|
+
if (configSource && configPath) {
|
|
62
|
+
log.labelValue(`${configSource === 'local' ? 'Local' : 'Global'} Config:`, configPath);
|
|
63
|
+
if (envSource) {
|
|
64
|
+
const envSourceLabel = envSource === 'local.env'
|
|
65
|
+
? 'Local project .env file'
|
|
66
|
+
: envSource === 'global.env'
|
|
67
|
+
? 'Global .env file'
|
|
68
|
+
: 'process.env';
|
|
69
|
+
log.labelValue('Environment Source:', envSourceLabel);
|
|
70
|
+
}
|
|
71
|
+
log.blank();
|
|
72
|
+
}
|
|
22
73
|
// Project Info
|
|
23
74
|
log.labelValue('Project:', String(config.project_name));
|
|
24
75
|
log.labelValue('Agent:', String(config.agent_name));
|
|
@@ -11,4 +11,13 @@ export declare function displayAlreadyInitialized(): void;
|
|
|
11
11
|
* @param configPath - Path to the created config file
|
|
12
12
|
*/
|
|
13
13
|
export declare function displayInitSuccess(configPath: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Display the "global already initialized" message.
|
|
16
|
+
*/
|
|
17
|
+
export declare function displayGlobalAlreadyInitialized(): void;
|
|
18
|
+
/**
|
|
19
|
+
* Display the global initialization success message.
|
|
20
|
+
* @param configPath - Path to the created global config file
|
|
21
|
+
*/
|
|
22
|
+
export declare function displayGlobalInitSuccess(configPath: string): void;
|
|
14
23
|
//# sourceMappingURL=init-ui.d.ts.map
|
|
@@ -38,4 +38,37 @@ export function displayInitSuccess(configPath) {
|
|
|
38
38
|
log.plain(` 4. ${Messages.INIT_RUN_DEV(ToolCommands.DEV)}`);
|
|
39
39
|
log.blank();
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Display the "global already initialized" message.
|
|
43
|
+
*/
|
|
44
|
+
export function displayGlobalAlreadyInitialized() {
|
|
45
|
+
log.blank();
|
|
46
|
+
log.warning(` ${Messages.GLOBAL_INIT_ALREADY_INITIALIZED}`);
|
|
47
|
+
log.blank();
|
|
48
|
+
log.plain(`${Icons.FOLDER} ${Messages.GLOBAL_INIT_CONFIG_FILE(Paths.GLOBAL_CONFIG_FILE)}`);
|
|
49
|
+
log.blank();
|
|
50
|
+
log.plain(`${Icons.DOCUMENT} ${Messages.INIT_NEXT_STEPS_HEADER}`);
|
|
51
|
+
log.plain(` ${Messages.GLOBAL_INIT_EDIT_CONFIG}`);
|
|
52
|
+
log.plain(` ${Messages.GLOBAL_INIT_EDIT_ENV}`);
|
|
53
|
+
log.blank();
|
|
54
|
+
log.info(Messages.GLOBAL_INIT_REINITIALIZE_TIP);
|
|
55
|
+
log.plain(` ${Messages.GLOBAL_INIT_REINITIALIZE_INSTRUCTION}`);
|
|
56
|
+
log.blank();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Display the global initialization success message.
|
|
60
|
+
* @param configPath - Path to the created global config file
|
|
61
|
+
*/
|
|
62
|
+
export function displayGlobalInitSuccess(configPath) {
|
|
63
|
+
log.blank();
|
|
64
|
+
log.success(`${Icons.CHECK} ${Messages.GLOBAL_INIT_SUCCESS}`);
|
|
65
|
+
log.blank();
|
|
66
|
+
log.plain(`${Icons.FOLDER} Configuration file: ${configPath}`);
|
|
67
|
+
log.blank();
|
|
68
|
+
log.plain(`${Icons.DOCUMENT} ${Messages.INIT_NEXT_STEPS_HEADER}`);
|
|
69
|
+
log.plain(` 1. Set your API keys in ~/.syrin/.env or as environment variables`);
|
|
70
|
+
log.plain(` 2. Run \`syrin config edit-env --global\` to edit the environment file`);
|
|
71
|
+
log.plain(` 3. ${Messages.INIT_RUN_DOCTOR(ToolCommands.DOCTOR)}`);
|
|
72
|
+
log.blank();
|
|
73
|
+
}
|
|
41
74
|
//# sourceMappingURL=init-ui.js.map
|
|
@@ -7,7 +7,7 @@ import { normalizeTools } from './normalizer.js';
|
|
|
7
7
|
import { buildIndexes } from './indexer.js';
|
|
8
8
|
import { inferDependencies } from './dependencies.js';
|
|
9
9
|
import { ALL_RULES } from './rules/index.js';
|
|
10
|
-
import {
|
|
10
|
+
import { log } from '../../utils/logger.js';
|
|
11
11
|
/**
|
|
12
12
|
* Analyze MCP tools and return diagnostics.
|
|
13
13
|
* Executes all registered rules.
|
|
@@ -32,7 +32,7 @@ function runRules(tools, dependencies, indexes) {
|
|
|
32
32
|
}
|
|
33
33
|
catch (error) {
|
|
34
34
|
// If a rule fails, log error but don't crash the analysis
|
|
35
|
-
|
|
35
|
+
log.error(`Rule ${rule.id} failed`, error instanceof Error ? error : new Error(String(error)), {
|
|
36
36
|
ruleId: rule.id,
|
|
37
37
|
ruleName: rule.ruleName,
|
|
38
38
|
});
|
|
@@ -42,7 +42,7 @@ declare class W104GenericDescriptionRule extends BaseRule {
|
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
44
|
* ```ts
|
|
45
|
-
* import { createW104Rule, DEFAULT_CONCRETE_NOUNS } from './w005-generic-description
|
|
45
|
+
* import { createW104Rule, DEFAULT_CONCRETE_NOUNS } from './w005-generic-description';
|
|
46
46
|
* const customNouns = [...DEFAULT_CONCRETE_NOUNS, 'invoice', 'report'];
|
|
47
47
|
* const customRule = createW104Rule(customNouns);
|
|
48
48
|
* ```
|
|
@@ -96,7 +96,7 @@ class W104GenericDescriptionRule extends BaseRule {
|
|
|
96
96
|
*
|
|
97
97
|
* @example
|
|
98
98
|
* ```ts
|
|
99
|
-
* import { createW104Rule, DEFAULT_CONCRETE_NOUNS } from './w005-generic-description
|
|
99
|
+
* import { createW104Rule, DEFAULT_CONCRETE_NOUNS } from './w005-generic-description';
|
|
100
100
|
* const customNouns = [...DEFAULT_CONCRETE_NOUNS, 'invoice', 'report'];
|
|
101
101
|
* const customRule = createW104Rule(customNouns);
|
|
102
102
|
* ```
|