@syrin/cli 1.3.2 → 1.4.0
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 +36 -0
- 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 +1 -1
- 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/loader.js
CHANGED
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
-
import { load } from 'js-yaml';
|
|
7
|
+
import { load, dump } from 'js-yaml';
|
|
8
8
|
import { validateConfig } from './schema.js';
|
|
9
9
|
import { ConfigurationError } from '../utils/errors.js';
|
|
10
10
|
import { Paths, Messages, ToolCommands } from '../constants/index.js';
|
|
11
|
+
import { loadGlobalConfig } from './global-loader.js';
|
|
12
|
+
import { mergeConfigs, createConfigFromGlobal, } from './merger.js';
|
|
11
13
|
/**
|
|
12
14
|
* Load configuration from syrin.yaml file.
|
|
13
15
|
* @param projectRoot - Root directory of the project (defaults to current working directory)
|
|
@@ -15,13 +17,37 @@ import { Paths, Messages, ToolCommands } from '../constants/index.js';
|
|
|
15
17
|
* @throws {ConfigurationError} If config file is missing or invalid
|
|
16
18
|
*/
|
|
17
19
|
export function loadConfig(projectRoot = process.cwd()) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
const config = loadConfigOptional(projectRoot);
|
|
21
|
+
if (config === null) {
|
|
22
|
+
const configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
21
23
|
throw new ConfigurationError(Messages.ERROR_CONFIG_NOT_FOUND(ToolCommands.INIT), {
|
|
22
24
|
context: { projectRoot, configPath },
|
|
23
25
|
});
|
|
24
26
|
}
|
|
27
|
+
return config;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if a configuration file exists.
|
|
31
|
+
* @param projectRoot - Root directory of the project
|
|
32
|
+
* @returns true if config file exists
|
|
33
|
+
*/
|
|
34
|
+
export function configExists(projectRoot = process.cwd()) {
|
|
35
|
+
const configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
36
|
+
return fs.existsSync(configPath);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Load configuration from syrin.yaml file (optional).
|
|
40
|
+
* Returns null if file doesn't exist instead of throwing.
|
|
41
|
+
* @param projectRoot - Root directory of the project (defaults to current working directory)
|
|
42
|
+
* @returns Loaded and validated configuration, or null if file doesn't exist
|
|
43
|
+
* @throws {ConfigurationError} If config file exists but is invalid
|
|
44
|
+
*/
|
|
45
|
+
export function loadConfigOptional(projectRoot = process.cwd()) {
|
|
46
|
+
const configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
47
|
+
// Check if config file exists
|
|
48
|
+
if (!fs.existsSync(configPath)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
25
51
|
try {
|
|
26
52
|
// Read and parse YAML file
|
|
27
53
|
const configContent = fs.readFileSync(configPath, 'utf-8');
|
|
@@ -46,12 +72,72 @@ export function loadConfig(projectRoot = process.cwd()) {
|
|
|
46
72
|
}
|
|
47
73
|
}
|
|
48
74
|
/**
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* @
|
|
75
|
+
* Load configuration with global fallback.
|
|
76
|
+
* Tries local config first, then global config, then throws error.
|
|
77
|
+
* @param projectRoot - Root directory of the project (defaults to current working directory)
|
|
78
|
+
* @param flags - CLI flags that can override config values
|
|
79
|
+
* @returns Loaded and merged configuration
|
|
80
|
+
* @throws {Error} If neither local nor global config exists
|
|
52
81
|
*/
|
|
53
|
-
export function
|
|
82
|
+
export function loadConfigWithGlobal(projectRoot = process.cwd(), flags = {}) {
|
|
83
|
+
const localConfig = loadConfigOptional(projectRoot);
|
|
84
|
+
const globalConfig = loadGlobalConfig();
|
|
85
|
+
if (localConfig) {
|
|
86
|
+
return { config: mergeConfigs(localConfig, globalConfig), source: 'local' };
|
|
87
|
+
}
|
|
88
|
+
if (globalConfig) {
|
|
89
|
+
const adaptedConfig = createConfigFromGlobal(globalConfig, flags);
|
|
90
|
+
return { config: adaptedConfig, source: 'global' };
|
|
91
|
+
}
|
|
92
|
+
throw new ConfigurationError(Messages.ERROR_CONFIG_NOT_FOUND(ToolCommands.INIT), {
|
|
93
|
+
context: { projectRoot },
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Save local configuration to syrin.yaml file.
|
|
98
|
+
* @param config - Configuration to save
|
|
99
|
+
* @param projectRoot - Root directory of the project (defaults to current working directory)
|
|
100
|
+
* @throws {ConfigurationError} If saving fails
|
|
101
|
+
*/
|
|
102
|
+
export function saveLocalConfig(config, projectRoot = process.cwd()) {
|
|
54
103
|
const configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
55
|
-
|
|
104
|
+
try {
|
|
105
|
+
// Convert config to plain object for YAML serialization
|
|
106
|
+
const configObject = {
|
|
107
|
+
version: config.version,
|
|
108
|
+
project_name: config.project_name,
|
|
109
|
+
agent_name: config.agent_name,
|
|
110
|
+
transport: config.transport,
|
|
111
|
+
...(config.mcp_url ? { mcp_url: config.mcp_url } : {}),
|
|
112
|
+
...(config.script ? { script: config.script } : {}),
|
|
113
|
+
llm: Object.fromEntries(Object.entries(config.llm).map(([key, provider]) => [
|
|
114
|
+
key,
|
|
115
|
+
{
|
|
116
|
+
...(provider.API_KEY !== undefined
|
|
117
|
+
? { API_KEY: provider.API_KEY }
|
|
118
|
+
: {}),
|
|
119
|
+
...(provider.MODEL_NAME !== undefined
|
|
120
|
+
? { MODEL_NAME: provider.MODEL_NAME }
|
|
121
|
+
: {}),
|
|
122
|
+
default: provider.default,
|
|
123
|
+
},
|
|
124
|
+
])),
|
|
125
|
+
...(config.check ? { check: config.check } : {}),
|
|
126
|
+
};
|
|
127
|
+
// Serialize to YAML
|
|
128
|
+
const yamlContent = dump(configObject, {
|
|
129
|
+
indent: 2,
|
|
130
|
+
lineWidth: 100,
|
|
131
|
+
quotingType: '"',
|
|
132
|
+
});
|
|
133
|
+
// Write to file
|
|
134
|
+
fs.writeFileSync(configPath, yamlContent, 'utf-8');
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
throw new ConfigurationError(`Failed to save local configuration: ${error instanceof Error ? error.message : String(error)}`, {
|
|
138
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
139
|
+
context: { configPath },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
56
142
|
}
|
|
57
143
|
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration merger.
|
|
3
|
+
* Merges local and global configurations with proper precedence.
|
|
4
|
+
*/
|
|
5
|
+
import type { SyrinConfig, GlobalSyrinConfig } from './types.js';
|
|
6
|
+
/**
|
|
7
|
+
* CLI flags that can override config values.
|
|
8
|
+
*/
|
|
9
|
+
export interface CLIConfigFlags {
|
|
10
|
+
/** Transport type override */
|
|
11
|
+
transport?: 'stdio' | 'http';
|
|
12
|
+
/** MCP URL override (for http transport) */
|
|
13
|
+
mcp_url?: string;
|
|
14
|
+
/** Script command override (for stdio transport) */
|
|
15
|
+
script?: string;
|
|
16
|
+
/** LLM provider override */
|
|
17
|
+
llm?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Merge local and global configurations.
|
|
21
|
+
* Local LLM providers override global, but other global providers are kept.
|
|
22
|
+
* @param local - Local configuration (from ./syrin.yaml) or null
|
|
23
|
+
* @param global - Global configuration (from ~/.syrin/syrin.yaml) or null
|
|
24
|
+
* @param flags - CLI flags that override config values
|
|
25
|
+
* @returns Merged configuration
|
|
26
|
+
* @throws {Error} If neither local nor global config exists
|
|
27
|
+
*/
|
|
28
|
+
export declare function mergeConfigs(local: SyrinConfig | null, global: GlobalSyrinConfig | null, flags?: CLIConfigFlags): SyrinConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Create a full SyrinConfig from global config and CLI flags.
|
|
31
|
+
* @param global - Global configuration
|
|
32
|
+
* @param flags - CLI flags that provide required fields
|
|
33
|
+
* @returns Full configuration
|
|
34
|
+
* @throws {Error} If required fields are missing
|
|
35
|
+
*/
|
|
36
|
+
export declare function createConfigFromGlobal(global: GlobalSyrinConfig, flags?: CLIConfigFlags): SyrinConfig;
|
|
37
|
+
//# sourceMappingURL=merger.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration merger.
|
|
3
|
+
* Merges local and global configurations with proper precedence.
|
|
4
|
+
*/
|
|
5
|
+
import { makeProjectName, makeMCPURL, makeScriptCommand, } from '../types/factories.js';
|
|
6
|
+
/**
|
|
7
|
+
* Merge local and global configurations.
|
|
8
|
+
* Local LLM providers override global, but other global providers are kept.
|
|
9
|
+
* @param local - Local configuration (from ./syrin.yaml) or null
|
|
10
|
+
* @param global - Global configuration (from ~/.syrin/syrin.yaml) or null
|
|
11
|
+
* @param flags - CLI flags that override config values
|
|
12
|
+
* @returns Merged configuration
|
|
13
|
+
* @throws {Error} If neither local nor global config exists
|
|
14
|
+
*/
|
|
15
|
+
export function mergeConfigs(local, global, flags = {}) {
|
|
16
|
+
// If local config exists, use it as base and merge LLM providers
|
|
17
|
+
if (local) {
|
|
18
|
+
const mergedLLM = {
|
|
19
|
+
...(global?.llm || {}), // Start with global LLM providers
|
|
20
|
+
...local.llm, // Override with local LLM providers
|
|
21
|
+
};
|
|
22
|
+
// Apply CLI flag overrides
|
|
23
|
+
const finalConfig = {
|
|
24
|
+
...local,
|
|
25
|
+
llm: mergedLLM,
|
|
26
|
+
transport: flags.transport || local.transport,
|
|
27
|
+
mcp_url: flags.mcp_url ? makeMCPURL(flags.mcp_url) : local.mcp_url,
|
|
28
|
+
script: flags.script ? makeScriptCommand(flags.script) : local.script,
|
|
29
|
+
};
|
|
30
|
+
return finalConfig;
|
|
31
|
+
}
|
|
32
|
+
// No local config - create from global with defaults
|
|
33
|
+
if (!global) {
|
|
34
|
+
throw new Error('No configuration found. Create a local config with `syrin init` or set up global config with `syrin init --global`.');
|
|
35
|
+
}
|
|
36
|
+
// Create config from global
|
|
37
|
+
return createConfigFromGlobal(global, flags);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a full SyrinConfig from global config and CLI flags.
|
|
41
|
+
* @param global - Global configuration
|
|
42
|
+
* @param flags - CLI flags that provide required fields
|
|
43
|
+
* @returns Full configuration
|
|
44
|
+
* @throws {Error} If required fields are missing
|
|
45
|
+
*/
|
|
46
|
+
export function createConfigFromGlobal(global, flags = {}) {
|
|
47
|
+
// Transport is required - must come from flags
|
|
48
|
+
if (!flags.transport) {
|
|
49
|
+
throw new Error('Transport type is required when using global config. Use --transport <stdio|http> flag.');
|
|
50
|
+
}
|
|
51
|
+
// Validate transport-specific requirements
|
|
52
|
+
if (flags.transport === 'http' && !flags.mcp_url) {
|
|
53
|
+
throw new Error('MCP URL is required for HTTP transport. Use --mcp-url <url> flag.');
|
|
54
|
+
}
|
|
55
|
+
if (flags.transport === 'stdio' && !flags.script) {
|
|
56
|
+
throw new Error('Script command is required for stdio transport. Use --script <command> flag.');
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
version: global.version,
|
|
60
|
+
project_name: makeProjectName('GlobalSyrin'),
|
|
61
|
+
agent_name: global.agent_name,
|
|
62
|
+
transport: flags.transport,
|
|
63
|
+
mcp_url: flags.mcp_url ? makeMCPURL(flags.mcp_url) : undefined,
|
|
64
|
+
script: flags.script ? makeScriptCommand(flags.script) : undefined,
|
|
65
|
+
llm: global.llm,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=merger.js.map
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Provides runtime validation for the Syrin configuration file.
|
|
4
4
|
*/
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
-
import type { SyrinConfig } from '../config/types.js';
|
|
6
|
+
import type { SyrinConfig, GlobalSyrinConfig } from '../config/types.js';
|
|
7
7
|
/**
|
|
8
8
|
* Main configuration schema.
|
|
9
9
|
*/
|
|
@@ -38,5 +38,30 @@ export declare const ConfigSchema: z.ZodObject<{
|
|
|
38
38
|
* Type inference from schema.
|
|
39
39
|
*/
|
|
40
40
|
export type ConfigSchemaType = z.infer<typeof ConfigSchema>;
|
|
41
|
+
/**
|
|
42
|
+
* Global configuration schema (LLM settings only).
|
|
43
|
+
* No transport, mcp_url, or script fields.
|
|
44
|
+
*/
|
|
45
|
+
export declare const GlobalConfigSchema: z.ZodObject<{
|
|
46
|
+
version: z.ZodString;
|
|
47
|
+
project_name: z.ZodLiteral<"GlobalSyrin">;
|
|
48
|
+
agent_name: z.ZodString;
|
|
49
|
+
llm: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
50
|
+
API_KEY: z.ZodOptional<z.ZodString>;
|
|
51
|
+
MODEL_NAME: z.ZodOptional<z.ZodString>;
|
|
52
|
+
default: z.ZodOptional<z.ZodBoolean>;
|
|
53
|
+
}, z.core.$strip>>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
/**
|
|
56
|
+
* Type inference from global schema.
|
|
57
|
+
*/
|
|
58
|
+
export type GlobalConfigSchemaType = z.infer<typeof GlobalConfigSchema>;
|
|
41
59
|
export declare function validateConfig(config: unknown): SyrinConfig;
|
|
60
|
+
/**
|
|
61
|
+
* Validate a global configuration object against the schema.
|
|
62
|
+
* @param config - Global configuration object to validate
|
|
63
|
+
* @returns Validated global configuration with opaque types
|
|
64
|
+
* @throws {ConfigurationError} If validation fails
|
|
65
|
+
*/
|
|
66
|
+
export declare function validateGlobalConfig(config: unknown): GlobalSyrinConfig;
|
|
42
67
|
//# sourceMappingURL=schema.d.ts.map
|
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
|