@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
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
* `syrin doctor` command implementation.
|
|
3
3
|
* Validates the Syrin project configuration and setup.
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { loadConfigOptional } from '../../config/loader.js';
|
|
6
6
|
import { checkEnvVar, checkCommandExists, extractCommandName, } from '../../config/env-checker.js';
|
|
7
7
|
import { handleCommandError } from '../../cli/utils/index.js';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { showVersionBanner } from '../../cli/utils/version-banner.js';
|
|
9
|
+
import { Messages, TransportTypes, Defaults, LLMProviders, Paths, } from '../../constants/index.js';
|
|
10
|
+
import { displayDoctorReport, displayGlobalConfigValidation, } from '../../presentation/doctor-ui.js';
|
|
11
|
+
import { loadGlobalConfig, getGlobalConfigPath, getGlobalEnvPath, } from '../../config/global-loader.js';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
import * as fs from 'fs';
|
|
14
|
+
import * as os from 'os';
|
|
10
15
|
/**
|
|
11
16
|
* Check transport configuration.
|
|
12
17
|
*/
|
|
@@ -92,7 +97,7 @@ function checkScript(config) {
|
|
|
92
97
|
/**
|
|
93
98
|
* Check LLM provider configuration.
|
|
94
99
|
*/
|
|
95
|
-
function checkLLMProviders(config, projectRoot) {
|
|
100
|
+
function checkLLMProviders(config, projectRoot, isGlobalContext = false) {
|
|
96
101
|
const checks = [];
|
|
97
102
|
for (const [providerName, providerConfig] of Object.entries(config.llm)) {
|
|
98
103
|
if (providerName === LLMProviders.OLLAMA) {
|
|
@@ -106,8 +111,8 @@ function checkLLMProviders(config, projectRoot) {
|
|
|
106
111
|
const modelVar = providerConfig.MODEL_NAME
|
|
107
112
|
? String(providerConfig.MODEL_NAME)
|
|
108
113
|
: '';
|
|
109
|
-
const apiKeyCheck = checkEnvVar(apiKeyVar, projectRoot);
|
|
110
|
-
const modelCheck = checkEnvVar(modelVar, projectRoot);
|
|
114
|
+
const apiKeyCheck = checkEnvVar(apiKeyVar, projectRoot, isGlobalContext);
|
|
115
|
+
const modelCheck = checkEnvVar(modelVar, projectRoot, isGlobalContext);
|
|
111
116
|
checks.push({
|
|
112
117
|
provider: providerName,
|
|
113
118
|
apiKeyCheck: {
|
|
@@ -128,6 +133,7 @@ function checkLLMProviders(config, projectRoot) {
|
|
|
128
133
|
: modelCheck.errorMessage || Messages.ENV_SET_INSTRUCTIONS(modelVar),
|
|
129
134
|
},
|
|
130
135
|
isDefault: providerConfig.default === true,
|
|
136
|
+
envSource: apiKeyCheck.source || modelCheck.source,
|
|
131
137
|
});
|
|
132
138
|
}
|
|
133
139
|
return checks;
|
|
@@ -135,7 +141,7 @@ function checkLLMProviders(config, projectRoot) {
|
|
|
135
141
|
/**
|
|
136
142
|
* Check local LLM providers.
|
|
137
143
|
*/
|
|
138
|
-
function checkLocalLLMProviders(config, projectRoot) {
|
|
144
|
+
function checkLocalLLMProviders(config, projectRoot, isGlobalContext = false) {
|
|
139
145
|
const checks = [];
|
|
140
146
|
for (const [providerName, providerConfig] of Object.entries(config.llm)) {
|
|
141
147
|
if (providerName === LLMProviders.OLLAMA) {
|
|
@@ -143,7 +149,7 @@ function checkLocalLLMProviders(config, projectRoot) {
|
|
|
143
149
|
const modelVar = providerConfig.MODEL_NAME
|
|
144
150
|
? String(providerConfig.MODEL_NAME)
|
|
145
151
|
: '';
|
|
146
|
-
const modelCheck = checkEnvVar(modelVar, projectRoot);
|
|
152
|
+
const modelCheck = checkEnvVar(modelVar, projectRoot, isGlobalContext);
|
|
147
153
|
checks.push({
|
|
148
154
|
provider: providerName,
|
|
149
155
|
check: {
|
|
@@ -159,12 +165,18 @@ function checkLocalLLMProviders(config, projectRoot) {
|
|
|
159
165
|
/**
|
|
160
166
|
* Generate doctor report.
|
|
161
167
|
*/
|
|
162
|
-
function generateReport(config, projectRoot) {
|
|
168
|
+
function generateReport(config, projectRoot, configSource, configPath) {
|
|
169
|
+
// Call checkLLMProviders once and reuse the result
|
|
170
|
+
const llmChecks = checkLLMProviders(config, projectRoot);
|
|
171
|
+
const envSource = llmChecks[0]?.envSource;
|
|
163
172
|
return {
|
|
164
173
|
config,
|
|
174
|
+
configSource,
|
|
175
|
+
configPath,
|
|
176
|
+
envSource,
|
|
165
177
|
transportCheck: checkTransport(config),
|
|
166
178
|
scriptCheck: checkScript(config),
|
|
167
|
-
llmChecks
|
|
179
|
+
llmChecks,
|
|
168
180
|
localLlmChecks: checkLocalLLMProviders(config, projectRoot),
|
|
169
181
|
};
|
|
170
182
|
}
|
|
@@ -173,11 +185,35 @@ function generateReport(config, projectRoot) {
|
|
|
173
185
|
* @param projectRoot - Project root directory (defaults to current working directory)
|
|
174
186
|
*/
|
|
175
187
|
export async function executeDoctor(projectRoot = process.cwd()) {
|
|
188
|
+
await showVersionBanner();
|
|
176
189
|
try {
|
|
177
|
-
//
|
|
178
|
-
const
|
|
190
|
+
// Try to load local config first
|
|
191
|
+
const localConfig = loadConfigOptional(projectRoot);
|
|
192
|
+
const globalConfig = loadGlobalConfig();
|
|
193
|
+
let config;
|
|
194
|
+
let configSource;
|
|
195
|
+
let configPath;
|
|
196
|
+
if (localConfig) {
|
|
197
|
+
config = localConfig;
|
|
198
|
+
configSource = 'local';
|
|
199
|
+
configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
200
|
+
}
|
|
201
|
+
else if (globalConfig) {
|
|
202
|
+
// Validate global config (including LLM providers)
|
|
203
|
+
const globalEnvPath = getGlobalEnvPath();
|
|
204
|
+
const globalEnvExists = fs.existsSync(globalEnvPath);
|
|
205
|
+
// Run LLM validation for global config (using home directory as project root)
|
|
206
|
+
const globalProjectRoot = os.homedir();
|
|
207
|
+
const llmChecks = checkLLMProviders(globalConfig, globalProjectRoot, true);
|
|
208
|
+
// Display validation results using presentation layer
|
|
209
|
+
displayGlobalConfigValidation(getGlobalConfigPath(), globalEnvPath, globalEnvExists, llmChecks);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
throw new Error('No configuration found. Create a local config with `syrin init` or set up global config with `syrin init --global`.');
|
|
214
|
+
}
|
|
179
215
|
// Generate report
|
|
180
|
-
const report = generateReport(config, projectRoot);
|
|
216
|
+
const report = generateReport(config, projectRoot, configSource, configPath);
|
|
181
217
|
// Display report using Ink UI
|
|
182
218
|
await displayDoctorReport(report);
|
|
183
219
|
// Exit with appropriate code
|
|
@@ -7,6 +7,8 @@ export interface InitCommandOptions {
|
|
|
7
7
|
yes?: boolean;
|
|
8
8
|
/** Project root directory (defaults to current working directory) */
|
|
9
9
|
projectRoot?: string;
|
|
10
|
+
/** Create global configuration (LLM providers only) */
|
|
11
|
+
global?: boolean;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Execute the init command.
|
|
@@ -3,19 +3,26 @@
|
|
|
3
3
|
* Initializes a new Syrin project with configuration.
|
|
4
4
|
*/
|
|
5
5
|
import { generateConfigFile, isProjectInitialized } from '../../config/generator.js';
|
|
6
|
-
import { promptInitOptions, getDefaultInitOptions, } from '../../cli/prompts/init-prompt.js';
|
|
6
|
+
import { promptInitOptions, getDefaultInitOptions, promptGlobalInitOptions, getDefaultGlobalInitOptions, } from '../../cli/prompts/init-prompt.js';
|
|
7
7
|
import { ConfigurationError } from '../../utils/errors.js';
|
|
8
|
-
import {
|
|
8
|
+
import { log } from '../../utils/logger.js';
|
|
9
9
|
import { Messages, Paths } from '../../constants/index.js';
|
|
10
10
|
import { ensureGitignorePattern } from '../../utils/gitignore.js';
|
|
11
|
-
import { displayAlreadyInitialized, displayInitSuccess, } from '../../presentation/init-ui.js';
|
|
11
|
+
import { displayAlreadyInitialized, displayInitSuccess, displayGlobalAlreadyInitialized, displayGlobalInitSuccess, } from '../../presentation/init-ui.js';
|
|
12
12
|
import { showVersionBanner } from '../../cli/utils/version-banner.js';
|
|
13
|
+
import { globalConfigExists, saveGlobalConfig, getGlobalConfigPath, } from '../../config/global-loader.js';
|
|
14
|
+
import { makeSyrinVersion, makeAPIKey, makeModelName } from '../../types/factories.js';
|
|
13
15
|
/**
|
|
14
16
|
* Execute the init command.
|
|
15
17
|
* @param options - Command options
|
|
16
18
|
*/
|
|
17
19
|
export async function executeInit(options = {}) {
|
|
18
20
|
await showVersionBanner();
|
|
21
|
+
// Handle global init
|
|
22
|
+
if (options.global) {
|
|
23
|
+
await executeGlobalInit(options);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
19
26
|
const projectRoot = options.projectRoot || process.cwd();
|
|
20
27
|
// Check if project is already initialized
|
|
21
28
|
if (isProjectInitialized(projectRoot)) {
|
|
@@ -26,19 +33,19 @@ export async function executeInit(options = {}) {
|
|
|
26
33
|
let initOptions;
|
|
27
34
|
if (options.yes) {
|
|
28
35
|
// Non-interactive mode: use defaults
|
|
29
|
-
|
|
36
|
+
log.info('Initializing project with default values (non-interactive mode)');
|
|
30
37
|
initOptions = getDefaultInitOptions(projectRoot);
|
|
31
38
|
}
|
|
32
39
|
else {
|
|
33
40
|
// Interactive mode: prompt user
|
|
34
|
-
|
|
41
|
+
log.info('Starting interactive project initialization');
|
|
35
42
|
try {
|
|
36
43
|
initOptions = await promptInitOptions();
|
|
37
44
|
}
|
|
38
45
|
catch (error) {
|
|
39
46
|
if (error instanceof Error && error.name === 'ExitPromptError') {
|
|
40
47
|
// User cancelled
|
|
41
|
-
|
|
48
|
+
log.info('Initialization cancelled by user');
|
|
42
49
|
process.exit(0);
|
|
43
50
|
}
|
|
44
51
|
throw error;
|
|
@@ -47,31 +54,25 @@ export async function executeInit(options = {}) {
|
|
|
47
54
|
try {
|
|
48
55
|
// Generate config file
|
|
49
56
|
const configPath = generateConfigFile(initOptions, projectRoot);
|
|
50
|
-
|
|
51
|
-
configPath,
|
|
52
|
-
projectName: initOptions.projectName,
|
|
53
|
-
transport: initOptions.transport,
|
|
54
|
-
});
|
|
57
|
+
log.info(`Configuration file created successfully: ${configPath}`);
|
|
55
58
|
// Update .gitignore to exclude event files and dev history
|
|
56
59
|
try {
|
|
57
60
|
const eventsPatternAdded = await ensureGitignorePattern(projectRoot, Paths.EVENTS_DIR);
|
|
58
61
|
if (eventsPatternAdded) {
|
|
59
|
-
|
|
62
|
+
log.info(`Added ${Paths.EVENTS_DIR} to .gitignore`);
|
|
60
63
|
}
|
|
61
64
|
const historyPatternAdded = await ensureGitignorePattern(projectRoot, Paths.DEV_HISTORY_FILE);
|
|
62
65
|
if (historyPatternAdded) {
|
|
63
|
-
|
|
66
|
+
log.info('Added .syrin/.dev-history to .gitignore');
|
|
64
67
|
}
|
|
65
68
|
const dataPatternAdded = await ensureGitignorePattern(projectRoot, Paths.DATA_DIR);
|
|
66
69
|
if (dataPatternAdded) {
|
|
67
|
-
|
|
70
|
+
log.info(`Added ${Paths.DATA_DIR} to .gitignore`);
|
|
68
71
|
}
|
|
69
72
|
}
|
|
70
73
|
catch (error) {
|
|
71
74
|
// Log but don't fail initialization if .gitignore update fails
|
|
72
|
-
|
|
73
|
-
error: error instanceof Error ? error.message : String(error),
|
|
74
|
-
});
|
|
75
|
+
log.warn(`Failed to update .gitignore: ${error instanceof Error ? error.message : String(error)}`);
|
|
75
76
|
}
|
|
76
77
|
// Display success message
|
|
77
78
|
displayInitSuccess(configPath);
|
|
@@ -83,7 +84,77 @@ export async function executeInit(options = {}) {
|
|
|
83
84
|
cause: error instanceof Error ? error : new Error(String(error)),
|
|
84
85
|
context: { projectRoot },
|
|
85
86
|
});
|
|
86
|
-
|
|
87
|
+
log.error(`Error: ${configError.message}`);
|
|
88
|
+
throw configError;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Execute global init command (LLM providers only).
|
|
93
|
+
* Creates ~/.syrin/syrin.yaml with LLM configuration.
|
|
94
|
+
* @param options - Command options
|
|
95
|
+
*/
|
|
96
|
+
async function executeGlobalInit(options) {
|
|
97
|
+
// Check if global config already exists
|
|
98
|
+
if (globalConfigExists()) {
|
|
99
|
+
displayGlobalAlreadyInitialized();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
let globalOptions;
|
|
103
|
+
if (options.yes) {
|
|
104
|
+
// Non-interactive mode: use defaults
|
|
105
|
+
log.info('Initializing global config with default values (non-interactive mode)');
|
|
106
|
+
globalOptions = getDefaultGlobalInitOptions();
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
// Interactive mode: prompt user
|
|
110
|
+
log.info('Starting interactive global initialization');
|
|
111
|
+
try {
|
|
112
|
+
globalOptions = await promptGlobalInitOptions();
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
if (error instanceof Error && error.name === 'ExitPromptError') {
|
|
116
|
+
// User cancelled
|
|
117
|
+
log.info('Global initialization cancelled by user');
|
|
118
|
+
process.exit(0);
|
|
119
|
+
}
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
// Build GlobalSyrinConfig
|
|
125
|
+
const llmConfig = {};
|
|
126
|
+
for (const [provider, settings] of Object.entries(globalOptions.llmProviders)) {
|
|
127
|
+
llmConfig[provider] = {
|
|
128
|
+
...('apiKey' in settings && settings.apiKey
|
|
129
|
+
? { API_KEY: makeAPIKey(String(settings.apiKey)) }
|
|
130
|
+
: {}),
|
|
131
|
+
...(settings.modelName
|
|
132
|
+
? { MODEL_NAME: makeModelName(String(settings.modelName)) }
|
|
133
|
+
: {}),
|
|
134
|
+
default: settings.default || false,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const globalConfig = {
|
|
138
|
+
version: makeSyrinVersion('1.0'),
|
|
139
|
+
project_name: 'GlobalSyrin',
|
|
140
|
+
agent_name: globalOptions.agentName,
|
|
141
|
+
llm: llmConfig,
|
|
142
|
+
};
|
|
143
|
+
// Save global config
|
|
144
|
+
saveGlobalConfig(globalConfig);
|
|
145
|
+
const configPath = getGlobalConfigPath();
|
|
146
|
+
log.info(`Global configuration file created successfully: ${configPath}`);
|
|
147
|
+
// Display success message
|
|
148
|
+
displayGlobalInitSuccess(configPath);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const configError = error instanceof ConfigurationError
|
|
152
|
+
? error
|
|
153
|
+
: new ConfigurationError(Messages.ERROR_GENERATE_CONFIG, {
|
|
154
|
+
cause: error instanceof Error ? error : new Error(String(error)),
|
|
155
|
+
context: { type: 'global' },
|
|
156
|
+
});
|
|
157
|
+
log.error(`Error: ${configError.message}`);
|
|
87
158
|
throw configError;
|
|
88
159
|
}
|
|
89
160
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `syrin status` command implementation.
|
|
3
|
+
* Shows a quick overview of project health (like `git status`).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Execute the status command.
|
|
7
|
+
* @param projectRoot - Project root directory (defaults to current working directory)
|
|
8
|
+
*/
|
|
9
|
+
export declare function executeStatus(projectRoot?: string): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `syrin status` command implementation.
|
|
3
|
+
* Shows a quick overview of project health (like `git status`).
|
|
4
|
+
*/
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import { loadConfigOptional } from '../../config/loader.js';
|
|
8
|
+
import { loadGlobalConfig, getGlobalConfigPath } from '../../config/global-loader.js';
|
|
9
|
+
import { checkEnvVar } from '../../config/env-checker.js';
|
|
10
|
+
import { handleCommandError } from '../../cli/utils/index.js';
|
|
11
|
+
import { showVersionBanner } from '../../cli/utils/version-banner.js';
|
|
12
|
+
import { log } from '../../utils/logger.js';
|
|
13
|
+
import { Paths, LLMProviders, Icons } from '../../constants/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Generate status report.
|
|
16
|
+
*/
|
|
17
|
+
function generateStatusReport(projectRoot) {
|
|
18
|
+
const localConfig = loadConfigOptional(projectRoot);
|
|
19
|
+
const globalConfig = loadGlobalConfig();
|
|
20
|
+
const localEnvPath = path.join(projectRoot, Paths.ENV_FILE);
|
|
21
|
+
const hasLocalEnv = fs.existsSync(localEnvPath);
|
|
22
|
+
const report = {
|
|
23
|
+
hasLocalConfig: !!localConfig,
|
|
24
|
+
hasGlobalConfig: !!globalConfig,
|
|
25
|
+
llmProviders: [],
|
|
26
|
+
hasEnvFile: hasLocalEnv,
|
|
27
|
+
envFilePath: hasLocalEnv ? localEnvPath : undefined,
|
|
28
|
+
};
|
|
29
|
+
const config = localConfig || globalConfig;
|
|
30
|
+
if (!config) {
|
|
31
|
+
return report;
|
|
32
|
+
}
|
|
33
|
+
if (localConfig) {
|
|
34
|
+
report.configPath = path.join(projectRoot, Paths.CONFIG_FILE);
|
|
35
|
+
report.projectName = String(localConfig.project_name);
|
|
36
|
+
report.transport = String(localConfig.transport);
|
|
37
|
+
report.mcpUrl = localConfig.mcp_url
|
|
38
|
+
? String(localConfig.mcp_url)
|
|
39
|
+
: undefined;
|
|
40
|
+
report.script = localConfig.script ? String(localConfig.script) : undefined;
|
|
41
|
+
}
|
|
42
|
+
else if (globalConfig) {
|
|
43
|
+
report.configPath = getGlobalConfigPath();
|
|
44
|
+
}
|
|
45
|
+
// Check LLM providers
|
|
46
|
+
for (const [providerName, providerConfig] of Object.entries(config.llm)) {
|
|
47
|
+
let isConfigured = false;
|
|
48
|
+
if (providerName === LLMProviders.OLLAMA) {
|
|
49
|
+
// Ollama only needs MODEL_NAME
|
|
50
|
+
if (providerConfig.MODEL_NAME) {
|
|
51
|
+
const modelCheck = checkEnvVar(String(providerConfig.MODEL_NAME), projectRoot);
|
|
52
|
+
isConfigured = modelCheck.isSet;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Cloud providers need API_KEY
|
|
57
|
+
if (providerConfig.API_KEY) {
|
|
58
|
+
const apiKeyCheck = checkEnvVar(String(providerConfig.API_KEY), projectRoot);
|
|
59
|
+
isConfigured = apiKeyCheck.isSet;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
report.llmProviders.push({
|
|
63
|
+
name: providerName,
|
|
64
|
+
isDefault: providerConfig.default === true,
|
|
65
|
+
isConfigured,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return report;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Display status report.
|
|
72
|
+
*/
|
|
73
|
+
function displayStatusReport(report) {
|
|
74
|
+
log.blank();
|
|
75
|
+
// Configuration Status
|
|
76
|
+
log.heading('Configuration');
|
|
77
|
+
log.plain('─'.repeat(40));
|
|
78
|
+
if (report.hasLocalConfig) {
|
|
79
|
+
log.plain(` ${Icons.SUCCESS} Local config: ${report.configPath}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
log.plain(` ${Icons.FAILURE} Local config: Not found`);
|
|
83
|
+
}
|
|
84
|
+
if (report.hasGlobalConfig) {
|
|
85
|
+
const globalPath = getGlobalConfigPath();
|
|
86
|
+
log.plain(` ${Icons.SUCCESS} Global config: ${globalPath}`);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
log.plain(` ${log.styleText('○', 'dim')} Global config: Not configured`);
|
|
90
|
+
}
|
|
91
|
+
log.blank();
|
|
92
|
+
// Project Info (if local config exists)
|
|
93
|
+
if (report.hasLocalConfig && report.projectName) {
|
|
94
|
+
log.heading('Project');
|
|
95
|
+
log.plain('─'.repeat(40));
|
|
96
|
+
log.plain(` Name: ${report.projectName}`);
|
|
97
|
+
log.plain(` Transport: ${report.transport}`);
|
|
98
|
+
if (report.mcpUrl) {
|
|
99
|
+
log.plain(` MCP URL: ${report.mcpUrl}`);
|
|
100
|
+
}
|
|
101
|
+
if (report.script) {
|
|
102
|
+
log.plain(` Script: ${report.script}`);
|
|
103
|
+
}
|
|
104
|
+
log.blank();
|
|
105
|
+
}
|
|
106
|
+
// LLM Providers
|
|
107
|
+
if (report.llmProviders.length > 0) {
|
|
108
|
+
log.heading('LLM Providers');
|
|
109
|
+
log.plain('─'.repeat(40));
|
|
110
|
+
for (const provider of report.llmProviders) {
|
|
111
|
+
const icon = provider.isConfigured ? Icons.SUCCESS : Icons.FAILURE;
|
|
112
|
+
const defaultLabel = provider.isDefault
|
|
113
|
+
? log.styleText(' (default)', 'cyan')
|
|
114
|
+
: '';
|
|
115
|
+
const status = provider.isConfigured
|
|
116
|
+
? log.styleText('configured', 'green')
|
|
117
|
+
: log.styleText('not configured', 'red');
|
|
118
|
+
log.plain(` ${icon} ${provider.name}${defaultLabel}: ${status}`);
|
|
119
|
+
}
|
|
120
|
+
log.blank();
|
|
121
|
+
}
|
|
122
|
+
// Environment
|
|
123
|
+
log.heading('Environment');
|
|
124
|
+
log.plain('─'.repeat(40));
|
|
125
|
+
if (report.hasEnvFile) {
|
|
126
|
+
log.plain(` ${Icons.SUCCESS} .env file: ${report.envFilePath}`);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
log.plain(` ${log.styleText('○', 'dim')} .env file: Not found (optional)`);
|
|
130
|
+
}
|
|
131
|
+
log.blank();
|
|
132
|
+
// Quick Actions
|
|
133
|
+
const hasIssues = !report.hasLocalConfig && !report.hasGlobalConfig;
|
|
134
|
+
const hasUnconfiguredProviders = report.llmProviders.some(p => !p.isConfigured);
|
|
135
|
+
if (hasIssues || hasUnconfiguredProviders) {
|
|
136
|
+
log.heading('Suggested Actions');
|
|
137
|
+
log.plain('─'.repeat(40));
|
|
138
|
+
if (!report.hasLocalConfig && !report.hasGlobalConfig) {
|
|
139
|
+
log.plain(` ${Icons.TIP} Run ${log.styleText('syrin init', 'cyan')} to initialize a project`);
|
|
140
|
+
}
|
|
141
|
+
if (hasUnconfiguredProviders) {
|
|
142
|
+
log.plain(` ${Icons.TIP} Run ${log.styleText('syrin doctor', 'cyan')} for detailed diagnostics`);
|
|
143
|
+
log.plain(` ${Icons.TIP} Run ${log.styleText('syrin config edit-env', 'cyan')} to set API keys`);
|
|
144
|
+
}
|
|
145
|
+
log.blank();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Execute the status command.
|
|
150
|
+
* @param projectRoot - Project root directory (defaults to current working directory)
|
|
151
|
+
*/
|
|
152
|
+
export async function executeStatus(projectRoot = process.cwd()) {
|
|
153
|
+
await showVersionBanner();
|
|
154
|
+
try {
|
|
155
|
+
const report = generateStatusReport(projectRoot);
|
|
156
|
+
displayStatusReport(report);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
handleCommandError(error);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=status.js.map
|